How to Convert a String to a Dictionary in Python

To convert a string to a dictionary in Python, use ast.literal_eval() when the text looks like a Python dict (single quotes, True, None), and json.loads() when it’s JSON. Both return a real dict:

import ast, json
ast.literal_eval("{'state': 'TX', 'total': 49.99}")   # {'state': 'TX', 'total': 49.99}
json.loads('{"state": "TX", "total": 49.99}')         # same dict

I tested these conversions on Python 3.12.5 from Command Prompt, feeding them made-up US customer orders.

The right tool depends on what the string looks like, so we’ll go format by format and finish with a safe helper.

Convert a Python dict string with ast.literal_eval()

A string like "{'customer': 'Emily Carter'}" usually comes from str(my_dict) or a log file. ast.literal_eval() reads it back, nested lists and booleans included:

import ast

text = "{'customer': 'Emily Carter', 'state': 'TX', 'balance': 1250.5, 'active': True, 'tags': ['pro', 'annual']}"

order = ast.literal_eval(text)
print(type(order))
print(order["customer"], order["tags"][0])
print(f"Balance: ${order['balance']:,.2f}")

Output:

<class 'dict'>
Emily Carter pro
Balance: $1,250.50
Command Prompt output of Python ast.literal_eval converting a dict string with single quotes into a real dictionary
type() confirms a real dict, so keys, list items and the balance work right away.

You can trust it because it only accepts literals, never function calls. Going the other way is covered in converting a dictionary to a string in Python.

Convert a JSON string to a dictionary with json.loads()

API responses use JSON: double quotes, true and null. json.loads() maps those to True and None, but a single-quoted Python string makes it fail:

import ast
import json

api_text = '{"customer": "James Miller", "total": 49.99, "paid": true, "coupon": null}'
data = json.loads(api_text)
print(data)

repr_text = "{'customer': 'James Miller', 'paid': True}"
try:
    json.loads(repr_text)
except json.JSONDecodeError as err:
    print("json.loads failed:", err)

print(ast.literal_eval(repr_text))

Output:

{'customer': 'James Miller', 'total': 49.99, 'paid': True, 'coupon': None}
json.loads failed: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
{'customer': 'James Miller', 'paid': True}
Command Prompt output of Python json.loads parsing a JSON string, then failing on single quotes while ast.literal_eval succeeds
json.loads() rejects the single-quoted keys with a JSONDecodeError; literal_eval() reads the same text fine.

Don’t swap the quotes with replace(); you’ll break names like O’Brien. Nested JSON, dates and JSON files are in my guide to converting a JSON string to a dictionary.

How do I convert a key=value string to a dictionary?

Text such as name=Olivia Brown; state=CO isn’t a literal, so split it yourself: on the pair separator, then on the first =, stripping spaces:

line = "name=Olivia Brown; city=Denver; state=CO; plan=pro; total=79.5"

record = {}
for pair in line.split(";"):
    key, value = pair.split("=", 1)      # maxsplit=1 keeps any '=' inside the value
    record[key.strip()] = value.strip()
print(record)

record["total"] = float(record["total"])
print(f"{record['name']} owes ${record['total']:.2f}")

# one-liner for simple "key:value,key:value" text
codes = dict(item.split(":", 1) for item in "TX:Texas,CA:California,NY:New York".split(","))
print(codes)

Output:

{'name': 'Olivia Brown', 'city': 'Denver', 'state': 'CO', 'plan': 'pro', 'total': '79.5'}
Olivia Brown owes $79.50
{'TX': 'Texas', 'CA': 'California', 'NY': 'New York'}
Command Prompt output of Python splitting a key=value string into a dictionary and a key:value one-liner with dict()
Each pair becomes a key and value; total stays text until float() turns it into a number.

You get strings from split(), so convert numbers yourself. More splitting options are in splitting a string by comma in Python, and extra spaces are handled in removing spaces from a string.

Convert a URL query string to a dictionary

For state=TX&plan=pro text from a URL, the standard library parses and decodes it. parse_qsl() gives pairs for dict(); parse_qs() keeps repeated keys:

from urllib.parse import parse_qs, parse_qsl, urlsplit

url = "https://shop.example.com/checkout?state=TX&plan=pro&total=49.99&tag=new&tag=sale"
query = urlsplit(url).query

print(dict(parse_qsl(query)))   # one value per key; the last tag wins
print(parse_qs(query))          # every value kept in a list

Output:

{'state': 'TX', 'plan': 'pro', 'total': '49.99', 'tag': 'sale'}
{'state': ['TX'], 'plan': ['pro'], 'total': ['49.99'], 'tag': ['new', 'sale']}

Use parse_qs() when a key can repeat, like the two tag values here. Then a dictionary comprehension can convert the values.

Safely convert any string to a dict, and why not eval()

eval() works too, but it runs any code in the string, so I never use it on text I didn’t write. This helper tries JSON, then literal_eval(), and rejects the rest:

import ast
import json

def to_dict(text):
    """Turn JSON or a Python dict literal into a dict, or raise ValueError."""
    try:
        result = json.loads(text)
    except json.JSONDecodeError:
        try:
            result = ast.literal_eval(text)
        except (ValueError, SyntaxError) as err:
            raise ValueError(f"not a dictionary string: {err}") from None
    if not isinstance(result, dict):
        raise ValueError(f"expected a dict, got {type(result).__name__}")
    return result

samples = ['{"plan": "pro", "seats": 5}',
           "{'plan': 'team', 'seats': 12}",
           "__import__('os').getcwd()",
           "[1, 2, 3]"]
for s in samples:
    try:
        print("OK  ", to_dict(s))
    except ValueError as err:
        print("FAIL", err)

Output:

OK   {'plan': 'pro', 'seats': 5}
OK   {'plan': 'team', 'seats': 12}
FAIL not a dictionary string: malformed node or string on line 1: <ast.Call object at 0x000002216ACA4DD0>
FAIL expected a dict, got list
Command Prompt output of a Python to_dict helper accepting JSON and dict literal strings and rejecting a code string and a list
Both dictionary strings pass; the __import__ call is refused as a malformed node, and the list is rejected because it isn’t a dict.

You need the isinstance() check because literal_eval() also returns lists. If you later need key-value pairs, see converting a dictionary to a list of tuples.

String to dictionary methods compared

String looks likeUseWatch out for
{'a': 1, 'ok': True}ast.literal_eval()Returns any literal, so check for dict
{"a": 1, "ok": true}json.loads()Single quotes raise JSONDecodeError
a=1; b=2split() + dict()Values stay strings
a=1&b=2parse_qsl() / parse_qs()Repeated keys

You’ll probably want these next:

Frequently asked questions

How do I convert a string to a dictionary in Python?

Use ast.literal_eval(s) for a Python-style dict string and json.loads(s) for a JSON string.

Why does json.loads fail on my dictionary string?

JSON needs double quotes. A str(dict) string uses single quotes, so read it with ast.literal_eval().

Is it safe to use eval() to convert a string to a dict?

No, it runs any code in the string. Use ast.literal_eval(), which raises ValueError on code.

How do I convert “key=value” text to a dictionary?

dict(p.split("=", 1) for p in s.split(";")), then strip spaces if needed.

How do I turn a URL query string into a dict?

Use dict(urllib.parse.parse_qsl(query)), or parse_qs(query) to keep repeated keys as lists.

Where is ast.literal_eval documented?

See ast.literal_eval() in the Python docs.