После долгого поиска я обнаружил:
После отсоединения USB я должен запустить
adb connect <device_ip_address>:5555
.
Есть ли у вас представление о ожидаемом выходе? Напр. это будет?
>>> f = FileItem("/foo/bar")
>>> magic(f)
'{"fname": "/foo/bar"}'
В этом случае вы можете просто называть json.dumps(f.__dict__)
.
Если вам нужен более индивидуальный вывод, вам придется подклассы JSONEncoder
и реализовать свою собственную сериализацию.
Для тривиального примера см. ниже.
>>> from json import JSONEncoder
>>> class MyEncoder(JSONEncoder):
def default(self, o):
return o.__dict__
>>> MyEncoder().encode(f)
'{"fname": "/foo/bar"}'
Затем вы передаете этот класс в метод json.dumps()
как cls
kwarg:
json.dumps(cls=MyEncoder)
Если вы также хотите декодировать, вам нужно будет поставить пользовательский object_hook
в класс JSONDecoder
. Например,
>>> def from_json(json_object):
if 'fname' in json_object:
return FileItem(json_object['fname'])
>>> f = JSONDecoder(object_hook = from_json).decode('{"fname": "/foo/bar"}')
>>> f
<__main__.FileItem object at 0x9337fac>
>>>
Большинство ответов связаны с изменением вызова на json.dumps (), что не всегда возможно или желательно (это может произойти, например, в компоненте framework).
Если вы хотите быть в состоянии для вызова json.dumps (obj) как есть, тогда простое решение наследуется от dict:
class FileItem(dict):
def __init__(self, fname):
dict.__init__(self, fname=fname)
f = FileItem('tasks.txt')
json.dumps(f) #No need to change anything here
Это работает, если ваш класс является просто базовым представлением данных, потому что для более сложных вещей вы всегда можете задавать ключи явно .
Мне нравится ответ Онура , но он будет расширяться, чтобы включить опциональный метод toJSON()
для сериализации объектов:
def dumper(obj):
try:
return obj.toJSON()
except:
return obj.__dict__
print json.dumps(some_big_object, default=dumper, indent=2)
Вот мои 3 цента ... Это демонстрирует явную сериализацию json для древовидного объекта python. Примечание. Если вам действительно нужен такой код, вы можете использовать класс twisted FilePath .
import json, sys, os
class File:
def __init__(self, path):
self.path = path
def isdir(self):
return os.path.isdir(self.path)
def isfile(self):
return os.path.isfile(self.path)
def children(self):
return [File(os.path.join(self.path, f))
for f in os.listdir(self.path)]
def getsize(self):
return os.path.getsize(self.path)
def getModificationTime(self):
return os.path.getmtime(self.path)
def _default(o):
d = {}
d['path'] = o.path
d['isFile'] = o.isfile()
d['isDir'] = o.isdir()
d['mtime'] = int(o.getModificationTime())
d['size'] = o.getsize() if o.isfile() else 0
if o.isdir(): d['children'] = o.children()
return d
folder = os.path.abspath('.')
json.dump(File(folder), sys.stdout, default=_default)
Я придумал свое решение. Используйте этот метод, передайте любой документ ( dict , list , ObjectId и т. Д.) Для сериализации.
def getSerializable(doc):
# check if it's a list
if isinstance(doc, list):
for i, val in enumerate(doc):
doc[i] = getSerializable(doc[i])
return doc
# check if it's a dict
if isinstance(doc, dict):
for key in doc.keys():
doc[key] = getSerializable(doc[key])
return doc
# Process ObjectId
if isinstance(doc, ObjectId):
doc = str(doc)
return doc
# Use any other custom serializting stuff here...
# For the rest of stuff
return doc
Для более сложных классов вы можете рассмотреть инструмент jsonpickle :
jsonpickle - это библиотека Python для сериализации и десериализации сложных объектов Python в JSON и из JSON.
Стандартные библиотеки Python для кодирования Python в JSON, такие как json, simplejson и demjson stdlib, могут обрабатывать только примитивы Python, которые имеют прямой эквивалент JSON (например, dicts, lists, string, ints и т. д.). ). jsonpickle строит поверх этих библиотек и позволяет сериализовать более сложные структуры данных в JSON. jsonpickle очень настраивается и расширяется, позволяя пользователю выбирать бэкэнд JSON и добавлять дополнительные бэкэнды.
blockquote>
Существует много подходов к этой проблеме. «ObjDict» (pip install objdict) - это другое. Существует акцент на предоставлении javascript-подобных объектов, которые также могут действовать как словари, чтобы лучше обрабатывать данные, загруженные из JSON, но есть и другие функции, которые могут быть полезны. Это дает другое альтернативное решение исходной проблемы.
Я решил использовать декораторы для решения проблемы сериализации объекта datetime. Вот мой код:
#myjson.py
#Author: jmooremcc 7/16/2017
import json
from datetime import datetime, date, time, timedelta
"""
This module uses decorators to serialize date objects using json
The filename is myjson.py
In another module you simply add the following import statement:
from myjson import json
json.dumps and json.dump will then correctly serialize datetime and date
objects
"""
def json_serial(obj):
"""JSON serializer for objects not serializable by default json code"""
if isinstance(obj, (datetime, date)):
serial = str(obj)
return serial
raise TypeError ("Type %s not serializable" % type(obj))
def FixDumps(fn):
def hook(obj):
return fn(obj, default=json_serial)
return hook
def FixDump(fn):
def hook(obj, fp):
return fn(obj,fp, default=json_serial)
return hook
json.dumps=FixDumps(json.dumps)
json.dump=FixDump(json.dump)
if __name__=="__main__":
today=datetime.now()
data={'atime':today, 'greet':'Hello'}
str=json.dumps(data)
print str
Импортируя вышеуказанный модуль, мои другие модули используют json обычным способом (без указания ключевого слова по умолчанию) для сериализации данных, содержащих объекты времени даты. Код datetime serializer автоматически вызывается для json.dumps и json.dump.
Этот класс может сделать трюк, он преобразует объект в стандартный json.
import json
class Serializer(object):
@staticmethod
def serialize(object):
return json.dumps(object, default=lambda o: o.__dict__.values()[0])
use:
Serializer.serialize(my_object)
работает в python2.7
и python3
.
Если вы не против установки пакета для него, вы можете использовать json-tricks :
pip install json-tricks
После этого вам просто нужно импортировать dump(s)
из json_tricks
вместо json, и он обычно работает:
from json_tricks import dumps
json_str = dumps(cls_instance, indent=4)
, который даст
{
"__instance_type__": [
"module_name.test_class",
"MyTestCls"
],
"attributes": {
"attr": "val",
"dct_attr": {
"hello": 42
}
}
}
И это в основном это!
Это будет отлично работать в целом. Существуют некоторые исключения, например. если в __new__
происходят особые вещи, или происходит больше метаклассической магии.
Очевидно, что загрузка также работает (в противном случае в чем смысл):
from json_tricks import loads
json_str = loads(json_str)
Это предполагает, что module_name.test_class.MyTestCls
могут быть импортированы и не изменены несовместимыми способами. Вы вернете экземпляр, а не какой-либо словарь или что-то еще, и он должен быть идентичной копией того, который вы сбросили.
Если вы хотите настроить, как что-то получает (де) сериализован, вы можете добавить специальные методы для вашего класса, например:
class CustomEncodeCls:
def __init__(self):
self.relevant = 42
self.irrelevant = 37
def __json_encode__(self):
# should return primitive, serializable types like dict, list, int, string, float...
return {'relevant': self.relevant}
def __json_decode__(self, **attrs):
# should initialize all properties; note that __init__ is not called implicitly
self.relevant = attrs['relevant']
self.irrelevant = 12
, который в качестве примера сериализует только часть параметров атрибутов.
И как бесплатный бонус, вы получаете (de) сериализация массивов numpy, date & amp; временами, упорядоченные карты, а также возможность включать комментарии в json.
Отказ: я создал json_tricks , потому что у меня была та же проблема, что и вы.
jaraco дал довольно аккуратный ответ. Мне нужно было исправить некоторые незначительные вещи, но это работает:
# Your custom class
class MyCustom(object):
def __json__(self):
return {
'a': self.a,
'b': self.b,
'__python__': 'mymodule.submodule:MyCustom.from_json',
}
to_json = __json__ # supported by simplejson
@classmethod
def from_json(cls, json):
obj = cls()
obj.a = json['a']
obj.b = json['b']
return obj
# Dumping and loading
import simplejson
obj = MyCustom()
obj.a = 3
obj.b = 4
json = simplejson.dumps(obj, for_json=True)
# Two-step loading
obj2_dict = simplejson.loads(json)
obj2 = MyCustom.from_json(obj2_dict)
# Make sure we have the correct thing
assert isinstance(obj2, MyCustom)
assert obj2.__dict__ == obj.__dict__
Обратите внимание, что нам нужно выполнить два шага для загрузки. На данный момент свойство __python__
не используется.
Используя метод AlJohri , я проверяю популярность подходов:
Сериализация (Python -> JSON):
to_json
: 266,595 на 2018-06-27 toJSON
: 96,307 по 2018-06-27 __json__
: 8 504 по 2018-06-27 for_json
: 6,937 на 2018-06-27 Дезициализация (JSON -> Python):
from_json
: 226,101 по 2018-06-27 jsonweb кажется лучшим решением для меня. См. http://www.jsonweb.info/en/latest/
from jsonweb.encode import to_object, dumper
@to_object()
class DataModel(object):
def __init__(self, id, value):
self.id = id
self.value = value
>>> data = DataModel(5, "foo")
>>> dumper(data)
'{"__type__": "DataModel", "id": 5, "value": "foo"}'
Вот простое решение для простой функции:
.toJSON()
Метод Вместо сериализуемого класса JSON реализуйте метод сериализатора:
import json
class Object:
def toJSON(self):
return json.dumps(self, default=lambda o: o.__dict__,
sort_keys=True, indent=4)
Итак, вы просто вызываете его для сериализации:
me = Object()
me.name = "Onur"
me.age = 35
me.dog = Object()
me.dog.name = "Apollo"
print(me.toJSON())
выведет:
{
"age": 35,
"dog": {
"name": "Apollo"
},
"name": "Onur"
}
Другим вариантом является перенос JSON-демпинга в свой класс:
import json
class FileItem:
def __init__(self, fname):
self.fname = fname
def __repr__(self):
return json.dumps(self.__dict__)
Или, что еще лучше, подклассификация класса FileItem из класса JsonSerializable
:
import json
class JsonSerializable(object):
def toJson(self):
return json.dumps(self.__dict__)
def __repr__(self):
return self.toJson()
class FileItem(JsonSerializable):
def __init__(self, fname):
self.fname = fname
Тестирование:
>>> f = FileItem('/foo/bar')
>>> f.toJson()
'{"fname": "/foo/bar"}'
>>> f
'{"fname": "/foo/bar"}'
>>> str(f) # string coercion
'{"fname": "/foo/bar"}'
import json
class Foo(object):
def __init__(self):
self.bar = 'baz'
self._qux = 'flub'
def somemethod(self):
pass
def default(instance):
return {k: v
for k, v in vars(instance).items()
if not str(k).startswith('_')}
json_foo = json.dumps(Foo(), default=default)
assert '{"bar": "baz"}' == json_foo
print(json_foo)
json
ограничено в терминах объектов, которые он может печатать, а jsonpickle
(возможно, вам нужен pip install jsonpickle
) ограничен в терминах, он не может отступать от текста. Если вы хотите проверить содержимое объекта, класс которого вы не можете изменить, я все равно не мог найти более строгий путь:
import json
import jsonpickle
...
print json.dumps(json.loads(jsonpickle.encode(object)), indent=2)
Обратите внимание, что они все еще не могут распечатать объект методы.
Просто добавьте метод to_json
в ваш класс следующим образом:
def to_json(self):
return self.message # or how you want it to be serialized
И добавьте этот код (из этот ответ ) , чтобы где-то в верхней части всего:
from json import JSONEncoder
def _default(self, obj):
return getattr(obj.__class__, "to_json", _default.default)(obj)
_default.default = JSONEncoder().default
JSONEncoder.default = _default
Это будет модуль monkey-patch json, когда он будет импортирован, поэтому JSONEncoder.default () автоматически проверяет специальный метод «to_json ()» и использует его для кодирования объект, если найден.
Так же, как сказал Онур, но на этот раз вам не нужно обновлять каждый json.dumps()
в вашем проекте.
Я столкнулся с этой проблемой, когда попытался сохранить модель Peewee в PostgreSQL JSONField
.
После долгой работы, вот общее решение.
Ключ к моему решение проходит через исходный код Python и понимает, что документация по коду (описанная здесь здесь ) уже объясняет, как расширить существующий json.dumps
для поддержки других типов данных.
Предположим, что вы иметь модель, которая содержит некоторые поля, которые не могут быть сериализованы для JSON, и модель, которая содержит поле JSON, первоначально выглядит следующим образом:
class SomeClass(Model):
json_field = JSONField()
Просто определите пользовательский JSONEncoder
, как это:
class CustomJsonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, SomeTypeUnsupportedByJsonDumps):
return < whatever value you want >
return json.JSONEncoder.default(self, obj)
@staticmethod
def json_dumper(obj):
return json.dumps(obj, cls=CustomJsonEncoder)
А затем просто используйте его в своем JSONField
, как показано ниже:
class SomeClass(Model):
json_field = JSONField(dumps=CustomJsonEncoder.json_dumper)
Ключом является метод default(self, obj)
выше. Для каждой жалобы ... is not JSON serializable
, которую вы получаете от Python, просто добавьте код для обработки типа unserializable-to-JSON (например, Enum
или datetime
)
Например, вот как я поддерживаю класс, наследующий от Enum
:
class TransactionType(Enum):
CURRENT = 1
STACKED = 2
def default(self, obj):
if isinstance(obj, TransactionType):
return obj.value
return json.JSONEncoder.default(self, obj)
Наконец, с помощью кода, реализованного, как описано выше, вы можете просто преобразовать любые модели Peewee в объект JSON-seriazable, как показано ниже:
peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)
Хотя приведенный выше код был (несколько) специфичен для Peewee, но я думаю:
json.dumps
, это решение также работает с Python (без ORM) вообще . Все вопросы, пожалуйста, публикуйте в разделе комментариев. Спасибо!
Это небольшая библиотека, которая сериализует объект со всеми его дочерними элементами в JSON, а также анализирует его обратно:
На днях я столкнулся с этой проблемой и реализовал более общую версию Encoder для объектов Python, которая может обрабатывать вложенные объекты и наследуемые поля:
import json
import inspect
class ObjectEncoder(json.JSONEncoder):
def default(self, obj):
if hasattr(obj, "to_json"):
return self.default(obj.to_json())
elif hasattr(obj, "__dict__"):
d = dict(
(key, value)
for key, value in inspect.getmembers(obj)
if not key.startswith("__")
and not inspect.isabstract(value)
and not inspect.isbuiltin(value)
and not inspect.isfunction(value)
and not inspect.isgenerator(value)
and not inspect.isgeneratorfunction(value)
and not inspect.ismethod(value)
and not inspect.ismethoddescriptor(value)
and not inspect.isroutine(value)
)
return self.default(d)
return obj
Пример:
class C(object):
c = "NO"
def to_json(self):
return {"c": "YES"}
class B(object):
b = "B"
i = "I"
def __init__(self, y):
self.y = y
def f(self):
print "f"
class A(B):
a = "A"
def __init__(self):
self.b = [{"ab": B("y")}]
self.c = C()
print json.dumps(A(), cls=ObjectEncoder, indent=2, sort_keys=True)
Результат:
{
"a": "A",
"b": [
{
"ab": {
"b": "B",
"i": "I",
"y": "y"
}
}
],
"c": {
"c": "YES"
},
"i": "I"
}
import simplejson
class User(object):
def __init__(self, name, mail):
self.name = name
self.mail = mail
def _asdict(self):
return self.__dict__
print(simplejson.dumps(User('alice', 'alice@mail.com')))
, если используется стандарт json
, необходимо определить функцию default
import json
def default(o):
return o._asdict()
print(json.dumps(User('alice', 'alice@mail.com'), default=default))
Мне понравился метод Lost Koder. Я столкнулся с проблемами при попытке сериализации более сложных объектов, чьи члены / методы не сериализуемы. Вот моя реализация, которая работает с большим количеством объектов:
class Serializer(object):
@staticmethod
def serialize(obj):
def check(o):
for k, v in o.__dict__.items():
try:
_ = json.dumps(v)
o.__dict__[k] = v
except TypeError:
o.__dict__[k] = str(v)
return o
return json.dumps(check(obj).__dict__, indent=2)