12

I am having problems using format with a string which looks like a Python dictionary.

I want to generate the following string: {"one":1} If I try to do it as:

'{"one":{}}'.format(1)

the interpreter throws a KeyError:

>>> a = '{"one":{}}'.format(1)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
KeyError: '"one"'

I understand that the issue probably revolves around the fact that the string contains {, which can be confused with format's {}. Why is this happening exactly and how can it be solved?

I know of percentage formatting, but I'd like to find a solution that doesn't involve ditching format().

user2891462
  • 3,033
  • 2
  • 32
  • 60
  • Keep in mind than percentage formatting is faster: format=0.7228269569986878, %=0.03355357599866693 ( result of `timeit.timeit` on your example ) – Yaroslav Surzhikov Sep 11 '17 at 15:02
  • @YaroslavSurzhikov Unless you're generating vast amounts of strings I don't think that really matters. – JAB Sep 11 '17 at 18:54
  • If you want to make a string of a dictionary, consider `str({"one":1})`. – marcelm Sep 11 '17 at 20:27
  • Note: Even if the question isn't identical, if an answer explains the reason for something, [it still qualifies](https://stackoverflow.com/questions/41983180/is-the-empty-tuple-in-python-a-constant#comment71144721_41983180). – cs95 Sep 11 '17 at 20:46
  • @cᴏʟᴅsᴘᴇᴇᴅ in this specific Q the issue isn't only how to solve this but why it is interpreted as a dictionary (which I address). Do you know any other answers that might answer the second part? If so please add it to the list of dupes. I'm leaning towards re-opening but I'm pretty sure there's an answer for the second issue too (Which I didn't find with a *very basic* search :-). – Dimitris Fasarakis Hilliard Sep 11 '17 at 20:55
  • @JimFasarakisHilliard Found one... https://stackoverflow.com/questions/31859757/format-keyerror-when-using-curly-brackets-in-strings – cs95 Sep 11 '17 at 20:58
  • 1
    @cᴏʟᴅsᴘᴇᴇᴅ Good enough for me. – Dimitris Fasarakis Hilliard Sep 11 '17 at 21:00

3 Answers3

17

The formatting of '{"one": {}}' is using an identifier as the field_name and will essentially try to look for a keyword argument that's been supplied to .format and has the name '"one"'.

As the docs state:

The field_name itself begins with an arg_name that is either a number or a keyword. If it’s a number, it refers to a positional argument, and if it’s a keyword, it refers to a named keyword argument.

(emphasis mine)

That's why you get the KeyError exception; it tries to look for a key in the mapping of keyword arguments provided to format. (which, in this case, is empty, hence the error).

As a solution, just escape the outer curly braces:

>>> '{{"one":{}}}'.format(1)
'{"one":1}'

The same remedy applies if you decide on using f-strings in the future:

>>> f'{{"one": {1}}}'
'{"one": 1}'
Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
13

You need doubled curly braces {{ }} to escape curly braces in string formatting.

a= '{{"one":{}}}'.format(1)

from doc:

Format strings contain “replacement fields” surrounded by curly braces {}. Anything that is not contained in braces is considered literal text, which is copied unchanged to the output. If you need to include a brace character in the literal text, it can be escaped by doubling: {{ and }}.

If you do not escape braces, str.format() will look for the value of key '"one"' to format the string. For example:

b = '{"one"} foo'.format(**{'"one"':1})
print(b) # 1 foo
Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
floatingpurr
  • 7,749
  • 9
  • 46
  • 106
2

Braces can be escaped by using double braces, use:

'{{"one":{}}}'.format(1)
Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
v.coder
  • 1,822
  • 2
  • 15
  • 24