296

我正在使用Python 2ASCII 编码的文本文件中解析 JSON。

使用json或 加载这些文件时simplejson,我的所有字符串值都将转换为 Unicode 对象而不是字符串对象。问题是,我必须将数据与一些只接受字符串对象的库一起使用。我不能更改库也不能更新它们。

是否可以获取字符串对象而不是 Unicode 对象?

例子

>>> import json
>>> original_list = ['a', 'b']
>>> json_list = json.dumps(original_list)
>>> json_list
'["a", "b"]'
>>> new_list = json.loads(json_list)
>>> new_list
[u'a', u'b']  # I want these to be of type `str`, not `unicode`

更新

这个问题是很久以前问的,当时我被Python 2困住了。今天一个简单而干净的解决方案是使用 Python 的最新版本——即Python 3及更高版本。

4

21 回答 21

187

虽然这里有一些很好的答案,但我最终使用PyYAML来解析我的 JSON 文件,因为它将键和值作为str类型字符串而不是unicode类型提供。因为 JSON 是 YAML 的一个子集,所以它工作得很好:

>>> import json
>>> import yaml
>>> list_org = ['a', 'b']
>>> list_dump = json.dumps(list_org)
>>> list_dump
'["a", "b"]'
>>> json.loads(list_dump)
[u'a', u'b']
>>> yaml.safe_load(list_dump)
['a', 'b']

笔记

不过有几点需要注意:

  • 我得到字符串对象,因为我所有的条目都是ASCII 编码的。如果我使用 unicode 编码的条目,我会将它们作为unicode 对象取回——没有转换!

  • 你应该(可能总是)使用 PyYAML 的safe_load函数;如果您使用它来加载 JSON 文件,那么无论如何您都不需要该load功能的“额外功能”。

  • 如果您想要一个对 1​​.2 版本的规范有更多支持的 YAML 解析器(并且可以正确解析非常低的数字),请尝试使用 Ruamel YAML:这就是我在测试中所需要的pip install ruamel.yamlimport ruamel.yaml as yaml

转换

如前所述,没有转换!如果你不能确定只处理 ASCII 值(而且你不能确定大部分时间),最好使用转换函数

我现在用过几次Mark Amery的,效果很好,而且很容易使用。您也可以使用类似的函数作为object_hook替代,因为它可能会提高大文件的性能。请参阅Mirec Miskuf的稍微复杂的答案。

于 2013-05-04T10:37:24.507 回答
145

没有内置选项可以使 json 模块函数返回字节字符串而不是 unicode 字符串。但是,这个简短的递归函数会将任何解码的 JSON 对象从使用 unicode 字符串转换为 UTF-8 编码的字节字符串:

def byteify(input):
    if isinstance(input, dict):
        return {byteify(key): byteify(value)
                for key, value in input.iteritems()}
    elif isinstance(input, list):
        return [byteify(element) for element in input]
    elif isinstance(input, unicode):
        return input.encode('utf-8')
    else:
        return input

只需在您从json.loadorjson.loads调用获得的输出上调用它。

几点注意事项:

  • 要支持 Python 2.6 或更早版本,请替换return {byteify(key): byteify(value) for key, value in input.iteritems()}return dict([(byteify(key), byteify(value)) for key, value in input.iteritems()]),因为直到 Python 2.7 才支持字典推导。
  • 由于此答案在整个解码对象中递归,因此它具有一些不良的性能特征,可以通过非常小心地使用object_hookorobject_pairs_hook参数来避免这些特征。到目前为止, Mirec Miskuf 的答案是唯一能够正确解决此问题的答案,尽管因此它比我的方法要复杂得多。
于 2012-10-28T00:27:17.133 回答
115

一个解决方案object_hook

[编辑]:针对 Python 2.73.x 兼容性进行了更新。

import json

def json_load_byteified(file_handle):
    return _byteify(
        json.load(file_handle, object_hook=_byteify),
        ignore_dicts=True
    )

def json_loads_byteified(json_text):
    return _byteify(
        json.loads(json_text, object_hook=_byteify),
        ignore_dicts=True
    )

