pythonkeyerrorstring.format

Python string.format KeyError with variable key


I'm pulling in text strings with placeholders for instance attributes. I'm trying to write something that will get the place holder text, find the attribute with that name, and swap it in. I'm able to get the attribute, but to swap it in I'm having to hard code the placeholder.

The "new_text_string = ..." line gives me "KeyError: 'dntier'" The commented line below it works, but I don't want to have to hard code every possible attribute.

import re

class Test:
    def __init__(self,mdtier,rxtier,dntier,vstier):
        self.mdtier = mdtier,
        self.rxtier = rxtier,
        self.dntier = dntier,
        self.vstier = vstier,


rec = Test('You Only','You Only','You + Family','You + Spouse')
text_string = 'Dental coverage for {dntier}.'

try:
    text_variable = re.search('\{(.+?)\}', text_string).group(1)
except AttributeError:
    text_variable = '' 
if text_variable:
    replacement = getattr(rec, text_variable)[0]
    new_text_string = text_string.format(text_variable=replacement)
    #new_text_string = text_string.format(dntier=replacement)
else:
    new_text_string = text_string

Solution

  • The error you see is because this line

    text_string.format(text_variable=replacement)
    

    will replace a variable named text_variable, but the string template is looking for a variable named dntier. That is, the variable name is not evaluated, but passed literally.

    Since you're trying to pass a keyword argument with a dynamic name, I suggest creating a dict and using **:

    new_text_string = text_string.format(**{text_variable: replacement})
    

    Or, to simplify the code even further, you can use rec.__dict__:

    import re
    
    class Test:
        def __init__(self,mdtier,rxtier,dntier,vstier):
            self.mdtier = mdtier,
            self.rxtier = rxtier,
            self.dntier = dntier,
            self.vstier = vstier,
    
    rec = Test('You Only','You Only','You + Family','You + Spouse')
    text_string = 'Dental coverage for {dntier}.'
    print(text_string.format(**rec.__dict__))