Pythonシーケンス化モジュール-pickleとjson

42990 ワード

Synopsis:Python言語固有のシーケンス化モジュールはpickleですが、シーケンス化をより汎用的でWeb規格に適合させるにはjsonモジュールを使用します.jsonモジュールのdumps()とloads()関数は非常によく定義されたインタフェースの模範である.使用する場合は、必要なパラメータを1つだけ入力する必要があります.しかし、デフォルトのシーケンス化または逆シーケンス化メカニズムが私たちの要件を満たしていない場合、シーケンス化または逆シーケンス化のルールをカスタマイズするために、より多くのパラメータを入力することができます.インタフェースが簡単で使いやすく、十分な拡張性と柔軟性を実現します.
1. pickle
Pythonプログラムが実行されると、オブジェクトはメモリに存在し、プログラムが終了すると、これらのオブジェクトが消費するメモリはオペレーティングシステムによってすべて回収されます.pickleモジュールを使用して、オブジェクトをディスクファイルに保存することができます.このようなオブジェクトをメモリから記憶可能または伝送可能にするプロセスを と呼びます.シーケンス化後、シーケンス化されたコンテンツをディスクに書き込むか、ネットワークを介して他のマシンに転送することができます.逆に,変数の内容をシーケンス化したオブジェクトからメモリに読み直すことを (unpickling)と呼ぶ.
1.1 pickle.dumps() pickle.dumps()メソッドは、任意のオブジェクトを1つのbytesにシーケンス化し、その後、bytesfile-like objectメソッドのopen()モードで開いているファイル記述子、BytesiOなどのwbに書き込むことができます.参照:http://www.madmalls.com/blog/post/read-write-files-in-python/#62-bytesio
In [1]: import pickle

In [2]: d = {'name': 'wangy', 'age': 18}

In [3]: pickle.dumps(d)
Out[3]: b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x05\x00\x00\x00wangyq\x02X\x03\x00\x00\x00ageq\x03K\x12u.'

In [4]: b = pickle.dumps(d)

In [5]: b
Out[5]: b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x05\x00\x00\x00wangyq\x02X\x03\x00\x00\x00ageq\x03K\x12u.'

In [6]: f = open('/tmp/test.txt', 'xb')

In [7]: f.write(b)
Out[7]: 43

In [8]: f.close()