def _byteify(data, ignore_dicts = False):
    if isinstance(data, str):
        return data

    # if this is a list of values, return list of byteified values
    if isinstance(data, list):
        return [ _byteify(item, ignore_dicts=True) for item in data ]
    # if this is a dictionary, return dictionary of byteified keys and values
    # but only if we haven't already byteified it
    if isinstance(data, dict) and not ignore_dicts:
        return {
            _byteify(key, ignore_dicts=True): _byteify(value, ignore_dicts=True)
            for key, value in data.items() # changed to .items() for python 2.7/3
        }

    # python 3 compatible duck-typing
    # if this is a unicode string, return its string representation
    if str(type(data)) == "<type 'unicode'>":
        return data.encode('utf-8')

    # if it's anything else, return it in its original form
    return data

示例用法:

>>> json_loads_byteified('{"Hello": "World"}')
{'Hello': 'World'}
>>> json_loads_byteified('"I am a top-level string"')
'I am a top-level string'
>>> json_loads_byteified('7')
7
>>> json_loads_byteified('["I am inside a list"]')
['I am inside a list']
>>> json_loads_byteified('[[[[[[[["I am inside a big nest of lists"]]]]]]]]')
[[[[[[[['I am inside a big nest of lists']]]]]]]]
>>> json_loads_byteified('{"foo": "bar", "things": [7, {"qux": "baz", "moo": {"cow": ["milk"]}}]}')
{'things': [7, {'qux': 'baz', 'moo': {'cow': ['milk']}}], 'foo': 'bar'}
>>> json_load_byteified(open('somefile.json'))
{'more json': 'from a file'}

这是如何工作的,我为什么要使用它?

Mark Amery 的功能比这些更短更清晰,那么它们有什么意义呢?为什么要使用它们?

纯粹为了性能。Mark 的答案首先使用 unicode 字符串完全解码 JSON 文本,然后递归整个解码值以将所有字符串转换为字节字符串。这有几个不良影响:

  • 整个解码结构的副本在内存中创建
  • 如果您的 JSON 对象嵌套非常深(500 层或更多),那么您将达到 Python 的最大递归深度

这个答案通过使用和的object_hook参数来缓解这两个性能问题。从文档json.loadjson.loads

object_hook是一个可选函数,将使用解码的任何对象字面量 (a dict) 的结果调用。将使用 object_hook 的返回值而不是dict. 此功能可用于实现自定义解码器

由于嵌套在其他字典深处的许多级别的字典object_hook 在解码时会被传递给它们,因此我们可以在那时将它们内部的任何字符串或列表字节化,并避免以后需要深度递归。

马克的答案不适合object_hook作为它的代表使用,因为它递归到嵌套字典中。ignore_dicts我们在这个答案中使用参数 to 来防止这种递归_byteify,它一直被传递给它,除非object_hook它传递给一个新dict的字节化。该ignore_dicts标志告诉_byteify忽略dicts,因为它们已经被字节化。

最后,我们对返回的结果执行json_load_byteifiedjson_loads_byteified调用_byteify(with ignore_dicts=True)json.load或处理被解码的 JSON 文本在顶层json.loads没有 a的情况。dict

于 2015-11-06T16:18:59.050 回答
75

您可以使用object_hook参数 forjson.loads传入转换器。您不必事后进行转换。该json模块将始终object_hook只传递 dicts,它会递归地传递嵌套的 dicts,因此您不必自己递归到嵌套的 dicts。我认为我不会将 unicode 字符串转换为 Wells 节目中的数字。如果它是一个 unicode 字符串,它在 JSON 文件中被引用为一个字符串,所以它应该是一个字符串(或者文件是坏的)。

str(val)另外,我会尽量避免在unicode对象上做类似的事情。您应该使用value.encode(encoding)有效的编码,具体取决于您的外部库所期望的。

因此,例如:

def _decode_list(data):
    rv = []
    for item in data:
        if isinstance(item, unicode):
            item = item.encode('utf-8')
        elif isinstance(item, list):
            item = _decode_list(item)
        elif isinstance(item, dict):
            item = _decode_dict(item)
        rv.append(item)
    return rv

