Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

164
Vistas
How to postpone/defer the evaluation of f-strings?

I am using template strings to generate some files and I love the conciseness of the new f-strings for this purpose, for reducing my previous template code from something like this:

template_a = "The current name is {name}"
names = ["foo", "bar"]
for name in names:
    print (template_a.format(**locals()))

Now I can do this, directly replacing variables:

names = ["foo", "bar"]
for name in names:
    print (f"The current name is {name}")

However, sometimes it makes sense to have the template defined elsewhere — higher up in the code, or imported from a file or something. This means the template is a static string with formatting tags in it. Something would have to happen to the string to tell the interpreter to interpret the string as a new f-string, but I don't know if there is such a thing.

Is there any way to bring in a string and have it interpreted as an f-string to avoid using the .format(**locals()) call?

Ideally I want to be able to code like this... (where magic_fstring_function is where the part I don't understand comes in):

template_a = f"The current name is {name}"
# OR [Ideal2] template_a = magic_fstring_function(open('template.txt').read())
names = ["foo", "bar"]
for name in names:
    print (template_a)

...with this desired output (without reading the file twice):

The current name is foo
The current name is bar

...but the actual output I get is:

The current name is {name}
The current name is {name}
over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Here's a complete "Ideal 2".

It's not an f-string—it doesn't even use f-strings—but it does as requested. Syntax exactly as specified. No security headaches since we are not using eval().

It uses a little class and implements __str__ which is automatically called by print. To escape the limited scope of the class we use the inspect module to hop one frame up and see the variables the caller has access to.

import inspect

class magic_fstring_function:
    def __init__(self, payload):
        self.payload = payload
    def __str__(self):
        vars = inspect.currentframe().f_back.f_globals.copy()
        vars.update(inspect.currentframe().f_back.f_locals)
        return self.payload.format(**vars)

template = "The current name is {name}"

template_a = magic_fstring_function(template)

# use it inside a function to demonstrate it gets the scoping right
def new_scope():
    names = ["foo", "bar"]
    for name in names:
        print(template_a)

new_scope()
# The current name is foo
# The current name is bar
over 4 years ago · Santiago Trujillo Denunciar

0

A concise way to have a string evaluated as an f-string (with its full capabilities) is using following function:

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

Then you can do:

template_a = "The current name is {name}"
names = ["foo", "bar"]
for name in names:
    print(fstr(template_a))
# The current name is foo
# The current name is bar

And, in contrast to many other proposed solutions, you can also do:

template_b = "The current name is {name.upper() * 2}"
for name in names:
    print(fstr(template_b))
# The current name is FOOFOO
# The current name is BARBAR
over 4 years ago · Santiago Trujillo Denunciar

0

This means the template is a static string with formatting tags in it

Yes, that's exactly why we have literals with replacement fields and .format, so we can replace the fields whenever we like by calling format on it.

Something would have to happen to the string to tell the interpreter to interpret the string as a new f-string

That's the prefix f/F. You could wrap it in a function and postpone the evaluation during call time but of course that incurs extra overhead:

template_a = lambda: f"The current name is {name}"
names = ["foo", "bar"]
for name in names:
    print (template_a())

Which prints out:

The current name is foo
The current name is bar

but feels wrong and is limited by the fact that you can only peek at the global namespace in your replacements. Trying to use it in a situation which requires local names will fail miserably unless passed to the string as arguments (which totally beats the point).

Is there any way to bring in a string and have it interpreted as an f-string to avoid using the .format(**locals()) call?

Other than a function (limitations included), nope, so might as well stick with .format.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda