150 votes

Puis-je reporter / différer l'évaluation des cordes f?

Je suis à l'aide de chaînes du modèle pour générer des fichiers et j'aime la concision de la nouvelle f-chaînes à cet effet, pour réduire mon précédent modèle de code à partir de quelque chose comme ceci:

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

Maintenant, je peux le faire directement en remplaçant les variables:

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

Cependant, parfois, il est logique d'avoir le modèle défini ailleurs, plus haut dans le code, ou importées à partir d'un fichier ou quelque chose. Cela signifie que le modèle est une chaîne statique avec les balises de mise en forme en elle. Quelque chose devrait se produire à la chaîne pour dire à l'interprète la chaîne comme un nouveau f-chaîne, mais je ne sais pas si une telle chose existe.

Est-il possible de l'amener dans une chaîne de caractères et l'ont interprété comme un f-chaîne pour éviter à l'aide de l' .format(**locals()) appel?

Idéalement, je veux être capable de code comme celui-ci... (où magic_fstring_function est là que la partie que je ne comprends pas vient en):

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)

...avec cette sortie désirée (sans lire le fichier deux fois):

The current name is foo
The current name is bar

... mais le résultat réel que je reçois est:

The current name is {name}
The current name is {name}

40voto

Paul Panzer Points 30707

Voici un "Idéal 2" complet.

Ce n'est pas une chaîne de caractères, elle n'utilise même pas de chaînes de caractères. Mais c'est comme demandé. Syntaxe exactement comme spécifiée. Aucun problème de sécurité, car nous n'utilisons pas eval.

Il utilise un peu de classe et implémente __str__ qui est automatiquement appelé par print. Pour échapper à l'étendue limitée de la classe, nous utilisons le module inspect pour sauter d'une image à la fois et voir les variables auxquelles l'appelant a accès.

 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
 

33voto

kadee Points 211

Une manière concise d’avoir une chaîne évaluée comme une chaîne f (avec toutes ses capacités) utilise la fonction suivante:

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

Ensuite, vous pouvez faire:

 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
 

Et, contrairement à beaucoup d'autres solutions proposées, vous pouvez également faire:

 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
 

29voto

Jim Points 8793

Cela signifie que le modèle est une chaîne statique avec les balises de mise en forme en elle

Oui, c'est exactement pourquoi nous avons littéraux avec le remplacement des champs et des .format, donc nous pouvons remplacer les champs à chaque fois que nous aimons en appelant format sur il.

Quelque chose devrait se produire à la chaîne pour dire à l'interprète la chaîne comme un nouveau f-chaîne

C'est le préfixe f/F. Vous peut encapsuler dans une fonction et de reporter l'évaluation lors de l'appel du temps, mais bien sûr, qui engage des frais généraux supplémentaires:

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

Ce qui affichera:

The current name is foo
The current name is bar

mais se sent mal et est limitée par le fait que vous ne pouvez coup d'oeil à l'espace de noms global de votre remplacement. Essayez de l'utiliser dans une situation qui exige de les noms locaux échouent lamentablement à moins transmis à la chaîne comme des arguments (qui a totalement bat le point).

Est-il possible de l'amener dans une chaîne de caractères et l'ont interprété comme un f-chaîne pour éviter à l'aide de l' .format(**locals()) appel?

Autre qu'une fonction (limites comprises), nope, alors peut-être ainsi bâton avec .format.

13voto

TigerhawkT3 Points 25584

Un f-chaîne est simplement une manière plus concise de la création d'une chaîne formatée, en remplaçant .format(**names) avec f. Si vous ne voulez pas une chaîne pour être immédiatement évaluée dans une telle manière, ne pas en faire un f-chaîne. L'enregistrer comme une chaîne ordinaire littérale, puis appelez format sur plus tard, lorsque vous souhaitez effectuer l'interpolation, comme vous l'avez fait.

Bien sûr, il existe une alternative avec eval.

template.txt:

f ' de l'actuel nom est {nom}'

Code:

>>> template_a = open('template.txt').read()
>>> names = 'foo', 'bar'
>>> for name in names:
...     print(eval(template_a))
...
The current name is foo
The current name is bar

Mais alors tout ce que vous avez réussi à faire est de remplacer str.format avec eval, ce qui est sûrement pas la peine. Il suffit de garder en utilisant des chaînes de caractères avec un format appel.

5voto

MySZ Points 143

Ou peut-être n'utilisez pas de chaînes de caractères, mais simplement le format:

 fun = "The curent name is {name}".format
names = ["foo", "bar"]
for name in names:
    print(fun(name=name))
 

En version sans nom:

 fun = "The curent name is {}".format
names = ["foo", "bar"]
for name in names:
    print(fun(name))
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X