将 Dictionary 的 String 表示形式转换为字典

Convert a String representation of a Dictionary to a dictionary

提问人:UberJumper 提问时间:6/13/2009 最后编辑:cottontailUberJumper 更新时间:11/15/2023 访问量:1356446

问:

如何将字典的表示形式(例如以下字符串)转换为?strdict

s = "{'muffin' : 'lolz', 'foo' : 'kitty'}"

我不喜欢使用 .我还能使用什么?eval

python 字符串 字典

评论

27赞 Martijn Pieters 11/22/2018
注意:对于那些带着看似相似JSON 数据来到这里的人,你想去阅读 Python 中的解析 JSON。JSON与Python不是一回事。如果字符串周围有双引号,则可能有 JSON 数据。您还可以查找 、 或 、 Python 语法使用 和 。"nulltruefalseNoneTrueFalse
2赞 Ned Batchelder 6/13/2009
如果你不能使用 Python 2.6,你可以使用一个简单的安全实现,比如 code.activestate.com/recipes/364469 它搭载在 Python 编译器上,这样你就不必自己做所有的粗略工作。

答:

25赞 Blixt 6/13/2009 #1

如果字符串始终是可信的,则可以使用(或按照建议使用;无论字符串是什么,它都是安全的。否则,您需要一个解析器。如果 JSON 解析器(例如 simplejson)只存储适合 JSON 方案的内容,则该解析器将起作用。evalliteral_eval

评论

9赞 Eli Courtwright 6/13/2009
从 2.6 开始,simplejson 作为 json 模块包含在 Python 标准库中。
12赞 Ben Hoyt 6/15/2009
是的,这是一个很好的答案,但请注意,官方 JSON 不支持单引号字符串,如原始海报示例中所示。
1664赞 Jacob Gabrielson 6/13/2009 #2

您可以使用内置ast.literal_eval

>>> import ast
>>> ast.literal_eval("{'muffin' : 'lolz', 'foo' : 'kitty'}")
{'muffin': 'lolz', 'foo': 'kitty'}

这比使用 更安全。正如它自己的文档所说:eval

>>> help(ast.literal_eval)
Help on function literal_eval in module ast:

literal_eval(node_or_string)
    Safely evaluate an expression node or a string containing a Python
    expression.  The string or node provided may only consist of the following
    Python literal structures: strings, numbers, tuples, lists, dicts, booleans,
    and None.

例如:

>>> eval("shutil.rmtree('mongo')")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
  File "/opt/Python-2.6.1/lib/python2.6/shutil.py", line 208, in rmtree
    onerror(os.listdir, path, sys.exc_info())
  File "/opt/Python-2.6.1/lib/python2.6/shutil.py", line 206, in rmtree
    names = os.listdir(path)
OSError: [Errno 2] No such file or directory: 'mongo'
>>> ast.literal_eval("shutil.rmtree('mongo')")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/Python-2.6.1/lib/python2.6/ast.py", line 68, in literal_eval
    return _convert(node_or_string)
  File "/opt/Python-2.6.1/lib/python2.6/ast.py", line 67, in _convert
    raise ValueError('malformed string')
ValueError: malformed string

评论

1赞 Paulo Matos 10/4/2012
我应该补充一点,您需要清理字符串以用于ast.literal_eval。(确保字符串中的引号/双引号被转义)
0赞 12/10/2012
我收到此错误 我在 Windows 7 x64 上的 python 2.6 (x86) 文件 “D:\Python26\lib\ast.py”,第 48 行,在 literal_eval node_or_string = parse(node_or_string, mode='eval') 文件“D:\Python26\lib\ast.py”,第 36 行,在解析中返回 compile(expr, filename, mode, PyCF_ONLY_AST) 文件“<unknown>”,第 1 行 ^ SyntaxError: 语法无效
1赞 n611x007 7/4/2014
样式字符串呢?"dict(a=1)"
4赞 JuanB 1/8/2018
为什么不使用 json.dumps 和 json.loads insead,我发现这个解决方案比使用 eval 更出色
5赞 Michael Wheeler 4/22/2021
@JuanB json.loads 不接受单引号字符串。它也不接受 None,只接受 null。
400赞 i0x539 10/16/2013 #3

https://docs.python.org/library/json.html

JSON可以解决这个问题,尽管它的解码器需要在键和值周围加上双引号。如果您不介意替换黑客...

import json
s = "{'muffin' : 'lolz', 'foo' : 'kitty'}"
json_acceptable_string = s.replace("'", "\"")
d = json.loads(json_acceptable_string)
# d = {u'muffin': u'lolz', u'foo': u'kitty'}

请注意,如果键或值中有单引号作为键或值的一部分,则由于字符替换不当,这将失败。仅当您对 eval 解决方案有强烈厌恶感时,才建议使用此解决方案。

有关 json 单引号的更多信息:jQuery.parseJSON 由于 JSON 中的单引号转义而引发“无效的 JSON”错误

评论

5赞 Finn Årup Nielsen 8/23/2017
另一个问题是 ."{0: 'Hello'}"
5赞 gdvalderrama 3/22/2018
如果您有尾随逗号(不符合 JSON),例如:“{'muffin' : 'lolz', 'foo' : 'kitty',}”
2赞 AuthorOfTheSurf 5/23/2018
单引号字符串、元组文本和尾随逗号不是有效的 JSON。 将仅适用于有效的 JSON 字符串。请参阅此处的规范: json.org 使用是最安全的解决方案,因此请尽可能使用。如有必要,我建议将您的输入转换为有效的 JSON。json.loadsjson.loads
1赞 Matias Gonzalez 9/20/2018
此外,如果您有 unicode 字符串,此解决方案也不起作用
5赞 林果皞 8/9/2020
如果值(没有单引号,所以不能替换),则不起作用,例如None"{'d': None}"
234赞 tokhi 8/15/2014 #4

用:json.loads

>>> import json
>>> h = '{"foo":"bar", "foo2":"bar2"}'
>>> d = json.loads(h)
>>> d
{u'foo': u'bar', u'foo2': u'bar2'}
>>> type(d)
<type 'dict'>

评论

25赞 technazi 5/13/2016
我不认为它回答了 OP 的答案。我们如何使用 json.laads 将字符串 s = “{'muffin' : 'lolz', 'foo' : 'kitty'}” 转换为 dict?
4赞 ntg 12/8/2016
@technazi: json.loads(h.replace(“'”,'“'))
1赞 ntg 12/8/2016
但是,也有限制,例如: h= '{“muffin” : “lolz”, “foo” : “kitty”,}', also h= '{“muffin's” : “lolz”, “foo” : “kitty”}', (刚刚注意到类似答案中的部分相同评论......仍然为了完整而离开这里......
8赞 nostradamus 1/11/2017
在我看来,这是最短和最简单的方法......绝对是我个人喜欢的那个。
3赞 MrR 2/23/2019
@nostradamus 异常太多,浮点值,元组等。
20赞 Rogerio Silveira 8/27/2014 #5

用。该库消耗大量内存,而且速度较慢。我有一个进程需要读取 156Mb 的文本文件。 转换字典延迟 5 分钟,内存减少 1 分钟,内存减少 60%!jsonastAstjson

评论

15赞 ntg 12/8/2016
但有其局限性:尝试转换字符串“{'foo':'bar',}”
55赞 lqhcpsgbl 6/28/2016 #6

以 OP 为例:

s = "{'muffin' : 'lolz', 'foo' : 'kitty'}"

我们可以用 Yaml 来处理这种字符串中的非标准 json:

>>> import yaml
>>> s = "{'muffin' : 'lolz', 'foo' : 'kitty'}"
>>> s
"{'muffin' : 'lolz', 'foo' : 'kitty'}"
>>> yaml.load(s)
{'muffin': 'lolz', 'foo': 'kitty'}

评论

8赞 Eric Marcos 8/19/2017
这将导致“yes”和“no”字符串转换为 True / False
0赞 shailu 5/3/2021
我得到了我的价值,效果很好......但是我收到一个错误“AMLLoadWarning:在没有 Loader=...已弃用,因为默认的 Loader 不安全。请阅读 msg.pyyaml.org/load 了解详情。 这是什么??
1赞 Yasin Zähringer 7/23/2021
仅将此 yaml 解析器用于受信任的输入。最好用于避免安全隐患。safe_load
0赞 avadhut007 11/25/2022
config = yaml.load(ymlfile, Loader=yaml.装载机)
11赞 Siva Kameswara Rao Munipalle 7/30/2016 #7
string = "{'server1':'value','server2':'value'}"

#Now removing { and }
s = string.replace("{" ,"")
finalstring = s.replace("}" , "")

#Splitting the string based on , we get key value pairs
list = finalstring.split(",")

dictionary ={}
for i in list:
    #Get Key Value pairs separately to store in dictionary
    keyvalue = i.split(":")

    #Replacing the single quotes in the leading.
    m= keyvalue[0].strip('\'')
    m = m.replace("\"", "")
    dictionary[m] = keyvalue[1].strip('"\'')

print dictionary

评论

3赞 Om Sao 3/29/2019
这种方法存在许多错误。如果键的值包含 或 .如果它是嵌套的呢?如果值包含 ??{}dict,
6赞 tamerlaha 12/26/2016 #8

不使用任何库 (python2):

dict_format_string = "{'1':'one', '2' : 'two'}"
d = {}
elems  = filter(str.isalnum,dict_format_string.split("'"))
values = elems[1::2]
keys   = elems[0::2]
d.update(zip(keys,values))

注意:由于它已硬编码,因此仅适用于数据为“单引号”的字符串。split("'")

注2:在python3中,您需要换行才能获取列表。filter()list()

评论

0赞 Aravind Krishnakumar 1/24/2021
elems = filter(str.isalnum,dict_format_string.split(“'”)) 应该是 list(elems = filter(str.isalnum,dict_format_string.split(“'”))) 如果不转换为列表,它仍然是 'filter' 对象
34赞 Anatoly Alekseev 7/20/2018 #9

总结一下:

import ast, yaml, json, timeit

descs=['short string','long string']
strings=['{"809001":2,"848545":2,"565828":1}','{"2979":1,"30581":1,"7296":1,"127256":1,"18803":2,"41619":1,"41312":1,"16837":1,"7253":1,"70075":1,"3453":1,"4126":1,"23599":1,"11465":3,"19172":1,"4019":1,"4775":1,"64225":1,"3235":2,"15593":1,"7528":1,"176840":1,"40022":1,"152854":1,"9878":1,"16156":1,"6512":1,"4138":1,"11090":1,"12259":1,"4934":1,"65581":1,"9747":2,"18290":1,"107981":1,"459762":1,"23177":1,"23246":1,"3591":1,"3671":1,"5767":1,"3930":1,"89507":2,"19293":1,"92797":1,"32444":2,"70089":1,"46549":1,"30988":1,"4613":1,"14042":1,"26298":1,"222972":1,"2982":1,"3932":1,"11134":1,"3084":1,"6516":1,"486617":1,"14475":2,"2127":1,"51359":1,"2662":1,"4121":1,"53848":2,"552967":1,"204081":1,"5675":2,"32433":1,"92448":1}']
funcs=[json.loads,eval,ast.literal_eval,yaml.load]

for  desc,string in zip(descs,strings):
    print('***',desc,'***')
    print('')
    for  func in funcs:
        print(func.__module__+' '+func.__name__+':')
        %timeit func(string)        
    print('')

结果:

*** short string ***

json loads:
4.47 µs ± 33.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
builtins eval:
24.1 µs ± 163 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
ast literal_eval:
30.4 µs ± 299 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
yaml load:
504 µs ± 1.29 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

*** long string ***

json loads:
29.6 µs ± 230 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
builtins eval:
219 µs ± 3.92 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
ast literal_eval:
331 µs ± 1.89 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
yaml load:
9.02 ms ± 92.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

结论: 首选 json.loads

评论

13赞 Michael Campbell 11/27/2018
除了这不适用于他的单引号字符串,这是他最初问题的一部分。性能从未被提及。
3赞 MestreLion 4/19/2021
+1 表示基准(它有助于做出明智的决定),-1 表示结论:正如多次提到的,在许多情况下都是失败的。应该由用户在功能与性能之间做出选择。json
7赞 tsuresh97 3/26/2021 #10

Siva Kameswara Rao Munipalle 的优化代码

s = s.replace("{", "").replace("}", "").split(",")
            
dictionary = {}

for i in s:
    dictionary[i.split(":")[0].strip('\'').replace("\"", "")] = i.split(":")[1].strip('"\'')
            
print(dictionary)
0赞 A. West 11/29/2022 #11

我的字符串里面没有引号:
s = 'Date: 2022-11-29T10:57:01.024Z, Size: 910.11 KB'

我的解决方案是使用:str.split
{k:v for k, v in map(lambda d: d.split(': '), s.split(', '))}

评论

0赞 A. West 11/30/2022
@EricAya,你为什么要把我的问题删掉?如果没有?map
0赞 Eric Aya 11/30/2022
因为答案部分只是为了答案,而不是问题,所以这不是一个讨论论坛。如果您有新问题,则需要发布实际的新问题。
1赞 Mahsa Yazdani 8/14/2023 #12

我无法使用上述任何答案,因为我有一个指定了 dtypes 的字符串,所以我使用了 json.load,如下所示:

string_dict = """{'contexts': array(['Programmed cell death (PCD) is the regulated death of cells within an organism.', ..., '...'], dtype=object)},..."""

# Replace array( with np.array(
string_dict = string_dict.replace("array(", "np.array(")

# Evaluate the string as python code
python_dict = ast.literal_eval(string_dict)
0赞 cottontail 11/15/2023 #13

如果您有一个 Python 对象的字符串表示形式,而该字符串表示形式无法被 或 解析,请尝试 asteval module。您可以先通过 pip 安装它以使用它: .ast.literal_evaljsonpip install asteval

与内置 or 相比,它的主要优点是它可以比 .特别是当您的字符串包含数学表达式(如 、 、 numpy 对象等)时,请使用它。astevalastevalnanDecimal

要使用它,我们必须实例化一个对象并使用要计算的字符串调用它。在下面的示例中,字典的字符串表示形式不是 JSON,并且包含无法通过 ;但是,正确评估它。Interpreterast.literal_evalasteval.Interpreter

import ast
import json
from asteval import Interpreter

s = "{1: nan, 2: 3}"
ast.literal_eval(s)     # ValueError: malformed node or string
json.loads(s)           # JSONDecodeError
aeval = Interpreter()
aeval(s)                # {1: nan, 2: 3}

其他一些例子,其中或失败但有效。literal_evaljson.loadsasteval

  1. 如果您有 numpy 对象的字符串表示形式,并且您的系统上安装了 numpy,那么转换为正确的对象也容易得多。asteval

    aeval = Interpreter()
    aeval("{'a': array([ 1.,  2., nan])}")    # {'a': array([ 1.,  2., nan])}
    
  2. 默认情况下,计算 numpy 函数;但是,如果你想让它以某种方式解析一些符号(例如numpy dtypes),你可以定义一个自定义符号表,并在创建时将其传递给。astevalInterpreter

    下面是一个示例,其中创建了一个符号表,该符号表定义了如何计算 numpy dtypes、type 和 value,并将其传递给 .decimal.DecimalnullInterpreter

    from asteval import Interpreter, make_symbol_table
    from decimal import Decimal
    
    s = "{'a': array(['text'], dtype=object), 'b': Decimal('3.33'), 'c': null, 'd': array([1, 2], dtype=int8)}"
    symtable = make_symbol_table(object=object, Decimal=Decimal, null=None, int8='int8')
    aeval = Interpreter(symtable=symtable)
    d = aeval(s)
    print(d)   # {'a': array(['text'], dtype=object), 'b': Decimal('3.33'), 'c': None, 'd': array([1, 2], dtype=int8)}
    

最后,请记住,由于它计算任何 numpy/math 函数(实际上,只要它在参数中定义,就会输入到其中的任何函数),请注意您传递给它的输入。symtable