def _decode_dict(data):
    rv = {}
    for key, value in data.iteritems():
        if isinstance(key, unicode):
            key = key.encode('utf-8')
        if isinstance(value, unicode):
            value = value.encode('utf-8')
        elif isinstance(value, list):
            value = _decode_list(value)
        elif isinstance(value, dict):
            value = _decode_dict(value)
        rv[key] = value
    return rv

obj = json.loads(s, object_hook=_decode_dict)
于 2011-07-09T08:25:41.640 回答
39

那是因为 json 在字符串对象和 unicode 对象之间没有区别。它们都是javascript中的字符串。

我认为JSON 返回 unicode 对象是正确的。事实上,我不会接受任何更少的内容,因为 javascript 字符串实际上是unicode对象(即 JSON (javascript) 字符串可以存储任何类型unicode的 unicode 字符),因此在从 JSON 转换字符串时创建对象是有意义的。纯字符串不适合,因为库必须猜测您想要的编码。

最好在unicode任何地方使用字符串对象。因此,您最好的选择是更新您的库,以便它们可以处理 unicode 对象。

但是,如果您真的想要字节串,只需将结果编码为您选择的编码:

>>> nl = json.loads(js)
>>> nl
[u'a', u'b']
>>> nl = [s.encode('utf-8') for s in nl]
>>> nl
['a', 'b']
于 2009-06-05T16:44:45.000 回答
16

有一个简单的解决方法。

TL;DR - 使用ast.literal_eval()而不是json.loads(). 两者astjson在标准库中。

虽然不是一个“完美”的答案,但如果您的计划是完全忽略 Unicode,它会走得很远。在 Python 2.7 中

import json, ast
d = { 'field' : 'value' }
print "JSON Fail: ", json.loads(json.dumps(d))
print "AST Win:", ast.literal_eval(json.dumps(d))

给出:

JSON Fail:  {u'field': u'value'}
AST Win: {'field': 'value'}

当某些对象实际上是 Unicode 字符串时,这会变得更加棘手。完整的答案很快就会变得毛茸茸。

于 2013-11-07T01:01:43.970 回答
13

Mike Brennan 的回答很接近,但没有理由重新遍历整个结构。如果您使用object_hook_pairs(Python 2.7+) 参数:

object_pairs_hook是一个可选函数,将调用使用有序对列表解码的任何对象文字的结果。将使用的返回值object_pairs_hook代替dict. 此功能可用于实现依赖于键值对解码顺序的自定义解码器(例如,collections.OrderedDict将记住插入的顺序)。如果object_hook还定义了,object_pairs_hook则优先。

有了它,您可以获得每个 JSON 对象,因此您无需递归即可进行解码:

def deunicodify_hook(pairs):
    new_pairs = []
    for key, value in pairs:
        if isinstance(value, unicode):
            value = value.encode('utf-8')
        if isinstance(key, unicode):
            key = key.encode('utf-8')
        new_pairs.append((key, value))
    return dict(new_pairs)

In [52]: open('test.json').read()
Out[52]: '{"1": "hello", "abc": [1, 2, 3], "def": {"hi": "mom"}, "boo": [1, "hi", "moo", {"5": "some"}]}'                                        

In [53]: json.load(open('test.json'))
Out[53]: 
{u'1': u'hello',
 u'abc': [1, 2, 3],
 u'boo': [1, u'hi', u'moo', {u'5': u'some'}],
 u'def': {u'hi': u'mom'}}

In [54]: json.load(open('test.json'), object_pairs_hook=deunicodify_hook)
Out[54]: 
{'1': 'hello',
 'abc': [1, 2, 3],
 'boo': [1, 'hi', 'moo', {'5': 'some'}],
 'def': {'hi': 'mom'}}

请注意,我不必递归调用钩子,因为当您使用object_pairs_hook. 您确实必须关心列表,但正如您所看到的,列表中的对象将被正确转换,您不必递归即可实现。

编辑:一位同事指出 Python2.6 没有object_hook_pairs. 通过进行非常小的更改,您仍然可以在 Python2.6 中使用它。在上面的钩子中,更改:

for key, value in pairs:

for key, value in pairs.iteritems():

然后使用object_hook代替object_pairs_hook

