web-dev-qa-db-fra.com

Convertir une représentation sous forme de chaîne d'un dictionnaire en dictionnaire?

Comment puis-je convertir la représentation str d'un dict, telle que la chaîne suivante, en un dict?

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

Je préfère ne pas utiliser eval. Que puis-je utiliser?

La principale raison en est que l’un de mes cours de collègues a été écrit, convertit toutes les entrées en chaînes. Je ne suis pas d'humeur à modifier ses cours pour régler ce problème.

684
UberJumper

À partir de Python 2.6, vous pouvez utiliser les fonctions intégrées ast.literal_eval :

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

C'est plus sûr que d'utiliser eval. Comme le dit sa propre documentation:

 >>> help (ast.literal_eval) 
 Aide sur la fonction literal_eval dans le module ast: 
 
 literal_eval (node_or_string) 
 Évaluez en toute sécurité une expression noeud ou une chaîne contenant une expression Python 
. La chaîne ou le nœud fourni ne peut contenir que les structures littérales 
 Python suivantes: chaînes, nombres, n-uplets, listes, dicts, booléens, 
 Et aucun. 

Par exemple:

_>>> 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
_
1055
Jacob Gabrielson

http://docs.python.org/2/library/json.html

JSON peut résoudre ce problème bien que son décodeur veuille des guillemets doubles autour des clés et des valeurs. Si cela ne vous dérange pas de remplacer le hack ...

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

REMARQUE: si vous utilisez des guillemets simples dans vos clés ou vos valeurs, cela échouera à cause d'un remplacement incorrect des caractères. Cette solution n'est recommandée que si vous avez une forte aversion pour la solution eval.

En savoir plus sur la citation simple json: citation simple jQuery dans une réponse JSON

190
ir0x539

en utilisant json.loads:

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

Pour l'exemple d'OP:

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

Nous pouvons utiliser Yaml pour traiter ce type de json non standard dans la chaîne:

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

Si la chaîne peut toujours être fiable, vous pouvez utiliser eval (ou utiliser literal_eval comme suggéré; c'est sûr, quelle que soit la chaîne.) Sinon, vous avez besoin d'un analyseur. Un analyseur JSON (tel que simplejson) fonctionnerait s’il ne stockait que le contenu compatible avec le schéma JSON.

22
Blixt

Utilisez json. la bibliothèque ast consomme beaucoup de mémoire et plus lentement. J'ai un processus qui a besoin de lire un fichier texte de 156 Mo. Ast avec 5 minutes de retard pour le dictionnaire de conversion json et 1 minute avec 60% de mémoire en moins!

18
Rogerio Silveira

Résumer:

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

Résultats:

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

Conclusion: prefer json.loads

6
Anatoly Alekseev

Vous pouvez essayer ça.

    >>> import ast
    >>> data = "{'user': 'bob', 'age': 10, 'grades': ['A', 'F', 'C']}"
    >>> ast.literal_eval(data)

    O/P: {'age': 10, 'grades': ['A', 'F', 'C'], 'user': 'bob'}

    >>> user = ast.literal_eval(data)

    >>> user['age']
    O/P: 10

    >>> user['grades']
    O/P: ['A', 'F', 'C']

    >>> user['user']
    O/P: 'bob'
6
Walk

Si vous ne pouvez pas utiliser Python 2.6, vous pouvez utiliser une implémentation sécurisée simple telle que http://code.activestate.com/recipes/364469/

Il se greffe sur le compilateur Python afin que vous n'ayez pas à faire tout le travail grossier vous-même.

5
Ned Batchelder
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

aucune bibliothèque n'est utilisée:

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

NOTE: Comme il a codé en dur, split("'") ne fonctionnera que pour les chaînes où les données sont "entre guillemets simples".

3
tamerlaha