Python cách tốt nhất để phân tích cú pháp JSON

Tất nhiên, bạn có thể kết hợp các giải pháp với nhiều thư viện. Hoặc, bạn có thể sử dụng msgspec một thư viện mới cung cấp lược đồ, phân tích cú pháp nhanh và một số thủ thuật gọn gàng để giảm mức sử dụng bộ nhớ, tất cả trong một thư viện

Một điểm khởi đầu. tích hợp sẵn
import json

with open["large.json", "r"] as f:
    data = json.load[f]

user_to_repos = {}
for record in data:
    user = record["actor"]["login"]
    repo = record["repo"]["name"]
    if user not in user_to_repos:
        user_to_repos[user] = set[]
    user_to_repos[user].add[repo]
print[len[user_to_repos], "records"]
0 và
import json

with open["large.json", "r"] as f:
    data = json.load[f]

user_to_repos = {}
for record in data:
    user = record["actor"]["login"]
    repo = record["repo"]["name"]
    if user not in user_to_repos:
        user_to_repos[user] = set[]
    user_to_repos[user].add[repo]
print[len[user_to_repos], "records"]
1

Hãy bắt đầu bằng cách xem xét hai thư viện khác. mô-đun

import json

with open["large.json", "r"] as f:
    data = json.load[f]

user_to_repos = {}
for record in data:
    user = record["actor"]["login"]
    repo = record["repo"]["name"]
    if user not in user_to_repos:
        user_to_repos[user] = set[]
    user_to_repos[user].add[repo]
print[len[user_to_repos], "records"]
0 tích hợp trong Python và thư viện
import json

with open["large.json", "r"] as f:
    data = json.load[f]

user_to_repos = {}
for record in data:
    user = record["actor"]["login"]
    repo = record["repo"]["name"]
    if user not in user_to_repos:
        user_to_repos[user] = set[]
    user_to_repos[user].add[repo]
print[len[user_to_repos], "records"]
1 nhanh chóng. Chúng tôi sẽ xem lại ví dụ từ bài viết của tôi về phân tích cú pháp JSON trực tuyến. Cụ thể, chúng tôi sẽ phân tích một tệp ~25 MB mã hóa danh sách các đối tượng JSON [tôi. e. từ điển], trông giống như các sự kiện GitHub, người dùng thực hiện các thao tác với kho lưu trữ

[{"id":"2489651045","type":"CreateEvent","actor":{"id":665991,"login":"petroav","gravatar_id":"","url":"//api.github.com/users/petroav","avatar_url":"//avatars.githubusercontent.com/u/665991?"},"repo":{"id":28688495,"name":"petroav/6.828","url":"//api.github.com/repos/petroav/6.828"},"payload":{"ref":"master","ref_type":"branch","master_branch":"master","description":"Solution to homework and assignments from MIT's 6.828 [Operating Systems Engineering]. Done in my spare time.","pusher_type":"user"},"public":true,"created_at":"2015-01-01T15:00:00Z"},
...
]

Mục tiêu của chúng tôi là tìm ra kho lưu trữ nào mà một người dùng nhất định đã tương tác với

Đây là cách bạn làm điều đó với mô-đun

import json

with open["large.json", "r"] as f:
    data = json.load[f]

user_to_repos = {}
for record in data:
    user = record["actor"]["login"]
    repo = record["repo"]["name"]
    if user not in user_to_repos:
        user_to_repos[user] = set[]
    user_to_repos[user].add[repo]
print[len[user_to_repos], "records"]
0 tích hợp trong thư viện chuẩn Python

import json

with open["large.json", "r"] as f:
    data = json.load[f]

user_to_repos = {}
for record in data:
    user = record["actor"]["login"]
    repo = record["repo"]["name"]
    if user not in user_to_repos:
        user_to_repos[user] = set[]
    user_to_repos[user].add[repo]
print[len[user_to_repos], "records"]

Và đây là cách bạn thực hiện với

import json

with open["large.json", "r"] as f:
    data = json.load[f]

user_to_repos = {}
for record in data:
    user = record["actor"]["login"]
    repo = record["repo"]["name"]
    if user not in user_to_repos:
        user_to_repos[user] = set[]
    user_to_repos[user].add[repo]
