标签归档:json

如何使可序列化的JSON类

问题:如何使可序列化的JSON类

如何使Python类可序列化?

一个简单的类:

class FileItem:
    def __init__(self, fname):
        self.fname = fname

我应该怎么做才能获得输出:

>>> import json

>>> my_file = FileItem('/foo/bar')
>>> json.dumps(my_file)
TypeError: Object of type 'FileItem' is not JSON serializable

没有错误

How to make a Python class serializable?

A simple class:

class FileItem:
    def __init__(self, fname):
        self.fname = fname

What should I do to be able to get output of:

>>> import json

>>> my_file = FileItem('/foo/bar')
>>> json.dumps(my_file)
TypeError: Object of type 'FileItem' is not JSON serializable

Without the error


回答 0

您对预期的输出有想法吗?例如这样做吗?

>>> 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()作为clskwarg 传递给方法:

json.dumps(cls=MyEncoder)

如果你也想解码,那么你将有一个自定义供应object_hookJSONDecoder类。例如

>>> 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>
>>> 

Do you have an idea about the expected output? For e.g. will this do?

>>> f  = FileItem("/foo/bar")
>>> magic(f)
'{"fname": "/foo/bar"}'

In that case you can merely call json.dumps(f.__dict__).

If you want more customized output then you will have to subclass JSONEncoder and implement your own custom serialization.

For a trivial example, see below.

>>> from json import JSONEncoder
>>> class MyEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__    

>>> MyEncoder().encode(f)
'{"fname": "/foo/bar"}'

Then you pass this class into the json.dumps() method as cls kwarg:

json.dumps(cls=MyEncoder)

If you also want to decode then you’ll have to supply a custom object_hook to the JSONDecoder class. For e.g.

>>> 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>
>>> 

回答 1

这是一个简单功能的简单解决方案:

.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"
}

Here is a simple solution for a simple feature:

.toJSON() Method

Instead of a JSON serializable class, implement a serializer method:

import json

class Object:
    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, 
            sort_keys=True, indent=4)

So you just call it to serialize:

me = Object()
me.name = "Onur"
me.age = 35
me.dog = Object()
me.dog.name = "Apollo"

print(me.toJSON())

will output:

{
    "age": 35,
    "dog": {
        "name": "Apollo"
    },
    "name": "Onur"
}

回答 2

对于更复杂的类,您可以考虑使用jsonpickle工具:

jsonpickle是一个Python库,用于将复杂的Python对象与JSON进行序列化和反序列化。

用于将Python编码为JSON的标准Python库(例如stdlib的json,simplejson和demjson)只能处理具有直接JSON等效项的Python原语(例如,字典,列表,字符串,整数等)。jsonpickle建立在这些库之上,并允许将更复杂的数据结构序列化为JSON。jsonpickle具有高度的可配置性和可扩展性,允许用户选择JSON后端并添加其他后端。

(链接到PyPi上的jsonpickle)

For more complex classes you could consider the tool jsonpickle:

jsonpickle is a Python library for serialization and deserialization of complex Python objects to and from JSON.

The standard Python libraries for encoding Python into JSON, such as the stdlib’s json, simplejson, and demjson, can only handle Python primitives that have a direct JSON equivalent (e.g. dicts, lists, strings, ints, etc.). jsonpickle builds on top of these libraries and allows more complex data structures to be serialized to JSON. jsonpickle is highly configurable and extendable–allowing the user to choose the JSON backend and add additional backends.

(link to jsonpickle on PyPi)


回答 3

大多数答案都涉及将对json.dumps()的调用更改为并非总是可能或不希望的(例如,它可能发生在框架组件内部)。

如果您希望能够原样调用 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

如果您的类只是基本数据表示形式,则此方法有效,对于棘手的事情,您始终可以显式设置键。

Most of the answers involve changing the call to json.dumps(), which is not always possible or desirable (it may happen inside a framework component for example).

If you want to be able to call json.dumps(obj) as is, then a simple solution is inheriting from 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

This works if your class is just basic data representation, for trickier things you can always set keys explicitly.


回答 4

我喜欢Onur的答案,但会扩展为包括一个可选toJSON()方法,以使对象自行序列化:

def dumper(obj):
    try:
        return obj.toJSON()
    except:
        return obj.__dict__
print json.dumps(some_big_object, default=dumper, indent=2)

I like Onur’s answer but would expand to include an optional toJSON() method for objects to serialize themselves:

def dumper(obj):
    try:
        return obj.toJSON()
    except:
        return obj.__dict__
print json.dumps(some_big_object, default=dumper, indent=2)

回答 5

另一个选择是将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"}'

Another option is to wrap JSON dumping in its own class:

import json

class FileItem:
    def __init__(self, fname):
        self.fname = fname

    def __repr__(self):
        return json.dumps(self.__dict__)

Or, even better, subclassing FileItem class from a JsonSerializable class:

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

Testing:

>>> f = FileItem('/foo/bar')
>>> f.toJson()
'{"fname": "/foo/bar"}'
>>> f
'{"fname": "/foo/bar"}'
>>> str(f) # string coercion
'{"fname": "/foo/bar"}'

回答 6

只需将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

导入时,它将对Monkeyjson模块进行Monkey补丁处理,因此JSONEncoder.default()自动检查特殊的“ to_json()”方法,并在找到后使用该方法对对象进行编码。

就像Onur所说的一样,但是这次您不必更新json.dumps()项目中的每个项目。

Just add to_json method to your class like this:

def to_json(self):
  return self.message # or how you want it to be serialized

And add this code (from this answer), to somewhere at the top of everything:

from json import JSONEncoder

def _default(self, obj):
    return getattr(obj.__class__, "to_json", _default.default)(obj)

_default.default = JSONEncoder().default
JSONEncoder.default = _default

This will monkey-patch json module when it’s imported so JSONEncoder.default() automatically checks for a special “to_json()” method and uses it to encode the object if found.

Just like Onur said, but this time you don’t have to update every json.dumps() in your project.


回答 7

前几天,我遇到了这个问题,并为Python对象实现了一个更通用的Encoder版本,可以处理嵌套对象继承的字段

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"
}

I came across this problem the other day and implemented a more general version of an Encoder for Python objects that can handle nested objects and inherited fields:

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

Example:

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)

Result:

{
  "a": "A", 
  "b": [
    {
      "ab": {
        "b": "B", 
        "i": "I", 
        "y": "y"
      }
    }
  ], 
  "c": {
    "c": "YES"
  }, 
  "i": "I"
}

回答 8

如果您使用的是Python3.5 +,则可以使用jsons。它将把您的对象(及其所有属性递归地)转换成字典。

import jsons

a_dict = jsons.dump(your_object)

或者,如果您想要一个字符串:

a_str = jsons.dumps(your_object)

或者如果您的Class实施了jsons.JsonSerializable

a_dict = your_object.json

If you’re using Python3.5+, you could use jsons. It will convert your object (and all its attributes recursively) to a dict.

import jsons

a_dict = jsons.dump(your_object)

Or if you wanted a string:

a_str = jsons.dumps(your_object)

Or if your class implemented jsons.JsonSerializable:

a_dict = your_object.json

回答 9

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))
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')))

if use standard json, u need to define a default function

import json
def default(o):
    return o._asdict()

print(json.dumps(User('alice', 'alice@mail.com'), default=default))

回答 10

json在可以打印的对象方面受到限制,并且jsonpickle(您可能需要pip install jsonpickle)在不能缩进文本方面受到限制。如果您想检查无法更改其类的对象的内容,我仍然找不到比以下方法更直接的方法:

 import json
 import jsonpickle
 ...
 print  json.dumps(json.loads(jsonpickle.encode(object)), indent=2)

注意:他们仍然无法打印对象方法。

json is limited in terms of objects it can print, and jsonpickle (you may need a pip install jsonpickle) is limited in terms it can’t indent text. If you would like to inspect the contents of an object whose class you can’t change, I still couldn’t find a straighter way than:

 import json
 import jsonpickle
 ...
 print  json.dumps(json.loads(jsonpickle.encode(object)), indent=2)

Note: that still they can’t print the object methods.


回答 11

此类可以解决问题,它将对象转换为标准json。

import json


class Serializer(object):
    @staticmethod
    def serialize(object):
        return json.dumps(object, default=lambda o: o.__dict__.values()[0])

用法:

Serializer.serialize(my_object)

python2.7和工作python3

This class can do the trick, it converts object to standard json .

import json


class Serializer(object):
    @staticmethod
    def serialize(object):
        return json.dumps(object, default=lambda o: o.__dict__.values()[0])

usage:

Serializer.serialize(my_object)

working in python2.7 and python3.


回答 12

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)
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)

回答 13

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):

反序列化(JSON-> Python):

jaraco gave a pretty neat answer. I needed to fix some minor things, but this works:

Code

# 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__

Note that we need two steps for loading. For now, the __python__ property is not used.

How common is this?

Using the method of AlJohri, I check popularity of approaches:

Serialization (Python -> JSON):

Deserialization (JSON -> Python):


回答 14

这对我来说效果很好:

class JsonSerializable(object):

    def serialize(self):
        return json.dumps(self.__dict__)

    def __repr__(self):
        return self.serialize()

    @staticmethod
    def dumper(obj):
        if "serialize" in dir(obj):
            return obj.serialize()

        return obj.__dict__

然后

class FileItem(JsonSerializable):
    ...

log.debug(json.dumps(<my object>, default=JsonSerializable.dumper, indent=2))

This has worked well for me:

class JsonSerializable(object):

    def serialize(self):
        return json.dumps(self.__dict__)

    def __repr__(self):
        return self.serialize()

    @staticmethod
    def dumper(obj):
        if "serialize" in dir(obj):
            return obj.serialize()

        return obj.__dict__

and then

class FileItem(JsonSerializable):
    ...

and

log.debug(json.dumps(<my object>, default=JsonSerializable.dumper, indent=2))

回答 15

如果您不介意为其安装软件包,则可以使用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
                }
        }
}

基本上就是这样!


总的来说,这会很好。有一些exceptions,例如,如果发生了特殊情况__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

例如,它仅序列化部分属性参数。

作为免费赠品,您可以获得numpy数组(日期)的反序列化,日期和时间,有序映射以及在json中包含注释的功能。

免责声明:我创建了json_tricks,因为我和您有同样的问题。

If you don’t mind installing a package for it, you can use json-tricks:

pip install json-tricks

After that you just need to import dump(s) from json_tricks instead of json, and it’ll usually work:

from json_tricks import dumps
json_str = dumps(cls_instance, indent=4)

which’ll give

{
        "__instance_type__": [
                "module_name.test_class",
                "MyTestCls"
        ],
        "attributes": {
                "attr": "val",
                "dct_attr": {
                        "hello": 42
                }
        }
}

And that’s basically it!


This will work great in general. There are some exceptions, e.g. if special things happen in __new__, or more metaclass magic is going on.

Obviously loading also works (otherwise what’s the point):

from json_tricks import loads
json_str = loads(json_str)

This does assume that module_name.test_class.MyTestCls can be imported and hasn’t changed in non-compatible ways. You’ll get back an instance, not some dictionary or something, and it should be an identical copy to the one you dumped.

If you want to customize how something gets (de)serialized, you can add special methods to your class, like so:

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

which serializes only part of the attributes parameters, as an example.

And as a free bonus, you get (de)serialization of numpy arrays, date & times, ordered maps, as well as the ability to include comments in json.

Disclaimer: I created json_tricks, because I had the same problem as you.


回答 16

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"}'

jsonweb seems to be the best solution for me. See 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"}'

回答 17

这是我的3美分…
这演示了一个类似树的python对象的显式json序列化。
注意:如果您实际上想要这样的代码,则可以使用扭曲的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)

Here is my 3 cents …
This demonstrates explicit json serialization for a tree-like python object.
Note: If you actually wanted some code like this you could use the twisted FilePath class.

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)

回答 18

当我尝试将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类型(例如Enumdatetime

例如,这是我如何支持从继承的类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可序列化的对象,如下所示:

peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)

尽管上面的代码(某种程度上)特定于Peewee,但是我认为:

  1. 通常适用于其他ORM(例如Django等)
  2. 另外,如果您了解其json.dumps工作原理,那么该解决方案通常也适用于Python(无ORM)

如有任何疑问,请发表在评论部分。谢谢!

I ran into this problem when I tried to store Peewee’s model into PostgreSQL JSONField.

After struggling for a while, here’s the general solution.

The key to my solution is going through Python’s source code and realizing that the code documentation (described here) already explains how to extend the existing json.dumps to support other data types.

Suppose you current have a model that contains some fields that are not serializable to JSON and the model that contains the JSON field originally looks like this:

class SomeClass(Model):
    json_field = JSONField()

Just define a custom JSONEncoder like this:

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)

And then just use it in your JSONField like below:

class SomeClass(Model):
    json_field = JSONField(dumps=CustomJsonEncoder.json_dumper)

The key is the default(self, obj) method above. For every single ... is not JSON serializable complaint you receive from Python, just add code to handle the unserializable-to-JSON type (such as Enum or datetime)

For example, here’s how I support a class inheriting from 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)

Finally, with the code implemented like above, you can just convert any Peewee models to be a JSON-seriazable object like below:

peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)

Though the code above was (somewhat) specific to Peewee, but I think:

  1. It’s applicable to other ORMs (Django, etc) in general
  2. Also, if you understood how json.dumps works, this solution also works with Python (sans ORM) in general too

Any questions, please post in the comments section. Thanks!


回答 19

此函数使用递归遍历字典的每个部分,然后调用非内置类型的类的repr()方法。

def sterilize(obj):
    object_type = type(obj)
    if isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    elif object_type in (list, tuple):
        return [sterilize(v) for v in obj]
    elif object_type in (str, int, bool):
        return obj
    else:
        return obj.__repr__()

This function uses recursion to iterate over every part of the dictionary and then calls the repr() methods of classes that are not build-in types.

def sterilize(obj):
    object_type = type(obj)
    if isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    elif object_type in (list, tuple):
        return [sterilize(v) for v in obj]
    elif object_type in (str, int, bool):
        return obj
    else:
        return obj.__repr__()

回答 20

这是一个小型库,它将带有其所有子级的对象序列化为JSON并将其解析回:

https://github.com/Toubs/PyJSONSerialization/

This is a small library that serializes an object with all its children to JSON and also parses it back:

https://github.com/Toubs/PyJSONSerialization/


回答 21

我想出了自己的解决方案。使用此方法,传递任何文档(dictlistObjectId等)进行序列化。

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

I came up with my own solution. Use this method, pass any document (dict,list, ObjectId etc) to serialize.

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

回答 22

我选择使用装饰器解决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序列化程序代码会被json.dumps和json.dump自动调用。

I chose to use decorators to solve the datetime object serialization problem. Here is my code:

#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

