1

I have tried several ways to convert a dict-like str from a list to a dict, but cannot figure out how to interpret the error message correctly.

I have a list:

list = [(45, "{'kingdom': 'Plantae', 'phylum': None, 'class': None, 'order': None, 'family': None}"), (12383, "{'kingdom': 'Plantae', 'phylum': None, 'class': None, 'order': 'Fagales', 'family': None}"), (12384, "{'kingdom': 'Plantae', 'phylum': None, 'class': None, 'order': 'Primulales', 'family': None}"), (12385, "{'kingdom': 'Plantae', 'phylum': None, 'class': None, 'order': 'Magnoliales', 'family': None}"), (12386, "{'kingdom': 'Plantae', 'phylum': None, 'class': None, 'order': 'Celastrales', 'family': None}")]

and want to convert the dict-like string into a dict, so I can access the values by key. I have tried:

test = (list[0][1]).replace("'", "\"")
dict(test)

but get the following error:

ValueError: dictionary update sequence element #0 has length 1; 2 is required

I also tried json.loads()

test2 = json.loads(test)

which returned:

JSONDecodeError: Expecting value: line 1 column 34 (char 33)

When I manually insert the string in the dict() function, the string successfully converts to a dict but not when using the list index. I would appreciate it if someone could explain why there is this difference and how I can convert the string directly into a dict.

Thanks for any help

  • 2
    `ast.literal_eval(list[0][1])` – Barmar May 12 '22 at 19:39
  • 2
    `dict` can accept a dict as argument, but not a string that looks like the representation of a dict, and `test` is just such a string. – Thierry Lathuille May 12 '22 at 19:41
  • See also https://stackoverflow.com/questions/15197673/using-pythons-eval-vs-ast-literal-eval. I'm confident there's a proper duplicate for this question but I'm struggling to find it. – Karl Knechtel May 12 '22 at 19:45

2 Answers2

3

You can use ast.literal_eval:

from ast import literal_eval

lst = [(45, "{'kingdom': 'Plantae', 'phylum': None, 'class': None, 'order': None, 'family': None}"), (12383, "{'kingdom': 'Plantae', 'phylum': None, 'class': None, 'order': 'Fagales', 'family': None}"), (12384, "{'kingdom': 'Plantae', 'phylum': None, 'class': None, 'order': 'Primulales', 'family': None}"), (12385, "{'kingdom': 'Plantae', 'phylum': None, 'class': None, 'order': 'Magnoliales', 'family': None}"), (12386, "{'kingdom': 'Plantae', 'phylum': None, 'class': None, 'order': 'Celastrales', 'family': None}")]

output = [(num, literal_eval(dct_rep)) for num, dct_rep in lst]

print(output) # [(45, {'kingdom': 'Plantae', 'phylum': None, 'class': None, 'order': None, 'family': None}), ...]
print(output[0][1]['kingdom']) # Plantae

The list comprehension converts each dict representation into a true dict. After that you can access the data in a more natural way.

j1-lee
  • 13,764
  • 3
  • 14
  • 26
-1

I would look at eval

test_dict = eval(list[0][1])

Note: This is not recommended in production code as this can run any python code

Tippecanoe
  • 188
  • 2
  • 10