Jika Anda ingin mengenkode anggota arbitrer enum.Enum
ke JSON dan kemudian mendekodekannya sebagai anggota enum yang sama (bukan hanya value
atribut anggota enum ), Anda dapat melakukannya dengan menulis JSONEncoder
kelas khusus , dan fungsi dekode untuk diteruskan sebagai object_hook
argumen ke json.load()
atau json.loads()
:
PUBLIC_ENUMS = {
'Status': Status,
}
class EnumEncoder(json.JSONEncoder):
def default(self, obj):
if type(obj) in PUBLIC_ENUMS.values():
return {"__enum__": str(obj)}
return json.JSONEncoder.default(self, obj)
def as_enum(d):
if "__enum__" in d:
name, member = d["__enum__"].split(".")
return getattr(PUBLIC_ENUMS[name], member)
else:
return d
The as_enum
fungsi bergantung pada JSON yang telah dikodekan menggunakan EnumEncoder
, atau sesuatu yang berperilaku identik dengan itu.
Pembatasan untuk anggota PUBLIC_ENUMS
diperlukan untuk menghindari teks perusak yang digunakan untuk, misalnya, menipu kode pemanggil untuk menyimpan informasi pribadi (misalnya kunci rahasia yang digunakan oleh aplikasi) ke bidang database yang tidak terkait, dari mana kemudian dapat diekspos (lihat http://chat.stackoverflow.com/transcript/message/35999686#35999686 ).
Contoh penggunaan:
>>> data = {
... "action": "frobnicate",
... "status": Status.success
... }
>>> text = json.dumps(data, cls=EnumEncoder)
>>> text
'{"status": {"__enum__": "Status.success"}, "action": "frobnicate"}'
>>> json.loads(text, object_hook=as_enum)
{'status': <Status.success: 0>, 'action': 'frobnicate'}
if isinstance(obj, Enum):
?Saya tahu ini sudah tua tetapi saya merasa ini akan membantu orang. Saya baru saja membahas masalah ini dan menemukan jika Anda menggunakan enum string, menyatakan enum Anda sebagai subkelas
str
berfungsi dengan baik untuk hampir semua situasi:import json from enum import Enum class LogLevel(str, Enum): DEBUG = 'DEBUG' INFO = 'INFO' print(LogLevel.DEBUG) print(json.dumps(LogLevel.DEBUG)) print(json.loads('"DEBUG"')) print(LogLevel('DEBUG'))
Akan menghasilkan:
LogLevel.DEBUG "DEBUG" DEBUG LogLevel.DEBUG
Seperti yang Anda lihat, memuat JSON mengeluarkan string
DEBUG
tetapi dengan mudah dapat diubah kembali ke objek LogLevel. Pilihan yang bagus jika Anda tidak ingin membuat JSONEncoder kustom.sumber
class LogLevel(str, Enum): DEBUG = 'Дебаг' INFO = 'Инфо'
dalam hal inienum with str
tidak ada yang berfungsi dengan baik (Jawaban yang benar tergantung pada apa yang ingin Anda lakukan dengan versi serial.
Jika Anda akan membatalkan serialisasi kembali ke Python, lihat jawaban Zero .
Jika versi serial Anda menggunakan bahasa lain maka Anda mungkin ingin menggunakan sebagai
IntEnum
gantinya, yang secara otomatis diserialkan sebagai integer yang sesuai:from enum import IntEnum import json class Status(IntEnum): success = 0 failure = 1 json.dumps(Status.success)
dan ini mengembalikan:
'0'
sumber
Python3.4
, dan jawaban ini spesifik 3.4+.EnumMeta
bukannyaIntEnum
Enum
, mungkin denganstr
mixin -class MyStrEnum(str, Enum): ...
EnumMeta
, yang dimaksudkan sebagai metaclass saja. Sebagai gantinya, perhatikan bahwa penerapannyaIntEnum
adalah satu baris dan Anda dapat mencapai hal yang samastr
denganclass StrEnum(str, Enum): ...
.Di Python 3.7, cukup gunakan
json.dumps(enum_obj, default=str)
sumber
name
enum ke dalam string json. Cara yang lebih baik adalah dengan menggunakanvalue
enum.json.dumps(enum_obj, default=lambda x: x.value)
Saya menyukai jawaban Zero Piraeus, tetapi sedikit memodifikasinya untuk bekerja dengan API untuk Amazon Web Services (AWS) yang dikenal sebagai Boto.
class EnumEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, Enum): return obj.name return json.JSONEncoder.default(self, obj)
Saya kemudian menambahkan metode ini ke model data saya:
def ToJson(self) -> str: return json.dumps(self.__dict__, cls=EnumEncoder, indent=1, sort_keys=True)
Saya harap ini membantu seseorang.
sumber
ToJson
model data Anda?Jika Anda menggunakan
jsonpickle
cara termudah harus melihat seperti di bawah ini.from enum import Enum import jsonpickle @jsonpickle.handlers.register(Enum, base=True) class EnumHandler(jsonpickle.handlers.BaseHandler): def flatten(self, obj, data): return obj.value # Convert to json friendly format if __name__ == '__main__': class Status(Enum): success = 0 error = 1 class SimpleClass: pass simple_class = SimpleClass() simple_class.status = Status.success json = jsonpickle.encode(simple_class, unpicklable=False) print(json)
Setelah serialisasi Json Anda akan mendapatkan seperti yang diharapkan,
{"status": 0}
bukan{"status": {"__objclass__": {"py/type": "__main__.Status"}, "_name_": "success", "_value_": 0}}
sumber
Ini berhasil untuk saya:
class Status(Enum): success = 0 def __json__(self): return self.value
Tidak perlu mengubah apa pun. Jelas, Anda hanya akan mendapatkan nilai dari ini dan perlu melakukan beberapa pekerjaan lain jika Anda ingin mengubah nilai serial kembali ke enum nanti.
sumber
JSONEncoder
?