By importing the above module, my other modules use json in a normal way (without specifying the default keyword) to serialize data that contains date time objects. The datetime serializer code is automatically called for json.dumps and json.dump.


回答 23

我最喜欢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)

I liked Lost Koder’s method the most. I ran into issues when trying to serialize more complex objects whos members/methods aren’t serializable. Here’s my implementation that works on more objects:

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)

回答 24

如果您能够安装软件包,我建议您尝试dill,这对于我的项目来说效果很好。这个套件的优点是它具有与相同的介面pickle,因此,如果您已经pickle在专案中使用过,可以简单地以dill为该脚本并查看脚本是否在运行,而无需更改任何代码。因此,这是一个非常便宜的解决方案!

(完全反公开:我与Dill项目毫无关系,也从未参与过该项目。)

安装软件包:

pip install dill

然后,编辑要导入的代码,dill而不是pickle

# import pickle
import dill as pickle

运行您的脚本,看看它是否有效。(如果这样做,您可能需要清理代码,以使您不再隐藏pickle模块名称!)

dill项目页面可以和不能序列化的数据类型的一些细节:

dill 可以腌制以下标准类型:

无,类型,布尔值,整数,长整型,浮点型,复杂,str,unicode,元组,列表,字典,文件,缓冲区,内置,新旧样式类,新旧样式类实例,集合,frozenset,数组,功能,异常

dill 也可以腌制更多“异国”标准类型:

具有yields的函数,嵌套函数,lambdas,单元格,方法,unboundmethod,模块,代码,methodwrapper,dictproxy,methoddescriptor,getsetdescriptor,memberdescriptor,wrapperperscriptor,xrange,slice,未实现,省略号,退出

dill 尚不能腌制这些标准类型:

框架,发生器,回溯

If you are able to install a package, I’d recommend trying dill, which worked just fine for my project. A nice thing about this package is that it has the same interface as pickle, so if you have already been using pickle in your project you can simply substitute in dill and see if the script runs, without changing any code. So it is a very cheap solution to try!

(Full anti-disclosure: I am in no way affiliated with and have never contributed to the dill project.)

Install the package:

pip install dill

Then edit your code to import dill instead of pickle:

# import pickle
import dill as pickle

Run your script and see if it works. (If it does you may want to clean up your code so that you are no longer shadowing the pickle module name!)

Some specifics on datatypes that dill can and cannot serialize, from the project page:

dill can pickle the following standard types:

none, type, bool, int, long, float, complex, str, unicode, tuple, list, dict, file, buffer, builtin, both old and new style classes, instances of old and new style classes, set, frozenset, array, functions, exceptions

dill can also pickle more ‘exotic’ standard types:

functions with yields, nested functions, lambdas, cell, method, unboundmethod, module, code, methodwrapper, dictproxy, methoddescriptor, getsetdescriptor, memberdescriptor, wrapperdescriptor, xrange, slice, notimplemented, ellipsis, quit

dill cannot yet pickle these standard types:

frame, generator, traceback


回答 25

我在这里没有提到串行版本控制或反向兼容,因此我将发布已经使用了一段时间的解决方案。我可能有很多东西要学,特别是Java和Javascript在这里可能比我更成熟,但是这里

https://gist.github.com/andy-d/b7878d0044a4242c0498ed6d67fd50fe

I see no mention here of serial versioning or backcompat, so I will post my solution which I’ve been using for a bit. I probably have a lot more to learn from, specifically Java and Javascript are probably more mature than me here but here goes

https://gist.github.com/andy-d/b7878d0044a4242c0498ed6d67fd50fe


回答 26

要添加另一个选项:您可以使用attrs包和asdict方法。

class ObjectEncoder(JSONEncoder):
    def default(self, o):
        return attr.asdict(o)

json.dumps(objects, cls=ObjectEncoder)

并转换回来

def from_json(o):
    if '_obj_name' in o:
        type_ = o['_obj_name']
        del o['_obj_name']
        return globals()[type_](**o)
    else:
        return o

data = JSONDecoder(object_hook=from_json).decode(data)

类看起来像这样

@attr.s
class Foo(object):
    x = attr.ib()
    _obj_name = attr.ib(init=False, default='Foo')

To add another option: You can use the attrs package and the asdict method.

class ObjectEncoder(JSONEncoder):
    def default(self, o):
        return attr.asdict(o)

json.dumps(objects, cls=ObjectEncoder)

and to convert back

def from_json(o):
    if '_obj_name' in o:
        type_ = o['_obj_name']
        del o['_obj_name']
        return globals()[type_](**o)
    else:
        return o

data = JSONDecoder(object_hook=from_json).decode(data)

class looks like this

@attr.s
class Foo(object):
    x = attr.ib()
    _obj_name = attr.ib(init=False, default='Foo')

回答 27

除了Onur的答案外,您可能还想处理类似以下的datetime类型。
(为了处理:“ datetime.datetime”对象没有属性“ dict ”异常。)

def datetime_option(value):
    if isinstance(value, datetime.date):
        return value.timestamp()
    else:
        return value.__dict__

用法:

def toJSON(self):
    return json.dumps(self, default=datetime_option, sort_keys=True, indent=4)

In addition to the Onur’s answer, You possibly want to deal with datetime type like below.
(in order to handle: ‘datetime.datetime’ object has no attribute ‘dict‘ exception.)

def datetime_option(value):
    if isinstance(value, datetime.date):
        return value.timestamp()
    else:
        return value.__dict__

Usage:

def toJSON(self):
    return json.dumps(self, default=datetime_option, sort_keys=True, indent=4)

回答 28

首先,我们需要使对象符合JSON,因此可以使用标准JSON模块将其转储。我这样做是这样的:

def serialize(o):
    if isinstance(o, dict):
        return {k:serialize(v) for k,v in o.items()}
    if isinstance(o, list):
        return [serialize(e) for e in o]
    if isinstance(o, bytes):
        return o.decode("utf-8")
    return o

First we need to make our object JSON-compliant, so we can dump it using the standard JSON module. I did it this way:

def serialize(o):
    if isinstance(o, dict):
        return {k:serialize(v) for k,v in o.items()}
    if isinstance(o, list):
        return [serialize(e) for e in o]
    if isinstance(o, bytes):
        return o.decode("utf-8")
    return o

回答 29

基于Quinten Cabo答案

def sterilize(obj):
    if type(obj) in (str, float, int, bool, type(None)):
        return obj
    elif isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    elif hasattr(obj, '__iter__') and callable(obj.__iter__):
        return [sterilize(v) for v in obj]
    elif hasattr(obj, '__dict__'):
        return {k: sterilize(v) for k, v in obj.__dict__.items() if k not in ['__module__', '__dict__', '__weakref__', '__doc__']}
    else:
        return repr(obj)

区别是

  1. 适用于任何迭代而不是just listtuple(适用于NumPy数组等)
  2. 适用于动态类型(包含 __dict__)。
  3. 包括本机类型floatNone因此它们不会转换为字符串。

留给读者的练习是处理__slots__,这些类既可迭代且具有成员,这些类既是字典又具有成员,等等。

Building on Quinten Cabo‘s answer:

def sterilize(obj):
    if type(obj) in (str, float, int, bool, type(None)):
        return obj
    elif isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    elif hasattr(obj, '__iter__') and callable(obj.__iter__):
        return [sterilize(v) for v in obj]
    elif hasattr(obj, '__dict__'):
        return {k: sterilize(v) for k, v in obj.__dict__.items() if k not in ['__module__', '__dict__', '__weakref__', '__doc__']}
    else:
        return repr(obj)

The differences are

  1. Works for any iterable instead of just list and tuple (it works for NumPy arrays, etc.)
  2. Works for dynamic types (ones that contain a __dict__).
  3. Includes native types float and None so they don’t get converted to string.

Left as an exercise to the reader is to handle __slots__, classes that are both iterable and have members, classes that are dictionaries and also have members, etc.


如何克服“ datetime.datetime无法JSON序列化”?

问题:如何克服“ datetime.datetime无法JSON序列化”?

我有一个基本的命令,如下所示:

sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere

当我尝试做时,jsonify(sample)我得到:

TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable

我该怎么做才能使我的字典示例可以克服上述错误?

注意:尽管可能无关紧要,但字典是从记录的检索中生成的,这些记录是mongodb在我打印出str(sample['somedate'])的地方输出的2012-08-08 21:46:24.862000

I have a basic dict as follows:

sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere

When I try to do jsonify(sample) I get:

TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable

What can I do such that my dictionary sample can overcome the error above?

Note: Though it may not be relevant, the dictionaries are generated from the retrieval of records out of mongodb where when I print out str(sample['somedate']), the output is 2012-08-08 21:46:24.862000.


回答 0

更新于2018

原始答案适应了MongoDB“日期”字段表示为:

{"$date": 1506816000000}

如果您希望使用通用的Python解决方案序列化为datetimejson,请查看@jjmontes的答案以获取无需依赖项的快速解决方案。


当您使用mongoengine(每个注释)并且pymongo是一个依赖项时,pymongo具有内置的实用程序来帮助json序列化:http ://api.mongodb.org/python/1.10.1/api/bson/json_util.html

用法示例(序列化):

from bson import json_util
import json

json.dumps(anObject, default=json_util.default)

用法示例(反序列化):

json.loads(aJsonString, object_hook=json_util.object_hook)

Django的

Django提供了本机DjangoJSONEncoder序列化程序,可以正确处理这种情况。

参见https://docs.djangoproject.com/en/dev/topics/serialization/#djangojsonencoder

from django.core.serializers.json import DjangoJSONEncoder

return json.dumps(
  item,
  sort_keys=True,
  indent=1,
  cls=DjangoJSONEncoder
)

我注意到DjangoJSONEncoder和使用这样的自定义之间的一个区别default

import datetime
import json

def default(o):
    if isinstance(o, (datetime.date, datetime.datetime)):
        return o.isoformat()

return json.dumps(
  item,
  sort_keys=True,
  indent=1,
  default=default
)

是Django剥离了一些数据:

 "last_login": "2018-08-03T10:51:42.990", # DjangoJSONEncoder 
 "last_login": "2018-08-03T10:51:42.990239", # default

因此,在某些情况下,您可能需要注意这一点。

Updated for 2018

The original answer accommodated the way MongoDB “date” fields were represented as:

{"$date": 1506816000000}

If you want a generic Python solution for serializing datetime to json, check out @jjmontes’ answer for a quick solution which requires no dependencies.


As you are using mongoengine (per comments) and pymongo is a dependency, pymongo has built-in utilities to help with json serialization:
http://api.mongodb.org/python/1.10.1/api/bson/json_util.html

Example usage (serialization):

from bson import json_util
import json

json.dumps(anObject, default=json_util.default)

Example usage (deserialization):

json.loads(aJsonString, object_hook=json_util.object_hook)

Django

Django provides a native DjangoJSONEncoder serializer that deals with this kind of properly.

See https://docs.djangoproject.com/en/dev/topics/serialization/#djangojsonencoder

from django.core.serializers.json import DjangoJSONEncoder

return json.dumps(
  item,
  sort_keys=True,
  indent=1,
  cls=DjangoJSONEncoder
)

One difference I’ve noticed between DjangoJSONEncoder and using a custom default like this:

import datetime
import json

def default(o):
    if isinstance(o, (datetime.date, datetime.datetime)):
        return o.isoformat()

return json.dumps(
  item,
  sort_keys=True,
  indent=1,
  default=default
)

Is that Django strips a bit of the data:

 "last_login": "2018-08-03T10:51:42.990", # DjangoJSONEncoder 
 "last_login": "2018-08-03T10:51:42.990239", # default

So, you may need to be careful about that in some cases.


回答 1

我的快速且肮脏的JSON转储会吃掉日期和所有东西:

json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)

My quick & dirty JSON dump that eats dates and everything:

json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)

回答 2

基于其他答案,这是一个基于特定序列化器的简单解决方案,该序列化器仅将datetime.datetime和转换datetime.date为字符串。

from datetime import date, datetime

def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError ("Type %s not serializable" % type(obj))

如图所示,代码仅检查对象是否属于datetime.datetime或类datetime.date,然后.isoformat()根据ISO 8601格式YYYY-MM-DDTHH:MM:SS来生成对象的序列化版本(可通过JavaScript轻松解码) )。如果寻求更复杂的序列化表示形式,则可以使用其他代码代替str()(有关示例,请参见此问题的其他答案)。该代码以引发异常结束,以处理使用非序列化类型调用该异常的情况。

此json_serial函数可以按如下方式使用:

from datetime import datetime
from json import dumps

print dumps(datetime.now(), default=json_serial)

有关json.dumps默认参数如何工作的详细信息,请参见json模块文档的“基本用法”部分

Building on other answers, a simple solution based on a specific serializer that just converts datetime.datetime and datetime.date objects to strings.

from datetime import date, datetime

def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError ("Type %s not serializable" % type(obj))

As seen, the code just checks to find out if object is of class datetime.datetime or datetime.date, and then uses .isoformat() to produce a serialized version of it, according to ISO 8601 format, YYYY-MM-DDTHH:MM:SS (which is easily decoded by JavaScript). If more complex serialized representations are sought, other code could be used instead of str() (see other answers to this question for examples). The code ends by raising an exception, to deal with the case it is called with a non-serializable type.

This json_serial function can be used as follows:

from datetime import datetime
from json import dumps

print dumps(datetime.now(), default=json_serial)

The details about how the default parameter to json.dumps works can be found in Section Basic Usage of the json module documentation.


回答 3

我刚遇到这个问题,我的解决方案是子类化json.JSONEncoder

from datetime import datetime
import json

class DateTimeEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, datetime):
            return o.isoformat()

        return json.JSONEncoder.default(self, o)

在您的通话做这样的事情:json.dumps(yourobj, cls=DateTimeEncoder).isoformat()我从上面的答案之一了。

I have just encountered this problem and my solution is to subclass json.JSONEncoder:

from datetime import datetime
import json

class DateTimeEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, datetime):
            return o.isoformat()

        return json.JSONEncoder.default(self, o)

In your call do something like: json.dumps(yourobj, cls=DateTimeEncoder) The .isoformat() I got from one of the answers above.


回答 4

将日期转换为字符串

sample['somedate'] = str( datetime.utcnow() )

Convert the date to a string

sample['somedate'] = str( datetime.utcnow() )

回答 5

对于不需要或想要使用pymongo库的其他人,您可以使用此小片段轻松实现日期时间JSON转换:

def default(obj):
    """Default JSON serializer."""
    import calendar, datetime

    if isinstance(obj, datetime.datetime):
        if obj.utcoffset() is not None:
            obj = obj - obj.utcoffset()
        millis = int(
            calendar.timegm(obj.timetuple()) * 1000 +
            obj.microsecond / 1000
        )
        return millis
    raise TypeError('Not sure how to serialize %s' % (obj,))