In [66]: json.load(open('test.json'), object_hook=deunicodify_hook)
Out[66]: 
{'1': 'hello',
 'abc': [1, 2, 3],
 'boo': [1, 'hi', 'moo', {'5': 'some'}],
 'def': {'hi': 'mom'}}

使用object_pairs_hook结果是为 JSON 对象中的每个对象实例化一个更少的字典,如果您正在解析一个巨大的文档,这可能是值得的。

于 2016-01-14T17:34:06.660 回答
9

恐怕没有办法在 simplejson 库中自动实现这一点。

simplejson 中的扫描仪和解码器旨在生成 unicode 文本。为此,该库使用一个函数调用c_scanstring(如果它可用,为了速度),或者py_scanstring如果 C 版本不可用。scanstring几乎所有 simplejson 用于解码可能包含文本的结构的例程都会多次调用该函数。您必须对scanstringsimplejson.decoder 中的值进行monkeypatch 或子类化JSONDecoder,并提供您自己的几乎所有可能包含文本的内容的完整实现。

然而,simplejson 输出 unicode 的原因是json 规范特别提到“字符串是零个或多个 Unicode 字符的集合”......对 unicode 的支持被假定为格式本身的一部分。Simplejson 的scanstring实现甚至可以扫描和解释 unicode 转义(甚至对格式错误的多字节字符集表示进行错误检查),因此它可以可靠地将值返回给您的唯一方法是作为 unicode。

如果您有一个需要str.外观,您可以在其中更细化地处理输入参数。如果您的数据结构确实是深度嵌套的,则第二种方法可能比第一种更易于管理。

于 2009-06-05T18:10:03.710 回答
4

正如 Mark (Amery) 正确指出的那样:仅当您只有 ASCII 时,在 json 转储上使用PyYaml的反序列化器才有效。至少开箱即用。

关于 PyYaml 方法的两个快速评论:

  1. 切勿对字段中的数据使用 yaml.load。它是 yaml 的一个功能(!),可以执行隐藏在结构中的任意代码。

  2. 可以通过以下方式使其也适用于非 ASCII:

    def to_utf8(loader, node):
        return loader.construct_scalar(node).encode('utf-8')
    yaml.add_constructor(u'tag:yaml.org,2002:str', to_utf8)
    

但在性能方面,它与 Mark Amery 的回答无法相提并论:

将一些深度嵌套的示例字典扔到这两种方法上,我得到了这个(dt[j] = time delta of json.loads(json.dumps(m))):

     dt[yaml.safe_load(json.dumps(m))] =~ 100 * dt[j]
     dt[byteify recursion(Mark Amery)] =~   5 * dt[j]

因此,反序列化包括完全遍历树编码,完全在 json 基于 C 的实现的数量级内。我发现这非常快,并且比深度嵌套结构中的 yaml 负载更健壮。并且查看 yaml.load 更不容易发生安全错误。

=> 虽然我很欣赏指向仅基于 C 的转换器的指针,但byteify 函数应该是默认答案。

如果您的 json 结构来自包含用户输入的字段,则尤其如此。因为那时您可能无论如何都需要遍历您的结构 - 独立于您想要的内部数据结构(“unicode 三明治”或仅字节字符串)。

为什么?

Unicode规范化。对于不知情的人:服用止痛药并阅读内容。

因此,使用 byteify 递归,您可以用一块石头杀死两只鸟:

  1. 从嵌套的 json 转储中获取您的字节串
  2. 使用户输入值标准化,以便您在存储中找到内容。

在我的测试中,结果证明用 unicodedata.normalize('NFC', input).encode('utf-8') 替换 input.encode('utf-8') 甚至比不带 NFC 更快 - 但是这在很大程度上取决于我猜的样本数据。

于 2015-04-14T17:36:25.790 回答
3

问题在于,simplejson它们json是两个不同的模块,至少在它们处理 unicode 的方式上是这样。你有jsonpy 2.6+,这给你 unicode 值,而simplejson返回字符串对象。只需在您的环境中尝试 easy_install-ing simplejson 看看是否可行。它对我有用。

于 2010-10-19T19:48:34.857 回答
2