print[len[user_to_repos], "records"]
1, thay đổi hai dòng

import orjson

with open["large.json", "rb"] as f:
    data = orjson.loads[f.read[]]

user_to_repos = {}
for record in data:
    # .. same as stdlib code ...

Đây là dung lượng bộ nhớ và thời gian mà hai tùy chọn này sử dụng

$ /usr/bin/time -f "RAM: %M KB, Elapsed: %E" python stdlib.py 
5250 records
RAM: 136464 KB, Elapsed: 0:00.42
$ /usr/bin/time -f "RAM: %M KB, Elapsed: %E" python with_orjson.py 
5250 records
RAM: 113676 KB, Elapsed: 0:00.28

Mức sử dụng bộ nhớ cũng tương tự, nhưng

import json

with open["large.json", "r"] as f:
    data = json.load[f]

user_to_repos = {}
for record in data:
    user = record["actor"]["login"]
    repo = record["repo"]["name"]
    if user not in user_to_repos:
        user_to_repos[user] = set[]
    user_to_repos[user].add[repo]
print[len[user_to_repos], "records"]
1 nhanh hơn, ở mức 280 mili giây thay vì 420 mili giây

Tiếp theo, hãy xem xét msgspec

msgspec. giải mã và mã hóa dựa trên lược đồ cho JSON

Đây là mã tương ứng sử dụng msgspec;

from msgspec.json import decode
from msgspec import Struct

class Repo[Struct]:
    name: str

class Actor[Struct]:
    login: str

class Interaction[Struct]:
    actor: Actor
    repo: Repo

with open["large.json", "rb"] as f:
    data = decode[f.read[], type=list[Interaction]]

user_to_repos = {}
for record in data:
    user = record.actor.login
    repo = record.repo.name
    if user not in user_to_repos:
        user_to_repos[user] = set[]
    user_to_repos[user].add[repo]
print[len[user_to_repos], "records"]

Mã này dài hơn và chi tiết hơn vì msgspec cho phép bạn xác định lược đồ cho các bản ghi mà bạn đang phân tích cú pháp

Khá hữu ích, bạn không cần phải có lược đồ cho tất cả các trường. Mặc dù bản ghi JSON có rất nhiều trường [hãy xem ví dụ trước đó để xem tất cả dữ liệu], chúng tôi chỉ cho msgspec biết về các trường mà chúng tôi thực sự quan tâm

Đây là kết quả của việc phân tích cú pháp với msgspec

$ /usr/bin/time -f "RAM: %M KB, Elapsed: %E" python with_msgspec.py 
5250 records
RAM: 38612 KB, Elapsed: 0:00.09

Nhanh hơn nhiều và bộ nhớ ít hơn nhiều

Để tóm tắt ba tùy chọn mà chúng tôi đã thấy, cũng như giải pháp dựa trên

import orjson

with open["large.json", "rb"] as f:
    data = orjson.loads[f.read[]]

user_to_repos = {}
for record in data:
    # .. same as stdlib code ...
0 phát trực tuyến

GóiThời gianRAMSử dụng bộ nhớ cố địnhSchemaStdlib
import json

with open["large.json", "r"] as f:
    data = json.load[f]

user_to_repos = {}
for record in data:
    user = record["actor"]["login"]
    repo = record["repo"]["name"]
    if user not in user_to_repos:
        user_to_repos[user] = set[]
    user_to_repos[user].add[repo]
print[len[user_to_repos], "records"]
0420ms136MB❌❌
import json

with open["large.json", "r"] as f:
    data = json.load[f]

user_to_repos = {}
for record in data:
    user = record["actor"]["login"]
    repo = record["repo"]["name"]
    if user not in user_to_repos:
        user_to_repos[user] = set[]
    user_to_repos[user].add[repo]
print[len[user_to_repos], "records"]
1280ms114MB❌❌
import orjson

with open["large.json", "rb"] as f:
    data = orjson.loads[f.read[]]

user_to_repos = {}
for record in data:
    # .. same as stdlib code ...
0300ms14MB✓❌msgspec90ms39MB❌✓