然后像这样使用它:

import datetime, json
print json.dumps(datetime.datetime.now(), default=default)

输出: 

'1365091796124'

For others who do not need or want to use the pymongo library for this.. you can achieve datetime JSON conversion easily with this small snippet:

def default(obj):
    """Default JSON serializer."""
    import calendar, datetime

    if isinstance(obj, datetime.datetime):
        if obj.utcoffset() is not None:
            obj = obj - obj.utcoffset()
        millis = int(
            calendar.timegm(obj.timetuple()) * 1000 +
            obj.microsecond / 1000
        )
        return millis
    raise TypeError('Not sure how to serialize %s' % (obj,))

Then use it like so:

import datetime, json
print json.dumps(datetime.datetime.now(), default=default)

output: 

'1365091796124'

回答 6

这是我的解决方案:

# -*- coding: utf-8 -*-
import json


class DatetimeEncoder(json.JSONEncoder):
    def default(self, obj):
        try:
            return super(DatetimeEncoder, obj).default(obj)
        except TypeError:
            return str(obj)

然后,您可以像这样使用它:

json.dumps(dictionnary, cls=DatetimeEncoder)

Here is my solution:

# -*- coding: utf-8 -*-
import json


class DatetimeEncoder(json.JSONEncoder):
    def default(self, obj):
        try:
            return super(DatetimeEncoder, obj).default(obj)
        except TypeError:
            return str(obj)

Then you can use it like that:

json.dumps(dictionnary, cls=DatetimeEncoder)

回答 7

我有一个类似问题的应用程序;我的方法是将datetime值作为6项列表(年,月,日,时,分,秒)进行JSON化;您可以将微秒作为7项列表,但是我不需要:

class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            encoded_object = list(obj.timetuple())[0:6]
        else:
            encoded_object =json.JSONEncoder.default(self, obj)
        return encoded_object

sample = {}
sample['title'] = "String"
sample['somedate'] = datetime.datetime.now()

print sample
print json.dumps(sample, cls=DateTimeEncoder)

生成:

{'somedate': datetime.datetime(2013, 8, 1, 16, 22, 45, 890000), 'title': 'String'}
{"somedate": [2013, 8, 1, 16, 22, 45], "title": "String"}

I have an application with a similar issue; my approach was to JSONize the datetime value as a 6-item list (year, month, day, hour, minutes, seconds); you could go to microseconds as a 7-item list, but I had no need to:

class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            encoded_object = list(obj.timetuple())[0:6]
        else:
            encoded_object =json.JSONEncoder.default(self, obj)
        return encoded_object

sample = {}
sample['title'] = "String"
sample['somedate'] = datetime.datetime.now()

print sample
print json.dumps(sample, cls=DateTimeEncoder)

produces:

{'somedate': datetime.datetime(2013, 8, 1, 16, 22, 45, 890000), 'title': 'String'}
{"somedate": [2013, 8, 1, 16, 22, 45], "title": "String"}

回答 8

我的解决方案(我认为冗长程度较低):

def default(o):
    if type(o) is datetime.date or type(o) is datetime.datetime:
        return o.isoformat()

def jsondumps(o):
    return json.dumps(o, default=default)

然后使用jsondumps代替json.dumps。它将打印:

>>> jsondumps({'today': datetime.date.today()})
'{"today": "2013-07-30"}'

我想要,稍后您可以通过简单的default方法添加其他特殊情况。例:

def default(o):
    if type(o) is datetime.date or type(o) is datetime.datetime:
        return o.isoformat()
    if type(o) is decimal.Decimal:
        return float(o)

My solution (with less verbosity, I think):

def default(o):
    if type(o) is datetime.date or type(o) is datetime.datetime:
        return o.isoformat()

def jsondumps(o):
    return json.dumps(o, default=default)

Then use jsondumps instead of json.dumps. It will print:

>>> jsondumps({'today': datetime.date.today()})
'{"today": "2013-07-30"}'

I you want, later you can add other special cases to this with a simple twist of the default method. Example:

def default(o):
    if type(o) is datetime.date or type(o) is datetime.datetime:
        return o.isoformat()
    if type(o) is decimal.Decimal:
        return float(o)

回答 9

这个Q一次又一次地重复-修补json模块的一种简单方法,以便序列化支持datetime。

import json
import datetime

json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)

比起您一如既往地使用json序列化-这次将datetime序列化为isoformat。

json.dumps({'created':datetime.datetime.now()})

结果:'{“ created”:“ 2015-08-26T14:21:31.853855”}“

有关更多详细信息,请注意: StackOverflow:Python和JavaScript之间的JSON日期时间

This Q repeats time and time again – a simple way to patch the json module such that serialization would support datetime.

import json
import datetime

json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)

Than use json serialization as you always do – this time with datetime being serialized as isoformat.

json.dumps({'created':datetime.datetime.now()})

Resulting in: ‘{“created”: “2015-08-26T14:21:31.853855”}’

See more details and some words of caution at: StackOverflow: JSON datetime between Python and JavaScript


回答 10

json.dumps方法可以接受称为default的可选参数,该参数应为函数。每次JSON尝试转换值时,它都不知道如何转换将调用我们传递给它的函数。该函数将接收有问题的对象,并且应返回该对象的JSON表示形式。

def myconverter(o):
 if isinstance(o, datetime.datetime):
    return o.__str__()

print(json.dumps(d, default = myconverter)) 

The json.dumps method can accept an optional parameter called default which is expected to be a function. Every time JSON tries to convert a value it does not know how to convert it will call the function we passed to it. The function will receive the object in question, and it is expected to return the JSON representation of the object.

def myconverter(o):
 if isinstance(o, datetime.datetime):
    return o.__str__()

print(json.dumps(d, default = myconverter)) 

回答 11

如果您使用的是python3.7,那么最好的解决方案是使用 datetime.isoformat()datetime.fromisoformat(); 它们既可以用于天真datetime对象,也可以用于感知对象:

#!/usr/bin/env python3.7

from datetime import datetime
from datetime import timezone
from datetime import timedelta
import json

def default(obj):
    if isinstance(obj, datetime):
        return { '_isoformat': obj.isoformat() }
    return super().default(obj)

def object_hook(obj):
    _isoformat = obj.get('_isoformat')
    if _isoformat is not None:
        return datetime.fromisoformat(_isoformat)
    return obj

if __name__ == '__main__':
    #d = { 'now': datetime(2000, 1, 1) }
    d = { 'now': datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=-8))) }
    s = json.dumps(d, default=default)
    print(s)
    print(d == json.loads(s, object_hook=object_hook))

输出:

{"now": {"_isoformat": "2000-01-01T00:00:00-08:00"}}
True

如果您使用的是python3.6或更低版本,并且您仅关心时间值(而不是时区),则可以使用datetime.timestamp()datetime.fromtimestamp()

如果您使用的是python3.6或更低版本,并且确实关心时区,则可以通过进行获取datetime.tzinfo,但是您必须自己序列化此字段;最简单的方法是_tzinfo在序列化对象中添加另一个字段;

最后,在所有这些示例中都要当心精度;

if you are using python3.7, then the best solution is using datetime.isoformat() and datetime.fromisoformat(); they work with both naive and aware datetime objects:

#!/usr/bin/env python3.7

from datetime import datetime
from datetime import timezone
from datetime import timedelta
import json

def default(obj):
    if isinstance(obj, datetime):
        return { '_isoformat': obj.isoformat() }
    return super().default(obj)

def object_hook(obj):
    _isoformat = obj.get('_isoformat')
    if _isoformat is not None:
        return datetime.fromisoformat(_isoformat)
    return obj

if __name__ == '__main__':
    #d = { 'now': datetime(2000, 1, 1) }
    d = { 'now': datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=-8))) }
    s = json.dumps(d, default=default)
    print(s)
    print(d == json.loads(s, object_hook=object_hook))

output:

{"now": {"_isoformat": "2000-01-01T00:00:00-08:00"}}
True

if you are using python3.6 or below, and you only care about the time value (not the timezone), then you can use datetime.timestamp() and datetime.fromtimestamp() instead;

if you are using python3.6 or below, and you do care about the timezone, then you can get it via datetime.tzinfo, but you have to serialize this field by yourself; the easiest way to do this is to add another field _tzinfo in the serialized object;

finally, beware of precisions in all these examples;


回答 12

您应使用.strftime()method on .datetime.now()method使其成为可序列化的方法。

这是一个例子:

from datetime import datetime

time_dict = {'time': datetime.now().strftime('%Y-%m-%dT%H:%M:%S')}
sample_dict = {'a': 1, 'b': 2}
sample_dict.update(time_dict)
sample_dict

输出:

Out[0]: {'a': 1, 'b': 2, 'time': '2017-10-31T15:16:30'}

You should use .strftime() method on .datetime.now() method to making it as a serializable method.

Here’s an example:

from datetime import datetime

time_dict = {'time': datetime.now().strftime('%Y-%m-%dT%H:%M:%S')}
sample_dict = {'a': 1, 'b': 2}
sample_dict.update(time_dict)
sample_dict

Output:

Out[0]: {'a': 1, 'b': 2, 'time': '2017-10-31T15:16:30'}

回答 13

这是解决“ datetime not JSON serializable”问题的简单解决方案。

enco = lambda obj: (
    obj.isoformat()
    if isinstance(obj, datetime.datetime)
    or isinstance(obj, datetime.date)
    else None
)

json.dumps({'date': datetime.datetime.now()}, default=enco)

输出:-> {“ date”:“ 2015-12-16T04:48:20.024609”}

Here is a simple solution to over come “datetime not JSON serializable” problem.

enco = lambda obj: (
    obj.isoformat()
    if isinstance(obj, datetime.datetime)
    or isinstance(obj, datetime.date)
    else None
)

json.dumps({'date': datetime.datetime.now()}, default=enco)

Output:-> {“date”: “2015-12-16T04:48:20.024609”}


回答 14

您必须提供一个自定义编码器类,其cls参数为json.dumps。引用文档

>>> import json
>>> class ComplexEncoder(json.JSONEncoder):
...     def default(self, obj):
...         if isinstance(obj, complex):
...             return [obj.real, obj.imag]
...         return json.JSONEncoder.default(self, obj)
...
>>> dumps(2 + 1j, cls=ComplexEncoder)
'[2.0, 1.0]'
>>> ComplexEncoder().encode(2 + 1j)
'[2.0, 1.0]'
>>> list(ComplexEncoder().iterencode(2 + 1j))
['[', '2.0', ', ', '1.0', ']']

这以复数为例,但是您可以轻松地创建一个类来对日期进行编码(但我认为JSON对日期有些模糊)

You have to supply a custom encoder class with the cls parameter of json.dumps. To quote from the docs:

>>> import json
>>> class ComplexEncoder(json.JSONEncoder):
...     def default(self, obj):
...         if isinstance(obj, complex):
...             return [obj.real, obj.imag]
...         return json.JSONEncoder.default(self, obj)
...
>>> dumps(2 + 1j, cls=ComplexEncoder)
'[2.0, 1.0]'
>>> ComplexEncoder().encode(2 + 1j)
'[2.0, 1.0]'
>>> list(ComplexEncoder().iterencode(2 + 1j))
['[', '2.0', ', ', '1.0', ']']

This uses complex numbers as the example, but you can just as easily create a class to encode dates (except I think JSON is a little fuzzy about dates)


回答 15

最简单的方法是将日期时间格式的字典部分更改为isoformat。该值将有效地是json可以使用的isoformat字符串。

v_dict = version.dict()
v_dict['created_at'] = v_dict['created_at'].isoformat()

The simplest way to do this is to change the part of the dict that is in datetime format to isoformat. That value will effectively be a string in isoformat which json is ok with.

v_dict = version.dict()
v_dict['created_at'] = v_dict['created_at'].isoformat()

回答 16

其实这很简单。如果您需要经常序列化日期,则将它们作为字符串使用。如果需要,您可以轻松地将它们转换回日期时间对象。

如果您主要需要用作日期时间对象,则在序列化之前将它们转换为字符串。

import json, datetime

date = str(datetime.datetime.now())
print(json.dumps(date))
"2018-12-01 15:44:34.409085"
print(type(date))
<class 'str'>

datetime_obj = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S.%f')
print(datetime_obj)
2018-12-01 15:44:34.409085
print(type(datetime_obj))
<class 'datetime.datetime'>

如您所见,两种情况下的输出是相同的。只有类型不同。

Actually it is quite simple. If you need to often serialize dates, then work with them as strings. You can easily convert them back as datetime objects if needed.

If you need to work mostly as datetime objects, then convert them as strings before serializing.

import json, datetime

date = str(datetime.datetime.now())
print(json.dumps(date))
"2018-12-01 15:44:34.409085"
print(type(date))
<class 'str'>

datetime_obj = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S.%f')
print(datetime_obj)
2018-12-01 15:44:34.409085
print(type(datetime_obj))
<class 'datetime.datetime'>

As you can see, the output is the same in both cases. Only the type is different.


回答 17

如果在视图中使用结果,请确保返回正确的响应。根据API,jsonify执行以下操作:

创建一个带有给定参数的JSON表示的响应,该响应具有application / json mimetype。

要用json.dumps模仿这种行为,您必须添加一些额外的代码行。