このとき、/tmp/test.txtファイルが作成され、そのデータは書き込まれたばかりのバイトストリームですが、コンテンツを正常に表示できません.
[root@CentOS ~]# file /tmp/test.txt
/tmp/test.txt: 8086 relocatable (Microsoft)
[root@CentOS ~]# cat /tmp/test.txt
}q(XnameqXwangyqXageqKu.[root@CentOS ~]#

1.2 pickle.dump() pickle.dump()メソッド オブジェクトをシーケンス化してfile-like objectに書き込みます.たとえば、open()メソッドのwbモードで開いているファイル記述子、BytesIOを使用します.参照:http://www.madmalls.com/blog/post/read-write-files-in-python/#62-bytesio
In [1]: import pickle

In [2]: d = {'name': 'wangy', 'age': 18}

In [3]: f = open('/tmp/test2.txt', 'xb')

In [4]: pickle.dump(d, f)

In [5]: f.close()

1.3 pickle.loads()
前のステップのファイルをrbモードで開き、bytesに戻り、pickle.loads()で前の辞書オブジェクトを逆シーケンス化することができます(コンテンツが同じで、異なるオブジェクトであり、idが異なるだけです):
In [1]: import pickle

In [2]: f = open('/tmp/test.txt', 'rb')

In [3]: b = f.read()

In [4]: b
Out[4]: b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x05\x00\x00\x00wangyq\x02X\x03\x00\x00\x00ageq\x03K\x12u.'

In [5]: d = pickle.loads(b)

In [6]: d
Out[6]: {'name': 'wangy', 'age': 18}

In [7]: f.close()

1.4 pickle.load() pickle.load()メソッドは、1つのfile-like objectからオブジェクトを直接逆シーケンス化する
In [1]: import pickle

In [2]: f = open('/tmp/test.txt', 'rb')

In [3]: d = pickle.load(f)

In [4]: d
Out[4]: {'name': 'wangy', 'age': 18}

In [5]: f.close()

2. JSON
Pythonに内蔵されたjsonモジュールは、非常に完全なPythonオブジェクトからJSONフォーマットへの変換を提供します.
2.1 json.dumps() json.dumps()メソッドは任意のオブジェクトを1つのstrにシーケンス化し,内容は標準的なJSONである.その後、このstrをファイルに書き込むことができます(Web開発時はサーバ側がPythonオブジェクトをJSONにシーケンス化した後、直接応答をクライアントに返すのが一般的です):
In [1]: import json

In [2]: d = {'name': 'wangy', 'age': 18}

In [3]: s = json.dumps(d)

In [4]: s
Out[4]: '{"name": "wangy", "age": 18}'

In [5]: type(s)
Out[5]: str

In [6]: f = open('/tmp/test.json', 'w')

In [7]: f.write(s)
Out[7]: 28

In [8]: f.close()
[root@CentOS ~]# cat /tmp/test.json 
{"name": "wangy", "age": 18}

2.2 json.dump() json.dump()メソッドは、オブジェクトをJSONに直接シーケンス化してfile-like objectに書き込みます.Web開発ではファイルに保存されることは少ないので、あまり使いません.
In [1]: import json

In [2]: d = {'name': 'wangy', 'age': 18}

In [3]: f = open('/tmp/test.json', 'w')

In [4]: json.dump(d, f)

In [5]: f.close()

2.3 json.loads() json.loads() JSONをPythonオブジェクトに逆シーケンス化し、Web開発中にクライアントから送信されたJSONデータをサーバが受信すると、Pythonではstrと表示される.
In [1]: import json

In [2]: json_str = '{"name": "wangy", "age": 18}'

In [3]: d = json.loads(json_str)

In [4]: d
Out[4]: {'name': 'wangy', 'age': 18}

In [5]: type(d)
Out[5]: dict

2.4 json.load() json.load()メソッドは、file-like objectから文字列を読み出してPythonオブジェクトに逆シーケンス化し、Web開発では通常、クライアントからJSONを直接受信するため、あまり使用されません.
In [1]: import json

In [2]: f = open('/tmp/test.json', 'r')

In [3]: d = json.load(f)

In [4]: d
Out[4]: {'name': 'wangy', 'age': 18}

2.5 TypeError: Object of type 'User' is not JSON serializable json.dumps()は、Pythonに組み込まれている基礎データ型(辞書など)を直接JSONにシーケンス化することができます.
Python
JSON
dict
object
list
array
str
string
int
number (int)
float
number (real)
True
true
False
false
None
null
しかし、一般的なクラスインスタンス化後のオブジェクトはjsonシーケンス化を使用するとエラーが発生します.
import json


class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age


u = User('wangy', 18)
print(json.dumps(u))
[root@CentOS ~]# python3 test.py
Traceback (most recent call last):
  File "test.py", line 11, in 
    print(json.dumps(u))
  File "/usr/local/python-3.6/lib/python3.6/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/usr/local/python-3.6/lib/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/python-3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/local/python-3.6/lib/python3.6/json/encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'User' is not JSON serializable

解決方法1:クラス属性をJSONにシーケンス化するだけの であれば、__dict__
In [1]: import json

In [2]: class User:
   ...:     def __init__(self, name, age):
   ...:         self.name = name
   ...:         self.age = age
   ...:         

In [3]: u = User('wangy', 18)

In [4]: json.dumps(u.__dict__)
Out[4]: '{"name": "wangy", "age": 18}'

In [5]: json.dumps(u, default=lambda obj: obj.__dict__)  #   default  ,      User      
Out[5]: '{"name": "wangy", "age": 18}'

解決策2:クラスインスタンス属性値は一般にそのまま出力されません.この場合、json.dumps()defaultの値を外部関数として指定します.
import json


class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def toJSON(self):
        data = {'name': self.name, 'age': self.age + 10}
        return data


def my_json_encoder(obj):
    try:
        return obj.toJSON()
    except:
        return obj.__dict__


u = User('wangy', 18)
print(json.dumps(u, default=my_json_encoder, indent=4))
[root@CentOS ~]# python3 test.py 
{
    "name": "wangy",
    "age": 28
}

JSONをクラスインスタンスオブジェクトに逆シーケンス化する場合は、json.loads()メソッドを使用し、object_hookパラメータ値をカスタム関数として指定します.
import json


class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def toJSON(self):
        data = {'name': self.name, 'age': self.age + 10}
        return data


def dict2user(d):
    return User(d['name'], d['age'] - 10)


json_str = '{"name": "wangy", "age": 38}'
u2 = json.loads(json_str, object_hook=dict2user)
print(u2.name)
print(u2.age)
[root@CentOS ~]# python3 test.py 
wangy
28