Giải pháp phát trực tuyến chỉ sử dụng một lượng bộ nhớ cố định để phân tích cú pháp; . Nhưng trong ba giải pháp đó, msgspec có mức sử dụng bộ nhớ thấp hơn đáng kể và cho đến nay đây là giải pháp nhanh nhất

Ưu và nhược điểm của phân tích cú pháp dựa trên lược đồ

msgspec cho phép bạn chỉ định lược đồ nên chúng tôi có thể tạo các đối tượng Python chỉ cho những trường mà chúng tôi thực sự quan tâm. Điều đó có nghĩa là sử dụng RAM thấp hơn và giải mã nhanh hơn;

Chúng tôi cũng đã xác thực lược đồ miễn phí. Nếu một trong các bản ghi bằng cách nào đó bị thiếu một trường hoặc nếu giá trị là loại sai, chẳng hạn như một số nguyên thay vì một chuỗi, trình phân tích cú pháp sẽ phàn nàn. Với các thư viện JSON tiêu chuẩn, việc xác thực lược đồ phải diễn ra riêng biệt

Mặt khác

  • Mức sử dụng bộ nhớ khi giải mã vẫn tỷ lệ với tệp đầu vào. Trình phân tích cú pháp JSON trực tuyến như
    import orjson
    
    with open["large.json", "rb"] as f:
        data = orjson.loads[f.read[]]
    
    user_to_repos = {}
    for record in data:
        # .. same as stdlib code ...
    
    0 vẫn mang lại lợi ích của việc sử dụng bộ nhớ cố định trong quá trình phân tích cú pháp, bất kể tệp đầu vào lớn đến mức nào
  • Chỉ định lược đồ liên quan đến mã hóa nhiều hơn và ít linh hoạt hơn để xử lý dữ liệu không hoàn hảo

Tìm hiểu thêm về msgspec

msgspec có các tính năng bổ sung, như mã hóa, hỗ trợ MessagePack [một định dạng thay thế nhanh hơn cho JSON], v.v. Nếu bạn đang phân tích cú pháp các tệp JSON một cách thường xuyên và bạn đang gặp phải các vấn đề về hiệu suất hoặc bộ nhớ hoặc bạn chỉ muốn các lược đồ tích hợp sẵn, hãy cân nhắc dùng thử

Bài viết tiếp theo. Ngoài cProfile. Chọn công cụ phù hợp để tối ưu hóa hiệu suất
Bài viết trước. Nút cổ chai của bạn ở đâu?

Xử lý dữ liệu quá chậm?

Bạn có thể nhận được kết quả nhanh hơn từ quy trình khoa học dữ liệu của mình—và cũng nhận lại được một số tiền—nếu bạn có thể tìm ra lý do tại sao mã của mình chạy chậm

Xác định các nút thắt cổ chai về hiệu suất và ngốn bộ nhớ trong khoa học dữ liệu sản xuất của bạn Các công việc Python với Sciagraph, trình lược tả luôn bật cho các công việc sản xuất hàng loạt

Tìm hiểu các kỹ năng kỹ thuật phần mềm Python thực tế mà bạn có thể sử dụng trong công việc của mình

Đăng ký nhận bản tin của tôi và tham gia cùng hơn 6500 nhà phát triển Python và nhà khoa học dữ liệu học các công cụ và kỹ thuật thực tế, từ hiệu suất Python đến đóng gói Docker, với một bài viết mới miễn phí trong hộp thư đến của bạn mỗi tuần

Làm cách nào để phân tích cú pháp dữ liệu JSON trong Python?

Nếu bạn có một chuỗi JSON, bạn có thể phân tích cú pháp chuỗi đó bằng cách sử dụng json. phương thức load[] . Kết quả sẽ là một từ điển Python.

Làm cách nào để phân tích chuỗi JSON trong Python?

Để phân tích chuỗi dữ liệu JSON thành đối tượng Python, hãy sử dụng json. loads[] của gói dựng sẵn có tên json . json. phương thức loading[] phân tích cú pháp chuỗi dữ liệu JSON được cung cấp và trả về một từ điển Python chứa tất cả dữ liệu từ JSON.

Chủ Đề