94

The following code raises a KeyError exception:

addr_list_formatted = []
addr_list_idx = 0

for addr in addr_list: # addr_list is a list
    addr_list_idx = addr_list_idx + 1
    addr_list_formatted.append("""
        "{0}"
        {
        "gamedir"  "str"
        "address"  "{1}"
        }
    """.format(addr_list_idx, addr))

Why?

I am using Python 3.1.

dreftymac
  • 31,404
  • 26
  • 119
  • 182
Dor
  • 7,344
  • 4
  • 32
  • 45

2 Answers2

168

The problem is that those { and } characters you have there don't specify a key for formatting. You need to double them up, so change your code to:

addr_list_formatted.append("""
    "{0}"
    {{
    "gamedir"  "str"
    "address"  "{1}"
    }}
""".format(addr_list_idx, addr))
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • 13
    What if someone wanted to use JSON in Python? – fijiaaron Jun 24 '16 at 00:47
  • 5
    @fijiaaron the double `{` in the answer is just to tell the `format` method that there is no key to format here (so they are escaped in the formated string and it shouldn't be a problem for build a JSON that way). Alternatively there is other efficient ways to manipulate strings, like the `join` method : `"".join(['{"', var_name, '":', value, '}'])` – mgc Jun 24 '16 at 00:57
  • 1
    I almost lost my mind until figured whats the problem – Dmitry Kankalovich Jul 16 '20 at 01:53
  • 4
    @DmitryKankalovich You have lost your mind, Stack Overflow, and everybody here, is just a figment of your imagination. (that's what I keep telling myself at least) :) – Lasse V. Karlsen Jul 16 '20 at 11:11
1

Using str.format() to format JSON strings is not ideal because you would have to escape the curly braces, as the accepted answer notes.

While this method may be suitable for small JSON templates, it could make the template difficult to read if there are many curly braces that require escaping.

A better alternative could be string.Template:

from string import Template

addr_list = ["address 1, country 1", "address 2, country 2"]

addr_list_formatted = []
addr_list_idx = 0

template = Template("""
"${index}"
{
"gamedir"  "str"
"address"  "${address}"
}
""")

for addr in addr_list:
    addr_list_idx = addr_list_idx + 1
    formatted = template.substitute(index=addr_list_idx, address=addr)
    addr_list_formatted.append(formatted)
Asa
  • 1,624
  • 15
  • 19