90

I have a bytes type object like this:

b"{'one': 1, 'two': 2}"

I need to get the dictionary from that using python code. I am converting it into string and then converting into dictionary as follows.

string = dictn.decode("utf-8")
print(type(string))
>> <class 'str'>
d = dict(toks.split(":") for toks in string.split(",") if toks)

But I am getting the below error:

------> d = dict(toks.split(":") for toks in string.split(",") if toks)
TypeError: 'bytes' object is not callable
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Harathi
  • 999
  • 2
  • 7
  • 8
  • 1
    No need to make you own dictionary parser. Send the string to [`ast.literal_eval`](https://docs.python.org/3/library/ast.html#ast.literal_eval) – Patrick Haugh Mar 09 '18 at 00:08
  • The code you've posted here does not raise that exception. In fact, it does almost what you say you want it to do (modulo some mistakes in dealing with quote characters—e.g., you're going to end up with a key like `" 'two'"` instead of `"two"`). – abarnert Mar 09 '18 at 00:13
  • 1
    Meanwhile, where did this input come from? Taking the `repr` of a Python dict and `encode`-ing it to UTF-8 is really not a good way to store data that you want to load back in later. Much better to use something like JSON or Pickle. – abarnert Mar 09 '18 at 00:14
  • @Aran-Fey bytes is different with strings – Willy satrio nugroho Nov 17 '21 at 03:09

5 Answers5

132

I think a decode is also required to get a proper dict.

a= b"{'one': 1, 'two': 2}"
ast.literal_eval(a.decode('utf-8'))
**Output:** {'one': 1, 'two': 2}

The accepted answer yields

a= b"{'one': 1, 'two': 2}"
ast.literal_eval(repr(a))
**output:**  b"{'one': 1, 'two': 2}"

The literal_eval hasn't done that properly with many of my code so I personally prefer to use json module for this

import json
a= b"{'one': 1, 'two': 2}"
json.loads(a.decode('utf-8'))
**Output:** {'one': 1, 'two': 2}
starball
  • 20,030
  • 7
  • 43
  • 238
H S Rathore
  • 1,954
  • 2
  • 15
  • 20
57

All you need is ast.literal_eval. Nothing fancier than that. No reason to mess with JSON unless you are specifically using non-Python dict syntax in your string.

# python3
import ast
byte_str = b"{'one': 1, 'two': 2}"
dict_str = byte_str.decode("UTF-8")
mydata = ast.literal_eval(dict_str)
print(repr(mydata))

See answer here. It also details how ast.literal_eval is safer than eval.

mattmc3
  • 17,595
  • 7
  • 83
  • 103
  • 5
    seems need extra decode. error log: raise ValueError('malformed node or string: ' + repr(node)) ValueError: malformed node or string: b"{'one': 1, 'two': 2}" – Zhi Yuan Feb 29 '20 at 16:15
20

You could try like this:

import json
import ast

a= b"{'one': 1, 'two': 2}"
print(json.loads(a.decode("utf-8").replace("'",'"')))

print(ast.literal_eval(a.decode("utf-8")))

There are the doc of module:

1.ast doc

2.json doc

William Feirie
  • 624
  • 3
  • 7
6

You can use Base64 library to convert string dictionary to bytes, and although you can convert bytes result to a dictionary using json library. Try this below sample code.

import base64
import json


input_dict = {'var1' : 0, 'var2' : 'some string', 'var1' : ['listitem1','listitem2',5]}

message = str(input_dict)
ascii_message = message.encode('ascii')
output_byte = base64.b64encode(ascii_message)

msg_bytes = base64.b64decode(output_byte)
ascii_msg = msg_bytes.decode('ascii')
# Json library convert stirng dictionary to real dictionary type.
# Double quotes is standard format for json
ascii_msg = ascii_msg.replace("'", "\"")
output_dict = json.loads(ascii_msg) # convert string dictionary to dict format

# Show the input and output
print("input_dict:", input_dict, type(input_dict))
print()
print("base64:", output_byte, type(output_byte))
print()
print("output_dict:", output_dict, type(output_dict))

enter image description here

-4

Simple

data = eval(b"{'one': 1, 'two': 2}")
vlad 0024
  • 3
  • 5