0

I have a string templ with variable part that I have to convert with local variables. Variable part of string have a dictionary cur_cols_dct from which I want to get a single value. Key of a dictionary is also a variable: col

templ = "COMMENT IS '{cur_cols_dct[col]}'" # string with variable part
cur_cols_dct = {'art_id':'ID of article'}  # dictionary
col = 'art_id'                             # variable for dictionary key

I have to get string with a single value from a dictionary:

COMMENT IS 'ID of article'

I can use f-string for this goal and it works:

print (f"COMMENT IS '{cur_cols_dct[col]}'")

But when I try to use format(locals()) it doesn't work, because Python can't recognize that 'col' is not a literal but a variable:

print(templ.format(**locals()))

I get an error: KeyError: 'col'

But I can't use f-string in this case because I define templ before I get cur_cols_dct and col variables.

Is there any way to get value from dictionary when both dictionary and key value are variables by using format(**locals())? Or what can I use instead of format?

10
  • 1
    **locals() doesn't include global variables. Commented Jun 21, 2024 at 20:49
  • Why do you want to define templ before cur_cols_dct? Why not do it afterwards with an f-string just as you said? Commented Jun 21, 2024 at 20:50
  • @quamrana It looks like he wants to define the template once, then use it repeatedly as the variables it references change. Commented Jun 21, 2024 at 20:51
  • 1
    The problem with what you're trying to do is that format() just does simple variable replacement, it doesn't evaluate expressions like f-strings do. cur_cols_dct[col] is an expression. Commented Jun 21, 2024 at 20:51
  • 1
    why not keep it as templ = "COMMENT IS '{}'" and later do directly templ.format(cur_cols_dct[col]) or templ.format(any_other_value) without using locals(). You can even use it in loop - for value in some_data: print(templ.format(valuie)) - but if you want to do something more complex then maybe use templates jinja Commented Jun 21, 2024 at 21:18

3 Answers 3

1

You're attempting to use str.format as if it were a fully functional template language, which it is not. However, you can perform the details while passing arguments to it.

template = "COMMENT IS '{comment}'"
cur_cols_dct = {'art_id': 'ID of article'}
col = 'art_id'
print(template.format(comment=cur_cols_dct[col]))

COMMENT IS 'ID of article'

Here is the documentation for str.format()
https://docs.python.org/3/library/stdtypes.html#str.format

There is a string.Template class in the standard library, but I've only used django templates in python.

Sign up to request clarification or add additional context in comments.

3 Comments

Yes, thank you, I knew that I can do it like this, but in real I have more than one variable in my string and using locals could be a better solution. I also can set a variable comment before format and still use locals, but I have to do it every time before I use this template. Probably I will do it if I won't find something more elegant
I have a working demo of using the original template to generate another template which then prints the desired result, but I didn't post it because you don't know, in general, how many levels of indirection you need. You do know you need a comment, and you can write a function that generates the expected context for your template.
Would you consider it more elegant to say template.format(generate_context(**locals()))? I can edit this to look like that -- it's the same thing really.
1

Just do something like:

def format_template(cur_cols_dct, col):
    return f"COMMENT IS '{cur_cols_dct[col]}'"

print(format_template(some_dict, some_col))

Comments

-2
eval(f'f"""{templ}"""')

Or as a function:

def fstr(template):
    return eval(f'f"""{template}"""')

All credit to kadee here. (The function as written in the answer doesn't work for your f-string containing quotes--it needs the multiline """ string delimiter. I've submitted an edit to the answer)

6 Comments

why would you do this?
Oh wow, that is simultaneously brilliant and horrifying. Does it work with ast.literal_eval? It doesn't seem to have access to the caller's locals when I test this.
@juanpa.arrivillaga because it accomplishes what OP wants without them needing to modify their code. I'm just proposing one possible method, OP is free to choose any implementation
@KennyOstrom no, it doesn't
reading the linked answer, it apparently only allows the fstring to reference global variables, but we know OP wants locals()
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.