response = make_response(dumps(sample, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response

您还应该返回一个字典以完全复制jsonify的响应。因此,整个文件将如下所示

from flask import make_response
from json import JSONEncoder, dumps


class CustomEncoder(JSONEncoder):
    def default(self, obj):
        if set(['quantize', 'year']).intersection(dir(obj)):
            return str(obj)
        elif hasattr(obj, 'next'):
            return list(obj)
        return JSONEncoder.default(self, obj)

@app.route('/get_reps/', methods=['GET'])
def get_reps():
    sample = ['some text', <datetime object>, 123]
    response = make_response(dumps({'result': sample}, cls=CustomEncoder))
    response.headers['Content-Type'] = 'application/json'
    response.headers['mimetype'] = 'application/json'
    return response

If you are using the result in a view be sure to return a proper response. According to the API, jsonify does the following:

Creates a Response with the JSON representation of the given arguments with an application/json mimetype.

To mimic this behavior with json.dumps you have to add a few extra lines of code.

response = make_response(dumps(sample, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response

You should also return a dict to fully replicate jsonify’s response. So, the entire file will look like this

from flask import make_response
from json import JSONEncoder, dumps


class CustomEncoder(JSONEncoder):
    def default(self, obj):
        if set(['quantize', 'year']).intersection(dir(obj)):
            return str(obj)
        elif hasattr(obj, 'next'):
            return list(obj)
        return JSONEncoder.default(self, obj)

@app.route('/get_reps/', methods=['GET'])
def get_reps():
    sample = ['some text', <datetime object>, 123]
    response = make_response(dumps({'result': sample}, cls=CustomEncoder))
    response.headers['Content-Type'] = 'application/json'
    response.headers['mimetype'] = 'application/json'
    return response

回答 18

尝试用一个示例来解析它:

#!/usr/bin/env python

import datetime
import json

import dateutil.parser  # pip install python-dateutil


class JSONEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()
        return super(JSONEncoder, self).default(obj)


def test():
    dts = [
        datetime.datetime.now(),
        datetime.datetime.now(datetime.timezone(-datetime.timedelta(hours=4))),
        datetime.datetime.utcnow(),
        datetime.datetime.now(datetime.timezone.utc),
    ]
    for dt in dts:
        dt_isoformat = json.loads(json.dumps(dt, cls=JSONEncoder))
        dt_parsed = dateutil.parser.parse(dt_isoformat)
        assert dt == dt_parsed
        print(f'{dt}, {dt_isoformat}, {dt_parsed}')
        # 2018-07-22 02:22:42.910637, 2018-07-22T02:22:42.910637, 2018-07-22 02:22:42.910637
        # 2018-07-22 02:22:42.910643-04:00, 2018-07-22T02:22:42.910643-04:00, 2018-07-22 02:22:42.910643-04:00
        # 2018-07-22 06:22:42.910645, 2018-07-22T06:22:42.910645, 2018-07-22 06:22:42.910645
        # 2018-07-22 06:22:42.910646+00:00, 2018-07-22T06:22:42.910646+00:00, 2018-07-22 06:22:42.910646+00:00


if __name__ == '__main__':
    test()

Try this one with an example to parse it:

#!/usr/bin/env python

import datetime
import json

import dateutil.parser  # pip install python-dateutil


class JSONEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()
        return super(JSONEncoder, self).default(obj)


def test():
    dts = [
        datetime.datetime.now(),
        datetime.datetime.now(datetime.timezone(-datetime.timedelta(hours=4))),
        datetime.datetime.utcnow(),
        datetime.datetime.now(datetime.timezone.utc),
    ]
    for dt in dts:
        dt_isoformat = json.loads(json.dumps(dt, cls=JSONEncoder))
        dt_parsed = dateutil.parser.parse(dt_isoformat)
        assert dt == dt_parsed
        print(f'{dt}, {dt_isoformat}, {dt_parsed}')
        # 2018-07-22 02:22:42.910637, 2018-07-22T02:22:42.910637, 2018-07-22 02:22:42.910637
        # 2018-07-22 02:22:42.910643-04:00, 2018-07-22T02:22:42.910643-04:00, 2018-07-22 02:22:42.910643-04:00
        # 2018-07-22 06:22:42.910645, 2018-07-22T06:22:42.910645, 2018-07-22 06:22:42.910645
        # 2018-07-22 06:22:42.910646+00:00, 2018-07-22T06:22:42.910646+00:00, 2018-07-22 06:22:42.910646+00:00


if __name__ == '__main__':
    test()

回答 19

我的解决方案…

from datetime import datetime
import json

from pytz import timezone
import pytz


def json_dt_serializer(obj):
    """JSON serializer, by macm.
    """
    rsp = dict()
    if isinstance(obj, datetime):
        rsp['day'] = obj.day
        rsp['hour'] = obj.hour
        rsp['microsecond'] = obj.microsecond
        rsp['minute'] = obj.minute
        rsp['month'] = obj.month
        rsp['second'] = obj.second
        rsp['year'] = obj.year
        rsp['tzinfo'] = str(obj.tzinfo)
        return rsp
    raise TypeError("Type not serializable")


def json_dt_deserialize(obj):
    """JSON deserialize from json_dt_serializer, by macm.
    """
    if isinstance(obj, str):
        obj = json.loads(obj)
    tzone = timezone(obj['tzinfo'])
    tmp_dt = datetime(obj['year'],
                      obj['month'],
                      obj['day'],
                      hour=obj['hour'],
                      minute=obj['minute'],
                      second=obj['second'],
                      microsecond=obj['microsecond'])
    loc_dt = tzone.localize(tmp_dt)
    deserialize = loc_dt.astimezone(tzone)
    return deserialize    

好的,现在进行一些测试。

# Tests
now = datetime.now(pytz.utc)

# Using this solution
rsp = json_dt_serializer(now)
tmp = json_dt_deserialize(rsp)
assert tmp == now
assert isinstance(tmp, datetime) == True
assert isinstance(now, datetime) == True

# using default from json.dumps
tmp = json.dumps(datetime.now(pytz.utc), default=json_dt_serializer)
rsp = json_dt_deserialize(tmp)
assert isinstance(rsp, datetime) == True

# Lets try another timezone
eastern = timezone('US/Eastern')
now = datetime.now(eastern)
rsp = json_dt_serializer(now)
tmp = json_dt_deserialize(rsp)

print(tmp)
# 2015-10-22 09:18:33.169302-04:00

print(now)
# 2015-10-22 09:18:33.169302-04:00

# Wow, Works!
assert tmp == now

My solution …

from datetime import datetime
import json

from pytz import timezone
import pytz


def json_dt_serializer(obj):
    """JSON serializer, by macm.
    """
    rsp = dict()
    if isinstance(obj, datetime):
        rsp['day'] = obj.day
        rsp['hour'] = obj.hour
        rsp['microsecond'] = obj.microsecond
        rsp['minute'] = obj.minute
        rsp['month'] = obj.month
        rsp['second'] = obj.second
        rsp['year'] = obj.year
        rsp['tzinfo'] = str(obj.tzinfo)
        return rsp
    raise TypeError("Type not serializable")


def json_dt_deserialize(obj):
    """JSON deserialize from json_dt_serializer, by macm.
    """
    if isinstance(obj, str):
        obj = json.loads(obj)
    tzone = timezone(obj['tzinfo'])
    tmp_dt = datetime(obj['year'],
                      obj['month'],
                      obj['day'],
                      hour=obj['hour'],
                      minute=obj['minute'],
                      second=obj['second'],
                      microsecond=obj['microsecond'])
    loc_dt = tzone.localize(tmp_dt)
    deserialize = loc_dt.astimezone(tzone)
    return deserialize    

Ok, now some tests.

# Tests
now = datetime.now(pytz.utc)

# Using this solution
rsp = json_dt_serializer(now)
tmp = json_dt_deserialize(rsp)
assert tmp == now
assert isinstance(tmp, datetime) == True
assert isinstance(now, datetime) == True

# using default from json.dumps
tmp = json.dumps(datetime.now(pytz.utc), default=json_dt_serializer)
rsp = json_dt_deserialize(tmp)
assert isinstance(rsp, datetime) == True

# Lets try another timezone
eastern = timezone('US/Eastern')
now = datetime.now(eastern)
rsp = json_dt_serializer(now)
tmp = json_dt_deserialize(rsp)

print(tmp)
# 2015-10-22 09:18:33.169302-04:00

print(now)
# 2015-10-22 09:18:33.169302-04:00

# Wow, Works!
assert tmp == now

回答 20

这是将日期时间转换为JSON并返回的完整解决方案。

import calendar, datetime, json

def outputJSON(obj):
    """Default JSON serializer."""

    if isinstance(obj, datetime.datetime):
        if obj.utcoffset() is not None:
            obj = obj - obj.utcoffset()

        return obj.strftime('%Y-%m-%d %H:%M:%S.%f')
    return str(obj)

def inputJSON(obj):
    newDic = {}

    for key in obj:
        try:
            if float(key) == int(float(key)):
                newKey = int(key)
            else:
                newKey = float(key)

            newDic[newKey] = obj[key]
            continue
        except ValueError:
            pass

        try:
            newDic[str(key)] = datetime.datetime.strptime(obj[key], '%Y-%m-%d %H:%M:%S.%f')
            continue
        except TypeError:
            pass

        newDic[str(key)] = obj[key]

    return newDic

x = {'Date': datetime.datetime.utcnow(), 34: 89.9, 12.3: 90, 45: 67, 'Extra': 6}

print x

with open('my_dict.json', 'w') as fp:
    json.dump(x, fp, default=outputJSON)

with open('my_dict.json') as f:
    my_dict = json.load(f, object_hook=inputJSON)

print my_dict

输出量

{'Date': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, 'Extra': 6}
{'Date': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, 'Extra': 6}

JSON文件

{"Date": "2013-11-08 02:30:56.479727", "34": 89.9, "45": 67, "12.3": 90, "Extra": 6}

这使我能够导入和导出字符串,整数,浮点数和日期时间对象。对于其他类型,应该不难扩展。

Here is my full solution for converting datetime to JSON and back..

import calendar, datetime, json

def outputJSON(obj):
    """Default JSON serializer."""

    if isinstance(obj, datetime.datetime):
        if obj.utcoffset() is not None:
            obj = obj - obj.utcoffset()

        return obj.strftime('%Y-%m-%d %H:%M:%S.%f')
    return str(obj)

def inputJSON(obj):
    newDic = {}

    for key in obj:
        try:
            if float(key) == int(float(key)):
                newKey = int(key)
            else:
                newKey = float(key)

            newDic[newKey] = obj[key]
            continue
        except ValueError:
            pass

        try:
            newDic[str(key)] = datetime.datetime.strptime(obj[key], '%Y-%m-%d %H:%M:%S.%f')
            continue
        except TypeError:
            pass

        newDic[str(key)] = obj[key]

    return newDic

x = {'Date': datetime.datetime.utcnow(), 34: 89.9, 12.3: 90, 45: 67, 'Extra': 6}

print x

with open('my_dict.json', 'w') as fp:
    json.dump(x, fp, default=outputJSON)

with open('my_dict.json') as f:
    my_dict = json.load(f, object_hook=inputJSON)

print my_dict

Output

{'Date': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, 'Extra': 6}
{'Date': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, 'Extra': 6}

JSON File

{"Date": "2013-11-08 02:30:56.479727", "34": 89.9, "45": 67, "12.3": 90, "Extra": 6}

This has enabled me to import and export strings, ints, floats and datetime objects. It shouldn’t be to hard to extend for other types.


回答 21

转换datestring

date = str(datetime.datetime(somedatetimehere)) 

Convert the date to string

date = str(datetime.datetime(somedatetimehere)) 

回答 22

通常,有几种方法可以序列化日期时间,例如:

  1. ISO字符串,短,可以包含时区信息,例如@jgbarah的答案
  2. 时间戳记(时区数据丢失),例如@JayTaylor的答案
  3. 属性字典(包括时区)。

如果您对最后一种方法感到满意,则json_tricks包将处理日期,时间和日期时间,包括时区。

from datetime import datetime
from json_tricks import dumps
foo = {'title': 'String', 'datetime': datetime(2012, 8, 8, 21, 46, 24, 862000)}
dumps(foo)

这使:

{"title": "String", "datetime": {"__datetime__": null, "year": 2012, "month": 8, "day": 8, "hour": 21, "minute": 46, "second": 24, "microsecond": 862000}}

所以你要做的就是

`pip install json_tricks`

然后从而json_tricks不是json

解码时不将其存储为单个字符串,int或float的优点是:如果仅遇到字符串,或者特别是int或float,则需要了解有关数据的一些信息才能知道它是日期时间。作为命令,您可以存储元数据,以便可以对其进行自动解码,这就是json_tricks您需要的。它对于人类也很容易编辑。

免责声明:它是我做的。因为我有同样的问题。

Generally there are several ways to serialize datetimes, like:

  1. ISO string, short and can include timezone info, e.g. @jgbarah’s answer
  2. Timestamp (timezone data is lost), e.g. @JayTaylor’s answer
  3. Dictionary of properties (including timezone).

If you’re okay with the last way, the json_tricks package handles dates, times and datetimes including timezones.

from datetime import datetime
from json_tricks import dumps
foo = {'title': 'String', 'datetime': datetime(2012, 8, 8, 21, 46, 24, 862000)}
dumps(foo)

which gives:

{"title": "String", "datetime": {"__datetime__": null, "year": 2012, "month": 8, "day": 8, "hour": 21, "minute": 46, "second": 24, "microsecond": 862000}}

So all you need to do is

`pip install json_tricks`

and then import from json_tricks instead of json.

The advantage of not storing it as a single string, int or float comes when decoding: if you encounter just a string or especially int or float, you need to know something about the data to know if it’s a datetime. As a dict, you can store metadata so it can be decoded automatically, which is what json_tricks does for you. It’s also easily editable for humans.

Disclaimer: it’s made by me. Because I had the same problem.


回答 23

在使用sqlalchemy的类中编写序列化装饰器时,我得到了相同的错误消息。所以代替:

Class Puppy(Base):
    ...
    @property
    def serialize(self):
        return { 'id':self.id,
                 'date_birth':self.date_birth,
                  ...
                }

我只是借用了jgbarah使用isoformat()的想法,并将原始值附加到isoformat()上,因此现在看起来像:

                  ...
                 'date_birth':self.date_birth.isoformat(),
                  ...

I got the same error message while writing the serialize decorator inside a Class with sqlalchemy. So instead of :

Class Puppy(Base):
    ...
    @property
    def serialize(self):
        return { 'id':self.id,
                 'date_birth':self.date_birth,
                  ...
                }

I simply borrowed jgbarah’s idea of using isoformat() and appended the original value with isoformat(), so that it now looks like:

                  ...
                 'date_birth':self.date_birth.isoformat(),
                  ...

回答 24

如果需要自己的格式,可以快速解决

for key,val in sample.items():
    if isinstance(val, datetime):
        sample[key] = '{:%Y-%m-%d %H:%M:%S}'.format(val) #you can add different formating here
json.dumps(sample)

A quick fix if you want your own formatting

for key,val in sample.items():
    if isinstance(val, datetime):
        sample[key] = '{:%Y-%m-%d %H:%M:%S}'.format(val) #you can add different formating here
json.dumps(sample)

回答 25

如果您处于通信的两面,则可以将repr()eval()函数与json一起使用。

import datetime, json

dt = datetime.datetime.now()
print("This is now: {}".format(dt))

dt1 = json.dumps(repr(dt))
print("This is serialised: {}".format(dt1))

dt2 = json.loads(dt1)
print("This is loaded back from json: {}".format(dt2))

dt3 = eval(dt2)
print("This is the same object as we started: {}".format(dt3))

print("Check if they are equal: {}".format(dt == dt3))

您不应该将datetime导入为

from datetime import datetime

因为eval会抱怨。或者,您可以将datetime作为参数传递给eval。无论如何,这都行得通。

If you are on both sides of the communication you can use repr() and eval() functions along with json.

import datetime, json

dt = datetime.datetime.now()
print("This is now: {}".format(dt))

dt1 = json.dumps(repr(dt))
print("This is serialised: {}".format(dt1))

dt2 = json.loads(dt1)
print("This is loaded back from json: {}".format(dt2))

dt3 = eval(dt2)
print("This is the same object as we started: {}".format(dt3))

print("Check if they are equal: {}".format(dt == dt3))

You shouldn’t import datetime as

from datetime import datetime

since eval will complain. Or you can pass datetime as a parameter to eval. In any case this should work.


回答 26

当外部化Django模型对象以JSON格式转储时,我遇到了相同的问题。这是解决问题的方法。

def externalize(model_obj):
  keys = model_obj._meta.get_all_field_names() 
  data = {}
  for key in keys:
    if key == 'date_time':
      date_time_obj = getattr(model_obj, key)
      data[key] = date_time_obj.strftime("%A %d. %B %Y")
    else:
      data[key] = getattr(model_obj, key)
  return data

I had encountered same problem when externalizing django model object to dump as JSON. Here is how you can solve it.

def externalize(model_obj):
  keys = model_obj._meta.get_all_field_names() 
  data = {}
  for key in keys:
    if key == 'date_time':
      date_time_obj = getattr(model_obj, key)
      data[key] = date_time_obj.strftime("%A %d. %B %Y")
    else:
      data[key] = getattr(model_obj, key)
  return data

回答 27

def j_serial(o):     # self contained
    from datetime import datetime, date
    return str(o).split('.')[0] if isinstance(o, (datetime, date)) else None

上面实用程序的用法:

import datetime
serial_d = j_serial(datetime.datetime.now())
if serial_d:
    print(serial_d)  # output: 2018-02-28 02:23:15
def j_serial(o):     # self contained
    from datetime import datetime, date
    return str(o).split('.')[0] if isinstance(o, (datetime, date)) else None

Usage of above utility:

import datetime
serial_d = j_serial(datetime.datetime.now())
if serial_d:
    print(serial_d)  # output: 2018-02-28 02:23:15

回答 28

这个库superjson可以做到。您可以按照以下说明轻松为自己的Python对象自定义json序列化程序:https://superjson.readthedocs.io/index.html#extend

一般概念是:

您的代码需要根据python对象找到正确的序列化/反序列化方法。通常,完整的类名是一个很好的标识符。

然后,您的ser / deser方法应该能够将您的对象转换为常规的Json可序列化对象,该对象是通用python类型,dict,list,string,int,float的组合。并反向实施您的deser方法。

This library superjson can do it. And you can easily custom json serializer for your own Python Object by following this instruction https://superjson.readthedocs.io/index.html#extend.

The general concept is:

your code need to locate the right serialization / deserialization method based on the python object. Usually, the full classname is a good identifier.

And then your ser / deser method should be able to transform your object to a regular Json serializable object, a combination of generic python type, dict, list, string, int, float. And implement your deser method reversely.


回答 29

我可能不是100%正确,但这是进行序列化的简单方法

#!/usr/bin/python
import datetime,json

sampledict = {}
sampledict['a'] = "some string"
sampledict['b'] = datetime.datetime.now()

print sampledict   # output : {'a': 'some string', 'b': datetime.datetime(2017, 4, 15, 5, 15, 34, 652996)}

#print json.dumps(sampledict)

'''
output : 

Traceback (most recent call last):
  File "./jsonencodedecode.py", line 10, in <module>
    print json.dumps(sampledict)
  File "/usr/lib/python2.7/json/__init__.py", line 244, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python2.7/json/encoder.py", line 184, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: datetime.datetime(2017, 4, 15, 5, 16, 17, 435706) is not JSON serializable


'''

sampledict['b'] = datetime.datetime.now().strftime("%B %d, %Y %H:%M %p")

afterdump = json.dumps(sampledict)

print afterdump  #output : {"a": "some string", "b": "April 15, 2017 05:18 AM"}

print type(afterdump) #<type 'str'>


afterloads = json.loads(afterdump) 

print afterloads # output : {u'a': u'some string', u'b': u'April 15, 2017 05:18 AM'}


print type(afterloads) # output :<type 'dict'> 

I may not 100% correct but, this is the simple way to do serialize

#!/usr/bin/python
import datetime,json

sampledict = {}
sampledict['a'] = "some string"
sampledict['b'] = datetime.datetime.now()

print sampledict   # output : {'a': 'some string', 'b': datetime.datetime(2017, 4, 15, 5, 15, 34, 652996)}

#print json.dumps(sampledict)

'''
output : 

Traceback (most recent call last):
  File "./jsonencodedecode.py", line 10, in <module>
    print json.dumps(sampledict)
  File "/usr/lib/python2.7/json/__init__.py", line 244, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python2.7/json/encoder.py", line 184, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: datetime.datetime(2017, 4, 15, 5, 16, 17, 435706) is not JSON serializable


'''

sampledict['b'] = datetime.datetime.now().strftime("%B %d, %Y %H:%M %p")

afterdump = json.dumps(sampledict)

print afterdump  #output : {"a": "some string", "b": "April 15, 2017 05:18 AM"}

print type(afterdump) #<type 'str'>


afterloads = json.loads(afterdump) 

print afterloads # output : {u'a': u'some string', u'b': u'April 15, 2017 05:18 AM'}


print type(afterloads) # output :<type 'dict'> 

为什么Python无法解析此JSON数据?

问题:为什么Python无法解析此JSON数据?

我在文件中有此JSON:

{
    "maps": [
        {
            "id": "blabla",
            "iscategorical": "0"
        },
        {
            "id": "blabla",
            "iscategorical": "0"
        }
    ],
    "masks": [
        "id": "valore"
    ],
    "om_points": "value",
    "parameters": [
        "id": "valore"
    ]
}

我编写了以下脚本来打印所有JSON数据:

import json
from pprint import pprint

with open('data.json') as f:
    data = json.load(f)

pprint(data)

但是,该程序会引发异常:

Traceback (most recent call last):
  File "<pyshell#1>", line 5, in <module>
    data = json.load(f)
  File "/usr/lib/python3.5/json/__init__.py", line 319, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.5/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.5/json/decoder.py", line 355, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting ',' delimiter: line 13 column 13 (char 213)

如何解析JSON并提取其值?

I have this JSON in a file:

{
    "maps": [
        {
            "id": "blabla",
            "iscategorical": "0"
        },
        {
            "id": "blabla",
            "iscategorical": "0"
        }
    ],
    "masks": [
        "id": "valore"
    ],
    "om_points": "value",
    "parameters": [
        "id": "valore"
    ]
}

I wrote this script to print all of the JSON data:

import json
from pprint import pprint

with open('data.json') as f:
    data = json.load(f)

pprint(data)

This program raises an exception, though:

Traceback (most recent call last):
  File "<pyshell#1>", line 5, in <module>
    data = json.load(f)
  File "/usr/lib/python3.5/json/__init__.py", line 319, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.5/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.5/json/decoder.py", line 355, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting ',' delimiter: line 13 column 13 (char 213)

How can I parse the JSON and extract its values?


回答 0

您的数据不是有效的JSON格式。您有[]什么时候应该拥有{}

  • []用于JSON数组,list在Python 中称为
  • {}用于JSON对象(dict在Python 中称为JSON对象)

JSON文件的外观如下:

{
    "maps": [
        {
            "id": "blabla",
            "iscategorical": "0"
        },
        {
            "id": "blabla",
            "iscategorical": "0"
        }
    ],
    "masks": {
        "id": "valore"
    },
    "om_points": "value",
    "parameters": {
        "id": "valore"
    }
}

然后,您可以使用您的代码:

import json
from pprint import pprint

with open('data.json') as f:
    data = json.load(f)

pprint(data)

使用数据,您现在还可以找到类似的值:

data["maps"][0]["id"]
data["masks"]["id"]
data["om_points"]

试试看,看看是否有意义。

Your data is not valid JSON format. You have [] when you should have {}:

  • [] are for JSON arrays, which are called list in Python
  • {} are for JSON objects, which are called dict in Python

Here’s how your JSON file should look:

{
    "maps": [
        {
            "id": "blabla",
            "iscategorical": "0"
        },
        {
            "id": "blabla",
            "iscategorical": "0"
        }
    ],
    "masks": {
        "id": "valore"
    },
    "om_points": "value",
    "parameters": {
        "id": "valore"
    }
}

Then you can use your code:

import json
from pprint import pprint

with open('data.json') as f:
    data = json.load(f)

pprint(data)

With data, you can now also find values like so:

data["maps"][0]["id"]
data["masks"]["id"]
data["om_points"]

Try those out and see if it starts to make sense.


回答 1

data.json应该看起来像这样:

{
 "maps":[
         {"id":"blabla","iscategorical":"0"},
         {"id":"blabla","iscategorical":"0"}
        ],
"masks":
         {"id":"valore"},
"om_points":"value",
"parameters":
         {"id":"valore"}
}

您的代码应为:

import json
from pprint import pprint

with open('data.json') as data_file:    
    data = json.load(data_file)
pprint(data)

请注意,这仅在Python 2.6及更高版本中有效,因为它取决于with-statement。在Python 2.5中使用from __future__ import with_statement,在Python <= 2.4中,请参见Justin Peel的答案,该答案基于该答案。

您现在还可以像这样访问单个值:

data["maps"][0]["id"]  # will return 'blabla'
data["masks"]["id"]    # will return 'valore'
data["om_points"]      # will return 'value'

Your data.json should look like this:

{
 "maps":[
         {"id":"blabla","iscategorical":"0"},
         {"id":"blabla","iscategorical":"0"}
        ],
"masks":
         {"id":"valore"},
"om_points":"value",
"parameters":
         {"id":"valore"}
}

Your code should be:

import json
from pprint import pprint

with open('data.json') as data_file:    
    data = json.load(data_file)
pprint(data)

Note that this only works in Python 2.6 and up, as it depends upon the with-statement. In Python 2.5 use from __future__ import with_statement, in Python <= 2.4, see Justin Peel’s answer, which this answer is based upon.

You can now also access single values like this:

data["maps"][0]["id"]  # will return 'blabla'
data["masks"]["id"]    # will return 'valore'
data["om_points"]      # will return 'value'

回答 2

贾斯汀·皮尔(Justin Peel)的回答确实很有帮助,但是,如果您使用的是Python 3,则应按以下方式读取JSON:

with open('data.json', encoding='utf-8') as data_file:
    data = json.loads(data_file.read())

注意:使用json.loads代替json.load。在Python 3中,json.loads采用字符串参数。json.load采用类似文件的对象参数。data_file.read()返回一个字符串对象。

老实说,在大多数情况下,将所有json数据加载到内存中都不是问题。

Justin Peel’s answer is really helpful, but if you are using Python 3 reading JSON should be done like this:

with open('data.json', encoding='utf-8') as data_file:
    data = json.loads(data_file.read())

Note: use json.loads instead of json.load. In Python 3, json.loads takes a string parameter. json.load takes a file-like object parameter. data_file.read() returns a string object.

To be honest, I don’t think it’s a problem to load all json data into memory most cases.


回答 3

data = []
with codecs.open('d:\output.txt','rU','utf-8') as f:
    for line in f:
       data.append(json.loads(line))
data = []
with codecs.open('d:\output.txt','rU','utf-8') as f:
    for line in f:
       data.append(json.loads(line))

回答 4

“超JSON”或简称“ ujson”可以处理[]您的JSON文件输入中的内容。如果您正在将程序中的JSON输入文件作为JSON元素列表读取;例如,[{[{}]}, {}, [], etc...]ujson可以处理字典列表的任何任意顺序,即列表字典。

您可以在Python包索引中找到ujson,并且该API与Python的内置json库几乎相同。

如果您要加载较大的JSON文件,则ujson也会更快。与提供的相同链接中的其他Python JSON库相比,您可以看到性能详细信息。

“Ultra JSON” or simply “ujson” can handle having [] in your JSON file input. If you’re reading a JSON input file into your program as a list of JSON elements; such as, [{[{}]}, {}, [], etc...] ujson can handle any arbitrary order of lists of dictionaries, dictionaries of lists.

You can find ujson in the Python package index and the API is almost identical to Python’s built-in json library.

ujson is also much faster if you’re loading larger JSON files. You can see the performance details in comparison to other Python JSON libraries in the same link provided.


回答 5

如果您使用的是Python3,则可以尝试将(connection.json文件)JSON 更改为:

{
  "connection1": {
    "DSN": "con1",
    "UID": "abc",
    "PWD": "1234",
    "connection_string_python":"test1"
  }
  ,
  "connection2": {
    "DSN": "con2",
    "UID": "def",
    "PWD": "1234"
  }
}

然后使用以下代码:

connection_file = open('connection.json', 'r')
conn_string = json.load(connection_file)
conn_string['connection1']['connection_string_python'])
connection_file.close()
>>> test1

If you’re using Python3, you can try changing your (connection.json file) JSON to:

{
  "connection1": {
    "DSN": "con1",
    "UID": "abc",
    "PWD": "1234",
    "connection_string_python":"test1"
  }
  ,
  "connection2": {
    "DSN": "con2",
    "UID": "def",
    "PWD": "1234"
  }
}

Then using the following code:

connection_file = open('connection.json', 'r')
conn_string = json.load(connection_file)
conn_string['connection1']['connection_string_python'])
connection_file.close()
>>> test1

回答 6

在这里,您可以使用修改后的data.json文件:

{
    "maps": [
        {
            "id": "blabla",
            "iscategorical": "0"
        },
        {
            "id": "blabla",
            "iscategorical": "0"
        }
    ],
    "masks": [{
        "id": "valore"
    }],
    "om_points": "value",
    "parameters": [{
        "id": "valore"
    }]
}

您可以使用以下几行在控制台上调用或打印数据:

import json
from pprint import pprint
with open('data.json') as data_file:
    data_item = json.load(data_file)
pprint(data_item)

预期输出print(data_item['parameters'][0]['id'])

{'maps': [{'id': 'blabla', 'iscategorical': '0'},
          {'id': 'blabla', 'iscategorical': '0'}],
 'masks': [{'id': 'valore'}],
 'om_points': 'value',
 'parameters': [{'id': 'valore'}]}

预期输出print(data_item['parameters'][0]['id'])

valore

Here you go with modified data.json file:

{
    "maps": [
        {
            "id": "blabla",
            "iscategorical": "0"
        },
        {
            "id": "blabla",
            "iscategorical": "0"
        }
    ],
    "masks": [{
        "id": "valore"
    }],
    "om_points": "value",
    "parameters": [{
        "id": "valore"
    }]
}

You can call or print data on console by using below lines:

import json
from pprint import pprint
with open('data.json') as data_file:
    data_item = json.load(data_file)
pprint(data_item)

Expected output for print(data_item['parameters'][0]['id']):

{'maps': [{'id': 'blabla', 'iscategorical': '0'},
          {'id': 'blabla', 'iscategorical': '0'}],
 'masks': [{'id': 'valore'}],
 'om_points': 'value',
 'parameters': [{'id': 'valore'}]}

Expected output for print(data_item['parameters'][0]['id']):

valore

回答 7

该解析有两种类型。

  1. 从系统路径解析文件中的数据
  2. 从远程URL解析JSON。

从文件中,您可以使用以下内容

import json
json = json.loads(open('/path/to/file.json').read())
value = json['key']
print json['value']

该小节解释了使用两种情况的完整解析和获取值。使用Python解析JSON

There are two types in this parsing.

  1. Parsing data from a file from a system path
  2. Parsing JSON from remote URL.

From a file, you can use the following

import json
json = json.loads(open('/path/to/file.json').read())
value = json['key']
print json['value']

This arcticle explains the full parsing and getting values using two scenarios.Parsing JSON using Python


回答 8

作为python3用户

loadloads方法之间的区别非常重要,尤其是当您从文件中读取json数据时。

如文档中所述:

json.load:

使用此转换表将fp(支持.read()的文本文件或包含JSON文档的二进制文件)反序列化为Python对象。

json.loads:

json.loads:使用此转换表将s(包含JSON文档的str,字节或字节数组实例)反序列化为Python对象。

json.load方法可以读取二进制文件,因此可以直接读取打开的json文档。

with open('./recipes.json') as data:
  all_recipes = json.load(data)

结果,您的json数据以根据此转换表指定的格式可用:

https://docs.python.org/3.7/library/json.html#json-to-py-table

As a python3 user,

The difference between load and loads methods is important especially when you read json data from file.

As stated in the docs:

json.load:

Deserialize fp (a .read()-supporting text file or binary file containing a JSON document) to a Python object using this conversion table.

json.loads:

json.loads: Deserialize s (a str, bytes or bytearray instance containing a JSON document) to a Python object using this conversion table.

json.load method can directly read opened json document since it is able to read binary file.

with open('./recipes.json') as data:
  all_recipes = json.load(data)

As a result, your json data available as in a format specified according to this conversion table:

https://docs.python.org/3.7/library/json.html#json-to-py-table


如何将JSON数据写入文件?

问题:如何将JSON数据写入文件?

我将JSON数据存储在变量中data

我想将其写入文本文件进行测试,因此不必每次都从服务器获取数据。

目前,我正在尝试:

obj = open('data.txt', 'wb')
obj.write(data)
obj.close

我收到此错误:

TypeError:必须是字符串或缓冲区,而不是dict

如何解决这个问题?

I have JSON data stored in the variable data.

I want to write this to a text file for testing so I don’t have to grab the data from the server each time.

Currently, I am trying this:

obj = open('data.txt', 'wb')
obj.write(data)
obj.close

And I am receiving this error:

TypeError: must be string or buffer, not dict

How to fix this?


回答 0

您忘记了实际的JSON部分- data是字典,尚未进行JSON编码。写这样的最大兼容性(Python 2和3):

import json
with open('data.json', 'w') as f:
    json.dump(data, f)

在现代系统(即Python 3和UTF-8支持)上,您可以使用

import json
with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)

You forgot the actual JSON part – data is a dictionary and not yet JSON-encoded. Write it like this for maximum compatibility (Python 2 and 3):

import json
with open('data.json', 'w') as f:
    json.dump(data, f)

On a modern system (i.e. Python 3 and UTF-8 support), you can write a nicer file with

import json
with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)