只需使用 pickle 而不是 json 进行转储和加载,如下所示:

    import json
    import pickle

    d = { 'field1': 'value1', 'field2': 2, }

    json.dump(d,open("testjson.txt","w"))

    print json.load(open("testjson.txt","r"))

    pickle.dump(d,open("testpickle.txt","w"))

    print pickle.load(open("testpickle.txt","r"))

它产生的输出是(正确处理字符串和整数):

    {u'field2': 2, u'field1': u'value1'}
    {'field2': 2, 'field1': 'value1'}
于 2014-04-27T20:15:01.860 回答
1

所以,我遇到了同样的问题。猜猜谷歌的第一个结果是什么。

因为我需要将所有数据传递给 PyGTK,所以 unicode 字符串对我也不是很有用。所以我有另一种递归转换方法。实际上,类型安全的 JSON 转换也需要它 - json.dump() 可以处理任何非文字,如 Python 对象。虽然不转换字典索引。

# removes any objects, turns unicode back into str
def filter_data(obj):
        if type(obj) in (int, float, str, bool):
                return obj
        elif type(obj) == unicode:
                return str(obj)
        elif type(obj) in (list, tuple, set):
                obj = list(obj)
                for i,v in enumerate(obj):
                        obj[i] = filter_data(v)
        elif type(obj) == dict:
                for i,v in obj.iteritems():
                        obj[i] = filter_data(v)
        else:
                print "invalid object in data, converting to string"
                obj = str(obj) 
        return obj
于 2010-07-05T18:22:51.620 回答
1

我有一个 JSON 字典作为字符串。键和值是 unicode 对象,如下例所示:

myStringDict = "{u'key':u'value'}"

我可以byteify通过将字符串转换为dict对象来使用上面建议的函数ast.literal_eval(myStringDict)

于 2015-01-30T10:12:14.647 回答
1

使用钩子支持 Python2&3(来自https://stackoverflow.com/a/33571117/558397

import requests
import six
from six import iteritems

requests.packages.urllib3.disable_warnings()  # @UndefinedVariable
r = requests.get("http://echo.jsontest.com/key/value/one/two/three", verify=False)

def _byteify(data):
    # if this is a unicode string, return its string representation
    if isinstance(data, six.string_types):
        return str(data.encode('utf-8').decode())

    # if this is a list of values, return list of byteified values
    if isinstance(data, list):
        return [ _byteify(item) for item in data ]

    # if this is a dictionary, return dictionary of byteified keys and values
    # but only if we haven't already byteified it
    if isinstance(data, dict):
        return {
            _byteify(key): _byteify(value) for key, value in iteritems(data)
        }
    # if it's anything else, return it in its original form
    return data

w = r.json(object_hook=_byteify)
print(w)

回报:

 {'three': '', 'key': 'value', 'one': 'two'}
于 2017-08-21T20:16:47.373 回答
0

这对游戏来说已经很晚了,但我构建了这个递归施法者。它适用于我的需求,我认为它相对完整。它可能会帮助你。

def _parseJSON(self, obj):
    newobj = {}

    for key, value in obj.iteritems():
        key = str(key)

        if isinstance(value, dict):
            newobj[key] = self._parseJSON(value)
        elif isinstance(value, list):
            if key not in newobj:
                newobj[key] = []
                for i in value:
                    newobj[key].append(self._parseJSON(i))
        elif isinstance(value, unicode):
            val = str(value)
            if val.isdigit():
                val = int(val)
            else:
                try:
                    val = float(val)
                except ValueError:
                    val = str(val)
            newobj[key] = val

    return newobj

只需像这样传递一个 JSON 对象:

obj = json.loads(content, parse_float=float, parse_int=int)
obj = _parseJSON(obj)

我将它作为类的私有成员,但您可以根据需要重新调整该方法的用途。

于 2009-10-29T03:53:43.340 回答
0

我重写了 Wells 的 _parse_json() 来处理 json 对象本身是一个数组的情况(我的用例)。

def _parseJSON(self, obj):
    if isinstance(obj, dict):
        newobj = {}
        for key, value in obj.iteritems():
            key = str(key)
            newobj[key] = self._parseJSON(value)
    elif isinstance(obj, list):
        newobj = []
        for value in obj:
            newobj.append(self._parseJSON(value))
    elif isinstance(obj, unicode):
        newobj = str(obj)
    else:
        newobj = obj
    return newobj
于 2013-06-07T05:12:22.313 回答
0

这是一个用 C 编写的递归编码器: https ://github.com/axiros/nested_encode

与 json.loads 相比,“平均”结构的性能开销约为 10%。

python speed.py                                                                                            
  json loads            [0.16sec]: {u'a': [{u'b': [[1, 2, [u'\xd6ster..
  json loads + encoding [0.18sec]: {'a': [{'b': [[1, 2, ['\xc3\x96ster.
  time overhead in percent: 9%

使用这个测试结构:

import json, nested_encode, time

s = """
{
  "firstName": "Jos\\u0301",
  "lastName": "Smith",
  "isAlive": true,
  "age": 25,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "\\u00d6sterreich",
    "state": "NY",
    "postalCode": "10021-3100"
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    }
  ],
  "children": [],
  "spouse": null,
  "a": [{"b": [[1, 2, ["\\u00d6sterreich"]]]}]
}
"""


t1 = time.time()
for i in xrange(10000):
    u = json.loads(s)
dt_json = time.time() - t1

t1 = time.time()
for i in xrange(10000):
    b = nested_encode.encode_nested(json.loads(s))
dt_json_enc = time.time() - t1

print "json loads            [%.2fsec]: %s..." % (dt_json, str(u)[:20])
print "json loads + encoding [%.2fsec]: %s..." % (dt_json_enc, str(b)[:20])

print "time overhead in percent: %i%%"  % (100 * (dt_json_enc - dt_json)/dt_json)
于 2015-05-04T12:44:46.757 回答
0

使用 Python 3.6,有时我仍然会遇到这个问题。例如,当从 REST API 获取响应并将响应文本加载到 JSON 时,我仍然会得到 unicode 字符串。使用 json.dumps() 找到了一个简单的解决方案。

response_message = json.loads(json.dumps(response.text))
print(response_message)
于 2018-04-25T17:17:55.117 回答
-1

我也遇到了这个问题,并且不得不处理 JSON,我想出了一个将 unicode 键转换为字符串的小循环。(simplejson在 GAE 上不返回字符串键。)

obj是从 JSON 解码的对象:

if NAME_CLASS_MAP.has_key(cls):
    kwargs = {}
    for i in obj.keys():
        kwargs[str(i)] = obj[i]
    o = NAME_CLASS_MAP[cls](**kwargs)
    o.save()

kwargs是我传递给 GAE 应用程序的构造函数的(它不喜欢unicodekey in **kwargs

不如 Wells 的解决方案强大,但要小得多。

于 2011-06-20T01:20:36.577 回答
-1

我已经从Mark Amery的答案中改编了代码,特别是为了摆脱鸭子打字的优点。isinstance

编码是手动完成的并且ensure_ascii被禁用。python 文档json.dump

如果 ensure_ascii 为 True(默认值),则输出中的所有非 ASCII 字符都使用 \uXXXX 序列进行转义

免责声明:在 doctest 中,我使用了匈牙利语。一些值得注意的与匈牙利语相关的字符编码是:cp852使用的 IBM/OEM 编码,例如。在 DOS 中(有时称为ascii,我认为不正确,它取决于代码页设置),cp1250例如使用。在 Windows 中(有时称为ansi,取决于语言环境设置),iso-8859-2有时在 http 服务器上使用。测试文本Tüskéshátú kígyóbűvölő归属于Koltai László(本地人名形式),来自wikipedia

# coding: utf-8
"""
This file should be encoded correctly with utf-8.
"""
import json

def encode_items(input, encoding='utf-8'):
    u"""original from: https://stackoverflow.com/a/13101776/611007
    adapted by SO/u/611007 (20150623)
    >>> 
    >>> ## run this with `python -m doctest <this file>.py` from command line
    >>> 
    >>> txt = u"Tüskéshátú kígyóbűvölő"
    >>> txt2 = u"T\\u00fcsk\\u00e9sh\\u00e1t\\u00fa k\\u00edgy\\u00f3b\\u0171v\\u00f6l\\u0151"
    >>> txt3 = u"uúuutifu"
    >>> txt4 = b'u\\xfauutifu'
    >>> # txt4 shouldn't be 'u\\xc3\\xbauutifu', string content needs double backslash for doctest:
    >>> assert u'\\u0102' not in b'u\\xfauutifu'.decode('cp1250')
    >>> txt4u = txt4.decode('cp1250')
    >>> assert txt4u == u'u\\xfauutifu', repr(txt4u)
    >>> txt5 = b"u\\xc3\\xbauutifu"
    >>> txt5u = txt5.decode('utf-8')
    >>> txt6 = u"u\\u251c\\u2551uutifu"
    >>> there_and_back_again = lambda t: encode_items(t, encoding='utf-8').decode('utf-8')
    >>> assert txt == there_and_back_again(txt)
    >>> assert txt == there_and_back_again(txt2)
    >>> assert txt3 == there_and_back_again(txt3)
    >>> assert txt3.encode('cp852') == there_and_back_again(txt4u).encode('cp852')
    >>> assert txt3 == txt4u,(txt3,txt4u)
    >>> assert txt3 == there_and_back_again(txt5)
    >>> assert txt3 == there_and_back_again(txt5u)
    >>> assert txt3 == there_and_back_again(txt4u)
    >>> assert txt3.encode('cp1250') == encode_items(txt4, encoding='utf-8')
    >>> assert txt3.encode('utf-8') == encode_items(txt5, encoding='utf-8')
    >>> assert txt2.encode('utf-8') == encode_items(txt, encoding='utf-8')
    >>> assert {'a':txt2.encode('utf-8')} == encode_items({'a':txt}, encoding='utf-8')
    >>> assert [txt2.encode('utf-8')] == encode_items([txt], encoding='utf-8')
    >>> assert [[txt2.encode('utf-8')]] == encode_items([[txt]], encoding='utf-8')
    >>> assert [{'a':txt2.encode('utf-8')}] == encode_items([{'a':txt}], encoding='utf-8')
    >>> assert {'b':{'a':txt2.encode('utf-8')}} == encode_items({'b':{'a':txt}}, encoding='utf-8')
    """
    try:
        input.iteritems
        return {encode_items(k): encode_items(v) for (k,v) in input.iteritems()}
    except AttributeError:
        if isinstance(input, unicode):
            return input.encode(encoding)
        elif isinstance(input, str):
            return input
        try:
            iter(input)
            return [encode_items(e) for e in input]
        except TypeError:
            return input

def alt_dumps(obj, **kwargs):
    """
    >>> alt_dumps({'a': u"T\\u00fcsk\\u00e9sh\\u00e1t\\u00fa k\\u00edgy\\u00f3b\\u0171v\\u00f6l\\u0151"})
    '{"a": "T\\xc3\\xbcsk\\xc3\\xa9sh\\xc3\\xa1t\\xc3\\xba k\\xc3\\xadgy\\xc3\\xb3b\\xc5\\xb1v\\xc3\\xb6l\\xc5\\x91"}'
    """
    if 'ensure_ascii' in kwargs:
        del kwargs['ensure_ascii']
    return json.dumps(encode_items(obj), ensure_ascii=False, **kwargs)

我还想强调引用JSON 规范Jarret Hardie的答案,引用:

字符串是零个或多个 Unicode 字符的集合

在我的用例中,我有带有 json 的文件。它们是utf-8编码文件。ensure_ascii导致正确转义但可读性不强的 json 文件,这就是为什么我调整了 Mark Amery 的答案以满足我的需要。

doctest 不是特别周到,但我分享代码希望它对某人有用。

于 2015-06-23T14:36:54.710 回答
-2

查看this answer to a similar question like this 指出

u- 前缀仅仅意味着你有一个 Unicode 字符串。当您真正使用该字符串时,它不会出现在您的数据中。不要被打印输出抛出。

例如,试试这个:

print mail_accounts[0]["i"]

你不会看到你。

于 2017-07-04T13:32:45.607 回答