回答 1

要获取utf8编码的文件,而不是Python 2可接受答案中的ascii编码,请使用:

import io, json
with io.open('data.txt', 'w', encoding='utf-8') as f:
  f.write(json.dumps(data, ensure_ascii=False))

该代码在Python 3中更简单:

import json
with open('data.txt', 'w') as f:
  json.dump(data, f, ensure_ascii=False)

在Windows上,encoding='utf-8'to 的参数open仍然是必需的。

为避免将数据的编码副本存储在内存中(结果为dumps),并在Python 2和3中输出utf8编码的字节串,请使用:

import json, codecs
with open('data.txt', 'wb') as f:
    json.dump(data, codecs.getwriter('utf-8')(f), ensure_ascii=False)

codecs.getwriter调用在Python 3中是多余的,但对于Python 2是必需的


可读性和大小:

使用可以ensure_ascii=False提供更好的可读性和更小的尺寸:

>>> json.dumps({'price': '€10'})
'{"price": "\\u20ac10"}'
>>> json.dumps({'price': '€10'}, ensure_ascii=False)
'{"price": "€10"}'

>>> len(json.dumps({'абвгд': 1}))
37
>>> len(json.dumps({'абвгд': 1}, ensure_ascii=False).encode('utf8'))
17

通过将标记indent=4, sort_keys=True(如dinos66所建议的)添加到dump或的参数,进一步提高可读性dumps。这样,您将在json文件中获得一个很好的缩进排序结构,但要付出稍大的文件大小。

To get utf8-encoded file as opposed to ascii-encoded in the accepted answer for Python 2 use:

import io, json
with io.open('data.txt', 'w', encoding='utf-8') as f:
  f.write(json.dumps(data, ensure_ascii=False))

The code is simpler in Python 3:

import json
with open('data.txt', 'w') as f:
  json.dump(data, f, ensure_ascii=False)

On Windows, the encoding='utf-8' argument to open is still necessary.

To avoid storing an encoded copy of the data in memory (result of dumps) and to output utf8-encoded bytestrings in both Python 2 and 3, use:

import json, codecs
with open('data.txt', 'wb') as f:
    json.dump(data, codecs.getwriter('utf-8')(f), ensure_ascii=False)

The codecs.getwriter call is redundant in Python 3 but required for Python 2


Readability and size:

The use of ensure_ascii=False gives better readability and smaller size:

>>> json.dumps({'price': '€10'})
'{"price": "\\u20ac10"}'
>>> json.dumps({'price': '€10'}, ensure_ascii=False)
'{"price": "€10"}'

>>> len(json.dumps({'абвгд': 1}))
37
>>> len(json.dumps({'абвгд': 1}, ensure_ascii=False).encode('utf8'))
17

Further improve readability by adding flags indent=4, sort_keys=True (as suggested by dinos66) to arguments of dump or dumps. This way you’ll get a nicely indented sorted structure in the json file at the cost of a slightly larger file size.


回答 2

我会稍作修改,对上述答案进行回答,那就是编写一个美化的JSON文件,人眼可以更好地阅读。为此,sort_keysTrue和传递indent4个空格字符就可以了。还要注意确保不会将ASCII代码写入您的JSON文件中:

with open('data.txt', 'w') as outfile:
     json.dump(jsonData, outfile, sort_keys = True, indent = 4,
               ensure_ascii = False)

I would answer with slight modification with aforementioned answers and that is to write a prettified JSON file which human eyes can read better. For this, pass sort_keys as True and indent with 4 space characters and you are good to go. Also take care of ensuring that the ascii codes will not be written in your JSON file:

with open('data.txt', 'w') as outfile:
     json.dump(jsonData, outfile, sort_keys = True, indent = 4,
               ensure_ascii = False)

回答 3

使用Python 2 + 3读写JSON文件;与unicode一起使用

# -*- coding: utf-8 -*-
import json

# Make it work for Python 2+3 and with Unicode
import io
try:
    to_unicode = unicode
except NameError:
    to_unicode = str

# Define data
data = {'a list': [1, 42, 3.141, 1337, 'help', u'€'],
        'a string': 'bla',
        'another dict': {'foo': 'bar',
                         'key': 'value',
                         'the answer': 42}}

# Write JSON file
with io.open('data.json', 'w', encoding='utf8') as outfile:
    str_ = json.dumps(data,
                      indent=4, sort_keys=True,
                      separators=(',', ': '), ensure_ascii=False)
    outfile.write(to_unicode(str_))

# Read JSON file
with open('data.json') as data_file:
    data_loaded = json.load(data_file)

print(data == data_loaded)

参数说明json.dump

  • indent:使用4个空格来缩进每个条目,例如,当开始一个新的dict时(否则所有内容将排在一行中),
  • sort_keys:对字典的键进行排序。如果要使用diff工具比较json文件/将其置于版本控制下,则此功能很有用。
  • separators:防止Python添加尾随空格

带包装

看看我的实用程序包mpu,它是一个超级简单易记的软件包:

import mpu.io
data = mpu.io.read('example.json')
mpu.io.write('example.json', data)

创建的JSON文件

{
    "a list":[
        1,
        42,
        3.141,
        1337,
        "help",
        "€"
    ],
    "a string":"bla",
    "another dict":{
        "foo":"bar",
        "key":"value",
        "the answer":42
    }
}

通用文件结尾

.json

备择方案

对于您的应用程序,以下内容可能很重要:

  • 其他编程语言的支持
  • 阅读/写作表现
  • 紧凑度(文件大小)

也可以看看: 数据序列化格式的比较

如果您想寻找一种制作配置文件的方法,则可能需要阅读我的短文《Python中的配置文件》。

Read and write JSON files with Python 2+3; works with unicode

# -*- coding: utf-8 -*-
import json

# Make it work for Python 2+3 and with Unicode
import io
try:
    to_unicode = unicode
except NameError:
    to_unicode = str

# Define data
data = {'a list': [1, 42, 3.141, 1337, 'help', u'€'],
        'a string': 'bla',
        'another dict': {'foo': 'bar',
                         'key': 'value',
                         'the answer': 42}}

# Write JSON file
with io.open('data.json', 'w', encoding='utf8') as outfile:
    str_ = json.dumps(data,
                      indent=4, sort_keys=True,
                      separators=(',', ': '), ensure_ascii=False)
    outfile.write(to_unicode(str_))

# Read JSON file
with open('data.json') as data_file:
    data_loaded = json.load(data_file)

print(data == data_loaded)

Explanation of the parameters of json.dump:

  • indent: Use 4 spaces to indent each entry, e.g. when a new dict is started (otherwise all will be in one line),
  • sort_keys: sort the keys of dictionaries. This is useful if you want to compare json files with a diff tool / put them under version control.
  • separators: To prevent Python from adding trailing whitespaces

With a package

Have a look at my utility package mpu for a super simple and easy to remember one:

import mpu.io
data = mpu.io.read('example.json')
mpu.io.write('example.json', data)

Created JSON file

{
    "a list":[
        1,
        42,
        3.141,
        1337,
        "help",
        "€"
    ],
    "a string":"bla",
    "another dict":{
        "foo":"bar",
        "key":"value",
        "the answer":42
    }
}

Common file endings

.json

Alternatives

For your application, the following might be important:

  • Support by other programming languages
  • Reading / writing performance
  • Compactness (file size)

See also: Comparison of data serialization formats

In case you are rather looking for a way to make configuration files, you might want to read my short article Configuration files in Python


回答 4

对于那些尝试转储希腊语或其他“异类”语言(例如我)但也遇到奇怪字符(例如和平符号(\ u262E)或通常包含在json格式数据中的其他字符)的问题(unicode错误)的人例如Twitter,解决方案可能如下(sort_keys显然是可选的):

import codecs, json
with codecs.open('data.json', 'w', 'utf8') as f:
     f.write(json.dumps(data, sort_keys = True, ensure_ascii=False))

For those of you who are trying to dump greek or other “exotic” languages such as me but are also having problems (unicode errors) with weird characters such as the peace symbol (\u262E) or others which are often contained in json formated data such as Twitter’s, the solution could be as follows (sort_keys is obviously optional):

import codecs, json
with codecs.open('data.json', 'w', 'utf8') as f:
     f.write(json.dumps(data, sort_keys = True, ensure_ascii=False))

回答 5

我没有足够的声誉来添加评论,所以我只在这里写下关于此烦人的TypeError的一些发现:

基本上,我认为这仅json.dump()是Python 2中的函数错误- 即使使用encoding = 'utf-8'参数打开文件,也无法转储包含非ASCII字符的Python(字典/列表)数据。(即,无论您做什么)。但是,json.dumps()可以在Python 2和3上使用。

为了说明这一点,请遵循phihag的答案:他的答案中的代码在Python 2中会中断TypeError: must be unicode, not str,如果data包含非ASCII字符,则会出现exception 。(Python 2.7.6,Debian):

import json
data = {u'\u0430\u0431\u0432\u0433\u0434': 1} #{u'абвгд': 1}
with open('data.txt', 'w') as outfile:
    json.dump(data, outfile)

但是,它在Python 3中工作正常。

I don’t have enough reputation to add in comments, so I just write some of my findings of this annoying TypeError here:

Basically, I think it’s a bug in the json.dump() function in Python 2 only – It can’t dump a Python (dictionary / list) data containing non-ASCII characters, even you open the file with the encoding = 'utf-8' parameter. (i.e. No matter what you do). But, json.dumps() works on both Python 2 and 3.

To illustrate this, following up phihag’s answer: the code in his answer breaks in Python 2 with exception TypeError: must be unicode, not str, if data contains non-ASCII characters. (Python 2.7.6, Debian):

import json
data = {u'\u0430\u0431\u0432\u0433\u0434': 1} #{u'абвгд': 1}
with open('data.txt', 'w') as outfile:
    json.dump(data, outfile)

It however works fine in Python 3.


回答 6

使用JSON使用json.dump()json.dumps()在文件中写入数据。这样写即可将数据存储在文件中。

import json
data = [1,2,3,4,5]
with open('no.txt', 'w') as txtfile:
    json.dump(data, txtfile)

列表中的此示例存储到文件中。

Write a data in file using JSON use json.dump() or json.dumps() used. write like this to store data in file.

import json
data = [1,2,3,4,5]
with open('no.txt', 'w') as txtfile:
    json.dump(data, txtfile)

this example in list is store to a file.


回答 7

要使用缩进“漂亮打印”来编写JSON:

import json

outfile = open('data.json')
json.dump(data, outfile, indent=4)

另外,如果您需要调试格式不正确的JSON,并希望得到有用的错误消息,请使用import simplejson库而不是import json(功能应相同)

To write the JSON with indentation, “pretty print”:

import json

outfile = open('data.json')
json.dump(data, outfile, indent=4)

Also, if you need to debug improperly formatted JSON, and want a helpful error message, use import simplejson library, instead of import json (functions should be the same)


回答 8

json.dump(data, open('data.txt', 'wb'))
json.dump(data, open('data.txt', 'wb'))

回答 9

将JSON写入文件

import json

data = {}
data['people'] = []
data['people'].append({
    'name': 'Scott',
    'website': 'stackabuse.com',
    'from': 'Nebraska'
})
data['people'].append({
    'name': 'Larry',
    'website': 'google.com',
    'from': 'Michigan'
})
data['people'].append({
    'name': 'Tim',
    'website': 'apple.com',
    'from': 'Alabama'
})

with open('data.txt', 'w') as outfile:
    json.dump(data, outfile)

从文件读取JSON

import json

with open('data.txt') as json_file:
    data = json.load(json_file)
    for p in data['people']:
        print('Name: ' + p['name'])
        print('Website: ' + p['website'])
        print('From: ' + p['from'])
        print('')

Writing JSON to a File

import json

data = {}
data['people'] = []
data['people'].append({
    'name': 'Scott',
    'website': 'stackabuse.com',
    'from': 'Nebraska'
})
data['people'].append({
    'name': 'Larry',
    'website': 'google.com',
    'from': 'Michigan'
})
data['people'].append({
    'name': 'Tim',
    'website': 'apple.com',
    'from': 'Alabama'
})

with open('data.txt', 'w') as outfile:
    json.dump(data, outfile)

Reading JSON from a File

import json

with open('data.txt') as json_file:
    data = json.load(json_file)
    for p in data['people']:
        print('Name: ' + p['name'])
        print('Website: ' + p['website'])
        print('From: ' + p['from'])
        print('')

回答 10

如果您尝试使用json格式将pandas数据帧写入文件,我建议您这样做

destination='filepath'
saveFile = open(destination, 'w')
saveFile.write(df.to_json())
saveFile.close()

if you are trying to write a pandas dataframe into a file using a json format i’d recommend this

destination='filepath'
saveFile = open(destination, 'w')
saveFile.write(df.to_json())
saveFile.close()

回答 11

以前所有的答案都是正确的,这是一个非常简单的示例:

#! /usr/bin/env python
import json

def write_json():
    # create a dictionary  
    student_data = {"students":[]}
    #create a list
    data_holder = student_data["students"]
    # just a counter
    counter = 0
    #loop through if you have multiple items..         
    while counter < 3:
        data_holder.append({'id':counter})
        data_holder.append({'room':counter})
        counter += 1    
    #write the file        
    file_path='/tmp/student_data.json'
    with open(file_path, 'w') as outfile:
        print("writing file to: ",file_path)
        # HERE IS WHERE THE MAGIC HAPPENS 
        json.dump(student_data, outfile)
    outfile.close()     
    print("done")

write_json()

All previous answers are correct here is a very simple example:

#! /usr/bin/env python
import json

def write_json():
    # create a dictionary  
    student_data = {"students":[]}
    #create a list
    data_holder = student_data["students"]
    # just a counter
    counter = 0
    #loop through if you have multiple items..         
    while counter < 3:
        data_holder.append({'id':counter})
        data_holder.append({'room':counter})
        counter += 1    
    #write the file        
    file_path='/tmp/student_data.json'
    with open(file_path, 'w') as outfile:
        print("writing file to: ",file_path)
        # HERE IS WHERE THE MAGIC HAPPENS 
        json.dump(student_data, outfile)
    outfile.close()     
    print("done")

write_json()


回答 12

接受的答案很好。但是,我遇到了“不是json可序列化”错误。

这是我将其固定open("file-name.json", 'w')为输出的方式:

output.write(str(response))

尽管它不是一个很好的解决方案,因为它创建的json文件不会使用双引号,但是如果您希望快速又肮脏的话,那就太好了。

The accepted answer is fine. However, I ran into “is not json serializable” error using that.

Here’s how I fixed it with open("file-name.json", 'w') as output:

output.write(str(response))

Although it is not a good fix as the json file it creates will not have double quotes, however it is great if you are looking for quick and dirty.


回答 13

可以将JSON数据写入文件,如下所示

hist1 = [{'val_loss': [0.5139984398465246],
'val_acc': [0.8002029867684085],
'loss': [0.593220705309384],
'acc': [0.7687131817929321]},
{'val_loss': [0.46456472964199463],
'val_acc': [0.8173602046780344],
'loss': [0.4932038113037539],
'acc': [0.8063946213802453]}]

写入文件:

with open('text1.json', 'w') as f:
     json.dump(hist1, f)

The JSON data can be written to a file as follows

hist1 = [{'val_loss': [0.5139984398465246],
'val_acc': [0.8002029867684085],
'loss': [0.593220705309384],
'acc': [0.7687131817929321]},
{'val_loss': [0.46456472964199463],
'val_acc': [0.8173602046780344],
'loss': [0.4932038113037539],
'acc': [0.8063946213802453]}]

Write to a file:

with open('text1.json', 'w') as f:
     json.dump(hist1, f)

如何打印JSON文件?

问题:如何打印JSON文件?

我有一个JSON文件,我想对其进行漂亮打印-在python中执行此操作的最简单方法是什么?我知道PrettyPrint带有一个“对象”,我认为它可以是一个文件,但是我不知道如何传递文件-仅使用文件名是行不通的。

I have a JSON file that is a mess that I want to prettyprint– what’s the easiest way to do this in python? I know PrettyPrint takes an “object”, which I think can be a file, but I don’t know how to pass a file in– just using the filename doesn’t work.


回答 0

json模块已经使用indent参数实现了一些基本的漂亮打印:

>>> import json
>>>
>>> your_json = '["foo", {"bar":["baz", null, 1.0, 2]}]'
>>> parsed = json.loads(your_json)
>>> print(json.dumps(parsed, indent=4, sort_keys=True))
[
    "foo", 
    {
        "bar": [
            "baz", 
            null, 
            1.0, 
            2
        ]
    }
]

要解析文件,请使用json.load()

with open('filename.txt', 'r') as handle:
    parsed = json.load(handle)

The json module already implements some basic pretty printing with the indent parameter:

>>> import json
>>>
>>> your_json = '["foo", {"bar":["baz", null, 1.0, 2]}]'
>>> parsed = json.loads(your_json)
>>> print(json.dumps(parsed, indent=4, sort_keys=True))
[
    "foo", 
    {
        "bar": [
            "baz", 
            null, 
            1.0, 
            2
        ]
    }
]

To parse a file, use json.load():

with open('filename.txt', 'r') as handle:
    parsed = json.load(handle)

回答 1

您可以在命令行上执行此操作:

python3 -m json.tool some.json

(正如问题注释中已经提到的,感谢@Kai Petzke的python3建议)。

实际上,就命令行上的json处理而言,python不是我最喜欢的工具。简单的漂亮打印是可以的,但是如果您要操作json,它可能会变得过于复杂。您很快就需要编写一个单独的脚本文件,最终可能得到其键为u“ some-key”(python unicode)的地图,这会使选择字段更加困难,并且实际上并没有朝着漂亮的方向发展。 -印刷。

您也可以使用jq

jq . some.json

并获得颜色作为奖励(并且更容易扩展)。

附录:关于使用jq一方面处理大型JSON文件,另一方面使用非常大的jq程序的注释有些混乱。对于漂亮地打印由单个大型JSON实体组成的文件,实际的限制是RAM。对于漂亮地打印由单个真实数据数组组成的2GB文件,漂亮打印所需的“最大驻留集大小”为5GB(无论使用jq 1.5还是1.6)。还要注意,jq可以在python之后使用pip install jq

You can do this on the command line:

python3 -m json.tool some.json

(as already mentioned in the commentaries to the question, thanks to @Kai Petzke for the python3 suggestion).

Actually python is not my favourite tool as far as json processing on the command line is concerned. For simple pretty printing is ok, but if you want to manipulate the json it can become overcomplicated. You’d soon need to write a separate script-file, you could end up with maps whose keys are u”some-key” (python unicode), which makes selecting fields more difficult and doesn’t really go in the direction of pretty-printing.

You can also use jq:

jq . some.json

and you get colors as a bonus (and way easier extendability).

Addendum: There is some confusion in the comments about using jq to process large JSON files on the one hand, and having a very large jq program on the other. For pretty-printing a file consisting of a single large JSON entity, the practical limitation is RAM. For pretty-printing a 2GB file consisting of a single array of real-world data, the “maximum resident set size” required for pretty-printing was 5GB (whether using jq 1.5 or 1.6). Note also that jq can be used from within python after pip install jq.


回答 2

您可以使用内置的modul pprint(https://docs.python.org/3.6/library/pprint.html)

如何读取带有json数据的文件并打印出来。

import json
import pprint

json_data = None
with open('filename.txt', 'r') as f:
    data = f.read()
    json_data = json.loads(data)

pprint.pprint(json_data)

You could use the built-in modul pprint (https://docs.python.org/3.6/library/pprint.html).

How you can read the file with json data and print it out.

import json
import pprint

json_data = None
with open('filename.txt', 'r') as f:
    data = f.read()
    json_data = json.loads(data)

pprint.pprint(json_data)

回答 3

Pygmentize + Python json.tool =带有语法突出显示的漂亮打印

Pygmentize是杀手级工具。看到这个。

我结合python json.tool与pygmentize

echo '{"foo": "bar"}' | python -m json.tool | pygmentize -l json

有关pygmentize安装说明,请参见上面的链接。

下图是一个演示:

Pygmentize + Python json.tool = Pretty Print with Syntax Highlighting

Pygmentize is a killer tool. See this.

I combine python json.tool with pygmentize

echo '{"foo": "bar"}' | python -m json.tool | pygmentize -l json

See the link above for pygmentize installation instruction.

A demo of this is in the image below:


回答 4

使用此功能,不出汗不必记住,如果你的JSON是一种strdict再次-这个漂亮的打印只要看看:

import json

def pp_json(json_thing, sort=True, indents=4):
    if type(json_thing) is str:
        print(json.dumps(json.loads(json_thing), sort_keys=sort, indent=indents))
    else:
        print(json.dumps(json_thing, sort_keys=sort, indent=indents))
    return None

pp_json(your_json_string_or_dict)

Use this function and don’t sweat having to remember if your JSON is a str or dict again – just look at the pretty print:

import json

def pp_json(json_thing, sort=True, indents=4):
    if type(json_thing) is str:
        print(json.dumps(json.loads(json_thing), sort_keys=sort, indent=indents))
    else:
        print(json.dumps(json_thing, sort_keys=sort, indent=indents))
    return None

pp_json(your_json_string_or_dict)

回答 5

我曾经写过一个prettyjson()函数来产生漂亮的输出。您可以从此仓库中获取实现。

此功能的主要功能是尝试将dict和list项目保持在一行中,直到maxlinelength达到确定的水平为止。这样会产生更少的JSON行,输出看起来更紧凑且更易于阅读。

您可以产生这种输出,例如:

{
  "grid": {"port": "COM5"},
  "policy": {
    "movingaverage": 5,
    "hysteresis": 5,
    "fan1": {
      "name": "CPU",
      "signal": "cpu",
      "mode": "auto",
      "speed": 100,
      "curve": [[0, 75], [50, 75], [75, 100]]
    }
}

UPD 19年12月:我将代码放入单独的存储库中,更正了一些错误,并进行了其他一些调整。

I once wrote a prettyjson() function to produce nice-looking output. You can grab the implementation from this repo.

The main feature of this function is it tries to keep dict and list items in one line until a certain maxlinelength is reached. This produces fewer lines of JSON, the output looks more compact and easier to read.

You can produce this kind of output for instance:

{
  "grid": {"port": "COM5"},
  "policy": {
    "movingaverage": 5,
    "hysteresis": 5,
    "fan1": {
      "name": "CPU",
      "signal": "cpu",
      "mode": "auto",
      "speed": 100,
      "curve": [[0, 75], [50, 75], [75, 100]]
    }
}

UPD Dec’19: I placed the code into a separate repo, corrected a few bugs and made a few other tweaks.


回答 6

为了能够从命令行进行漂亮的打印并能够控制缩进等,您可以设置类似于以下的别名:

alias jsonpp="python -c 'import sys, json; print json.dumps(json.load(sys.stdin), sort_keys=True, indent=2)'"

然后以下列方式之一使用别名:

cat myfile.json | jsonpp
jsonpp < myfile.json

To be able to pretty print from the command line and be able to have control over the indentation etc. you can set up an alias similar to this:

alias jsonpp="python -c 'import sys, json; print json.dumps(json.load(sys.stdin), sort_keys=True, indent=2)'"

And then use the alias in one of these ways:

cat myfile.json | jsonpp
jsonpp < myfile.json

回答 7

使用pprint:https ://docs.python.org/3.6/library/pprint.html

import pprint
pprint.pprint(json)

print() 相比 pprint.pprint()

print(json)
{'feed': {'title': 'W3Schools Home Page', 'title_detail': {'type': 'text/plain', 'language': None, 'base': '', 'value': 'W3Schools Home Page'}, 'links': [{'rel': 'alternate', 'type': 'text/html', 'href': 'https://www.w3schools.com'}], 'link': 'https://www.w3schools.com', 'subtitle': 'Free web building tutorials', 'subtitle_detail': {'type': 'text/html', 'language': None, 'base': '', 'value': 'Free web building tutorials'}}, 'entries': [], 'bozo': 0, 'encoding': 'utf-8', 'version': 'rss20', 'namespaces': {}}

pprint.pprint(json)
{'bozo': 0,
 'encoding': 'utf-8',
 'entries': [],
 'feed': {'link': 'https://www.w3schools.com',
          'links': [{'href': 'https://www.w3schools.com',
                     'rel': 'alternate',
                     'type': 'text/html'}],
          'subtitle': 'Free web building tutorials',
          'subtitle_detail': {'base': '',
                              'language': None,
                              'type': 'text/html',
                              'value': 'Free web building tutorials'},
          'title': 'W3Schools Home Page',
          'title_detail': {'base': '',
                           'language': None,
                           'type': 'text/plain',
                           'value': 'W3Schools Home Page'}},
 'namespaces': {},
 'version': 'rss20'}

Use pprint: https://docs.python.org/3.6/library/pprint.html

import pprint
pprint.pprint(json)

print() compared to pprint.pprint()

print(json)
{'feed': {'title': 'W3Schools Home Page', 'title_detail': {'type': 'text/plain', 'language': None, 'base': '', 'value': 'W3Schools Home Page'}, 'links': [{'rel': 'alternate', 'type': 'text/html', 'href': 'https://www.w3schools.com'}], 'link': 'https://www.w3schools.com', 'subtitle': 'Free web building tutorials', 'subtitle_detail': {'type': 'text/html', 'language': None, 'base': '', 'value': 'Free web building tutorials'}}, 'entries': [], 'bozo': 0, 'encoding': 'utf-8', 'version': 'rss20', 'namespaces': {}}

pprint.pprint(json)
{'bozo': 0,
 'encoding': 'utf-8',
 'entries': [],
 'feed': {'link': 'https://www.w3schools.com',
          'links': [{'href': 'https://www.w3schools.com',
                     'rel': 'alternate',
                     'type': 'text/html'}],
          'subtitle': 'Free web building tutorials',
          'subtitle_detail': {'base': '',
                              'language': None,
                              'type': 'text/html',
                              'value': 'Free web building tutorials'},
          'title': 'W3Schools Home Page',
          'title_detail': {'base': '',
                           'language': None,
                           'type': 'text/plain',
                           'value': 'W3Schools Home Page'}},
 'namespaces': {},
 'version': 'rss20'}

回答 8

这是一个简单的示例,可以在Python中以一种不错的方式将JSON打印到控制台,而无需将JSON作为本地文件存储在您的计算机上:

import pprint
import json 
from urllib.request import urlopen # (Only used to get this example)

# Getting a JSON example for this example 
r = urlopen("https://mdn.github.io/fetch-examples/fetch-json/products.json")
text = r.read() 

# To print it
pprint.pprint(json.loads(text))

Here’s a simple example of pretty printing JSON to the console in a nice way in Python, without requiring the JSON to be on your computer as a local file:

import pprint
import json 
from urllib.request import urlopen # (Only used to get this example)

# Getting a JSON example for this example 
r = urlopen("https://mdn.github.io/fetch-examples/fetch-json/products.json")
text = r.read() 

# To print it
pprint.pprint(json.loads(text))

回答 9

def saveJson(date,fileToSave):
    with open(fileToSave, 'w+') as fileToSave:
        json.dump(date, fileToSave, ensure_ascii=True, indent=4, sort_keys=True)

它可以显示或保存到文件中。

def saveJson(date,fileToSave):
    with open(fileToSave, 'w+') as fileToSave:
        json.dump(date, fileToSave, ensure_ascii=True, indent=4, sort_keys=True)

It works to display or save it to a file.


回答 10

我认为最好先解析json,以避免出现错误:

def format_response(response):
    try:
        parsed = json.loads(response.text)
    except JSONDecodeError:
        return response.text
    return json.dumps(parsed, ensure_ascii=True, indent=4)

I think that’s better to parse the json before, to avoid errors:

def format_response(response):
    try:
        parsed = json.loads(response.text)
    except JSONDecodeError:
        return response.text
    return json.dumps(parsed, ensure_ascii=True, indent=4)

回答 11

您可以尝试pprintjson


安装

$ pip3 install pprintjson

用法

使用pprintjson CLI从文件漂亮地打印JSON。

$ pprintjson "./path/to/file.json"

使用pprintjson CLI从标准输入漂亮地打印JSON。

$ echo '{ "a": 1, "b": "string", "c": true }' | pprintjson

使用pprintjson CLI从字符串漂亮地打印JSON。

$ pprintjson -c '{ "a": 1, "b": "string", "c": true }'

从缩进为1的字符串漂亮地打印JSON。

$ pprintjson -c '{ "a": 1, "b": "string", "c": true }' -i 1

从字符串漂亮地打印JSON并将输出保存到文件output.json。

$ pprintjson -c '{ "a": 1, "b": "string", "c": true }' -o ./output.json

输出量

You could try pprintjson.


Installation

$ pip3 install pprintjson

Usage

Pretty print JSON from a file using the pprintjson CLI.

$ pprintjson "./path/to/file.json"

Pretty print JSON from a stdin using the pprintjson CLI.

$ echo '{ "a": 1, "b": "string", "c": true }' | pprintjson

Pretty print JSON from a string using the pprintjson CLI.

$ pprintjson -c '{ "a": 1, "b": "string", "c": true }'

Pretty print JSON from a string with an indent of 1.

$ pprintjson -c '{ "a": 1, "b": "string", "c": true }' -i 1

Pretty print JSON from a string and save output to a file output.json.

$ pprintjson -c '{ "a": 1, "b": "string", "c": true }' -o ./output.json

Output


回答 12

它远非完美,但可以做到。

data = data.replace(',"',',\n"')

您可以对其进行改进,添加缩进等,但是如果您只想能够阅读更简洁的json,则可以采用这种方法。

It’s far from perfect, but it does the job.

data = data.replace(',"',',\n"')

you can improve it, add indenting and so on, but if you just want to be able to read a cleaner json, this is the way to go.


Visidata 一种用于发现和整理数据的终端电子表格工具

一种用于浏览和排列表格数据的终端界面

VisiData支持TSV、CSV、SQLite、json、xlsx(Excel)、hdf5和many other formats

平台要求

  • Linux、OS/X或Windows(带WSL)
  • Python 3.6+
  • 某些格式和源需要其他Python模块

安装

要从PyPI安装最新版本,请执行以下操作:

 

pip3 install visidata

安装尖端设备的步骤develop分公司(无明示或默示的保修):

 

pip3 install git+https://github.com/saulpw/visidata.git@develop

看见visidata.org/install有关所有可用平台和包管理器的详细说明,请参阅

用法

 

$ vd <input>
$ <command> | vd

按下Ctrl+Q随时戒烟

还可以使用数百个其他命令和选项;请参阅文档

文档

帮助和支持

如果您有关于VisiData的问题、问题或建议,请create an issue on Github或在#visidata上与我们聊天irc.libera.chat

如果您经常使用VisiData,请support me on Patreon好了!

许可证

中的代码。stable此存储库的分支,包括主vd应用程序、加载器和插件可在GPLv3下使用和重新分发

学分

VisiData由Saul Pwanson构思和开发<vd@saul.pw>

安雅·凯法拉(Anja Kefala)<anja.kefala@gmail.com>维护所有平台的文档和软件包

非常感谢无数其他人contributors,以及那些提供反馈的优秀用户,感谢他们帮助VisiData成为令人敬畏的工具

Fastapi-FastAPI框架,高性能,易学,编码速度快,可投入生产

FastAPI框架,高性能,易学,编码速度快,可投入生产


文档https://fastapi.tiangolo.com

源代码https://github.com/tiangolo/fastapi


FastAPI是一种现代、快速(高性能)的Web框架,用于使用Python 3.6+基于标准Python类型提示构建API

主要功能包括:

  • 快地:非常高的性能,可与节点JS(多亏了斯塔莱特和皮丹蒂克)One of the fastest Python frameworks available
  • 快速编码:提高功能开发速度约200%至300%。*
  • 更少的错误:减少约40%的人为(开发人员)引起的错误。*
  • 直观:强大的编辑支持。无处不在的完成度。调试时间更短
  • 简单易懂:设计成易于使用和学习。减少阅读文档的时间
  • 短的:最大限度地减少代码重复。来自每个参数声明的多个功能。更少的错误
  • 健壮:获取可投入生产的代码。使用自动交互文档
  • 基于标准的:基于(并完全兼容)API开放标准:OpenAPI(以前称为Swagger)和JSON Schema

*基于对内部开发团队、构建生产应用程序的测试进行估计

意见

[.]我在用FastAPI这几天有一吨多。[.]实际上我正计划把它用在我所有团队的微软的ML服务他们中的一些人正在融入核心窗口产品和一些办公室产品

卡比尔汗-微软(ref)

我们采用了FastAPI库以派生睡觉可以查询获取的服务器预测[路德维希]

皮耶罗·莫利诺,雅罗斯拉夫·杜丁和赛苏曼斯·米利亚拉-优步(Uber)(ref)

Netflix我很高兴地宣布我们的危机管理编排框架:派单好了![使用以下组件构建FastAPI]

凯文·格利森,马克·维拉诺瓦,福里斯特·蒙森-Netflix(ref)

我欣喜若狂FastAPI太好玩了!

布莱恩·奥肯-Python Bytes播客主持人(ref)

老实说,你建造的东西看起来非常坚固和精美。在很多方面,这是我想要的拥抱一下是-看到有人建造这样的建筑真的很鼓舞人心

蒂莫西·克罗斯利-Hug创建者(ref)

如果你想学一门现代框架要构建睡觉API,请查看FastAPI[.]它快速、易用、易学。

我们已经切换到FastAPI为了我们的API接口[.]我想你会喜欢的。

Ines Montani-Matthew Honnibal-Explosion AI创始人-spaCy创作者(ref)(ref)

要求

Python 3.6+

FastAPI站在巨人的肩膀上:

安装

$ pip install fastapi

---> 100%

您还需要一台ASGI服务器用于生产,例如UvicornHypercorn

$ pip install uvicorn[standard]

---> 100%

示例

创建它

  • 创建文件main.py使用:
from typing import Optional

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def read_root():
    return {"Hello": "World"}


@app.get("/items/{item_id}")
def read_item(item_id: int, q: Optional[str] = None):
    return {"item_id": item_id, "q": q}
或使用async def

如果您的代码使用async/await,使用async def

from typing import Optional

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def read_root():
    return {"Hello": "World"}


@app.get("/items/{item_id}")
async def read_item(item_id: int, q: Optional[str] = None):
    return {"item_id": item_id, "q": q}

注意事项

如果您不知道,请查看“赶时间?”部分关于async and await in the docs

运行它

使用以下命令运行服务器:

$ uvicorn main:app --reload

INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [28720]
INFO:     Started server process [28722]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
关于命令uvicorn main:app --reload

该命令uvicorn main:app指的是:

  • main:文件main.py(Python“模块”)
  • app:在中创建的对象main.py用这条线app = FastAPI()
  • --reload:使服务器在代码更改后重新启动。这样做只是为了发展。

检查一下

在以下位置打开您的浏览器http://127.0.0.1:8000/items/5?q=somequery

您将看到JSON响应为:

{"item_id": 5, "q": "somequery"}

您已经创建了一个API,该API:

  • 中接收HTTP请求。路径//items/{item_id}
  • 两者都有路径拿走GET运营(也称为HTTP方法:)
  • 这个路径/items/{item_id}有一个路径参数item_id这应该是一个int
  • 这个路径/items/{item_id}有一个可选的str查询参数q

交互式API文档

现在转到http://127.0.0.1:8000/docs

您将看到自动交互API文档(由提供Swagger UI):

替代API文档

现在,请转到http://127.0.0.1:8000/redoc

您将看到替代自动文档(由提供ReDoc):

示例升级

现在修改该文件main.py接收来自PUT请求

使用标准Python类型声明Body,这要归功于Pydatics

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    price: float
    is_offer: Optional[bool] = None


@app.get("/")
def read_root():
    return {"Hello": "World"}


@app.get("/items/{item_id}")
def read_item(item_id: int, q: Optional[str] = None):
    return {"item_id": item_id, "q": q}


@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
    return {"item_name": item.name, "item_id": item_id}

服务器应自动重新加载(因为您添加了--reload发送到uvicorn上述命令)

Interactive API文档升级

现在转到http://127.0.0.1:8000/docs

  • 交互API文档将自动更新,包括新的Body:

  • 点击[试用]按钮,即可填写参数,直接与接口交互:

  • 然后点击“执行”按钮,用户界面将与您的API进行通信,发送参数,得到结果并显示在屏幕上:

备用API文档升级

现在,请转到http://127.0.0.1:8000/redoc

  • 替代文档还将反映新的查询参数和正文:

概述

总而言之,您声明一次作为函数参数的参数类型、正文等

您可以使用标准的现代Python类型来实现这一点

您不必学习新语法、特定库的方法或类等

只是标准的Python 3.6+

例如,对于int

item_id: int

或者对于更复杂的Item型号:

item: Item

有了这一份声明,你就会得到:

  • 编辑器支持,包括:
    • 完成
    • 类型检查
  • 数据验证:
    • 数据无效时自动清除错误
    • 即使是针对深度嵌套的JSON对象的验证也是如此
  • 输入数据的转换:从网络到Python数据和类型的转换。阅读自:
    • JSON
    • 路径参数
    • 查询参数
    • 曲奇饼
    • 标题
    • 表格
    • 文件
  • 输出数据转换:从Python数据和类型转换为网络数据(如JSON):
    • 转换Python类型(strintfloatboollist等)
    • datetime对象
    • UUID对象
    • 数据库模型
    • 还有更多
  • 自动交互式API文档,包括2个替代用户界面:
    • 大摇大摆的UI
    • 复单

回到前面的代码示例,FastAPI将:

  • 验证是否存在item_id在用于的路径中GETPUT请求
  • 验证item_id类型为intGETPUT请求
    • 如果不是,客户端将看到一个有用的、明确的错误
  • 检查是否存在名为的可选查询参数q(如图所示http://127.0.0.1:8000/items/foo?q=somequery)用于GET请求
    • 作为q参数是用= None,它是可选的
    • 如果没有None这将是必需的(就像在具有以下情况的情况下的身体一样PUT)
  • PUT请求/items/{item_id},将正文读作JSON:
    • 检查它是否具有必需的属性name这应该是一个str
    • 检查它是否具有必需的属性price那一定是一个float
    • 检查它是否具有可选属性is_offer,那应该是一个bool,如果存在
    • 所有这些也适用于深度嵌套的JSON对象
  • 自动从JSON转换为JSON或自动转换为JSON
  • 使用OpenAPI记录可由以下人员使用的所有内容:
    • 交互式文档系统
    • 自动客户端代码生成系统,适用于多种语言
  • 直接提供2个交互式文档web界面

我们只是触及了皮毛,但您已经对它的工作原理有了大致的了解

尝试使用以下命令更改行:

    return {"item_name": item.name, "item_id": item_id}

出发地:

        ... "item_name": item.name ...

收件人:

        ... "item_price": item.price ...

并查看您的编辑器将如何自动完成属性并了解其类型:

有关包含更多功能的更完整示例,请参阅Tutorial – User Guide

剧透警报:教程-用户指南包括:

  • 的声明参数从其他不同的地方,如:标题曲奇饼表单域文件
  • 如何设置验证约束作为maximum_lengthregex
  • 一款功能非常强大且易于使用的依赖项注入系统
  • 安全性和身份验证,包括支持OAuth2使用JWT代币HTTP Basic身份验证
  • 更高级(但同样简单)的声明技术深度嵌套的JSON模型(多亏了皮丹蒂克)
  • 许多额外功能(感谢Starlette),如:
    • WebSockets
    • 图形QL
    • 极其简单的测试,基于requestspytest
    • CORS
    • Cookie会话
    • 还有更多

性能

独立TechEmpower基准显示FastAPI在Uvicorn AS下运行的应用程序one of the fastest Python frameworks available,仅低于Starlette和Uvicorn本身(由FastAPI内部使用)。(*)

要了解更多信息,请参阅小节Benchmarks

可选依赖项

由Pydtic使用:

由Starlette使用:

  • requests-如果要使用TestClient
  • aiofiles-如果要使用,则为必填项FileResponseStaticFiles
  • jinja2-如果要使用默认模板配置,则为必填项
  • python-multipart-如果您想支持表单“解析”,则为必填项,带有request.form()
  • itsdangerous-需要用于SessionMiddleware支持
  • pyyaml-Starlette的必填项SchemaGenerator支持(FastAPI可能不需要)
  • graphene-需要用于GraphQLApp支持
  • ujson-如果要使用,则为必填项UJSONResponse

由FastAPI/Starlette使用:

  • uvicorn-对于加载和服务您的应用程序的服务器
  • orjson-如果要使用,则为必填项ORJSONResponse

您可以使用以下命令安装所有这些组件pip install fastapi[all]

许可证

这个项目是根据麻省理工学院的许可条款授权的。