87 votes

Chaînes f imbriquées

Merci à Le tweet de David Beazley J'ai récemment découvert que la nouvelle Python 3.6 f-strings peuvent également être imbriqués :

>>> price = 478.23
>>> f"{f'${price:0.2f}':*>20s}"
'*************$478.23'

Ou :

>>> x = 42
>>> f'''-{f"""*{f"+{f'.{x}.'}+"}*"""}-'''
'-*+.42.+*-'

Bien que je sois surpris que cela soit possible, je me demande à quel point c'est pratique, quand l'imbrication des chaînes f serait-elle utile ? Quels cas d'utilisation cela peut-il couvrir ?

Remarque : La PEP elle-même ne mentionne pas l'imbrication des chaînes de caractères f, mais il existe un fichier scénario de test spécifique .

5 votes

Probablement dans le même but que l'emboîtement des anciens. str.format : stackoverflow.com/questions/40245650/

1 votes

Un autre bon aquí . Je vous laisse le soin de décider si vous voulez duper le marteau.

1 votes

@TigerhawkT3 merci pour ces bons exemples ! Je ne suis pas sûr qu'il s'agisse de doublons directs mais c'est tout à fait pertinent - en ce qui concerne la fermeture j'accepterai ce que la communauté décidera. J'espère aussi qu'il y a peut-être quelque chose de spécifique aux cordes F ici. Nous devrions probablement donner au sujet du temps et une chance.

93voto

Jim Points 8793

Je ne pense pas que les chaînes littérales formatées permettant l'imbrication (par imbrication, je veux dire f'{f".."}' ) est le résultat d'un examen minutieux des cas d'utilisation possibles, je suis davantage convaincu que c'est simplement autorisé pour qu'ils se conforment à leur spécification.

La spécification indique qu'ils supportent le langage Python complet expressions * entre parenthèses. Il est également précisé qu'un littéral de chaîne formaté n'est en fait qu'une expression qui est évaluée au moment de l'exécution (voir aquí et aquí ). Par conséquent, il n'est logique que d'autoriser un littéral de chaîne formatée comme expression à l'intérieur d'un autre littéral de chaîne formatée, l'interdire reviendrait à nier le support complet des expressions Python.

Le fait que vous ne trouviez pas de cas d'utilisation mentionnés dans la documentation (et que vous ne trouviez que des cas de test dans la suite de tests) est dû au fait qu'il s'agit probablement d'un effet (secondaire) agréable de l'implémentation et non de son cas d'utilisation motivant.


En fait, à deux exceptions près : Une expression vide n'est pas autorisée, et une expression lambda doit être entourée de parenthèses explicites.

2 votes

J'ai bien peur que vous ayez raison, tout à fait d'accord. Je n'ai plus de votes positifs pour aujourd'hui - je reviendrai demain. Merci.

0 votes

@alecxe Je suis presque sûr que des choses farfelues impliquant f-string La nidification va apparaître dans la nature à un moment donné, cependant :-)

0 votes

Yep, j'ai juste eu un cas où j'ai eu besoin de nicher f"…" et je l'ai utilisé pour mon plus grand plaisir. Une raison de plus pour laquelle Python est complètement schnufte !

18voto

Eugene Lisitsky Points 1119

Je suppose que c'est pour passer les paramètres de formatage dans la même ligne et ainsi simplifier Cordes en F l'usage.

Par exemple :

>>> import decimal
>>> width = 10
>>> precision = 4
>>> value = decimal.Decimal("12.34567")
>>> f"result: {value:{width}.{precision}}"
'result:      12.35'

Bien sûr, cela permet aux programmeurs d'écrire du code absolument illisible, mais ce n'est pas le but :)

2 votes

Oui ! str.format a toujours soutenu ce principe, par exemple '{0:.{1}f}'.format(math.pi, 4) es '3.1416' . Si f-string ne pouvait pas supporter ça, eh bien, ce serait nul.

5 votes

Votre exemple ne montre pas une chaîne f imbriquée, juste des accolades imbriquées.

9voto

andrewm4894 Points 487

Je viens de trouver quelque chose de similaire (je pense) et j'ai pensé que je devais le partager.

Mon cas spécifique est une grosse déclaration sql sale où je dois conditionnellement avoir des valeurs très différentes mais certaines chaînes de caractères sont les mêmes (et également utilisées à d'autres endroits).

Voici un exemple rapide de ce que je veux dire. Les colonnes que je sélectionne sont toujours les mêmes (et sont également utilisées dans d'autres requêtes) mais le nom de la table dépend du groupe et n'est pas tel que je puisse le faire en boucle.

Obligation d'inclure mycols=mycols dans str2 à chaque fois me semblait un peu sale quand j'ai plusieurs paramètres de ce type.

Je n'étais pas sûr que cela fonctionnerait, mais j'ai été heureux que ce soit le cas. Pour ce qui est de son caractère pythonique, je ne suis pas vraiment sûr.

mycols='col_a,col_b'

str1 = "select {mycols} from {mytable} where group='{mygroup}'".format(mycols=mycols,mytable='{mytable}',mygroup='{mygroup}')

group = 'group_b'

if group == 'group_a':
    str2 = str1.format(mytable='tbl1',mygroup=group)
elif group == 'group_b':
    str2 = str1.format(mytable='a_very_different_table_name',mygroup=group)

print(str2)

1 votes

Au lieu de substituer {my_table} pour my_table dans le format à la ligne 3, vous pourriez simplement utiliser {{my_table}} dans la chaîne littérale. Le site format convertit ensuite les accolades doubles en accolades simples. Vous auriez donc un code plus court : str1 = "select {mycols} from {{mytable}} where group='{{mygroup}}'".format(mycols=mycols)

3voto

David Points 5710

En travaillant sur un projet personnel, je me suis laissé distraire en écrivant ma propre bibliothèque de bases de données. J'ai découvert une chose :

>>> x = dict(a = 1, b = 2, d = 3)
>>> z = f"""
    UPDATE TABLE 
        bar 
    SET 
        {", ".join([ f'{k} = ?'     for k in x.keys() ])} """.strip()
>>> z
'UPDATE TABLE 
    bar 
SET 
    a = ?, b = ?, d = ?  '

J'ai également été surpris par cela et honnêtement, je ne suis pas sûr de faire quelque chose comme ça dans un code de production MAIS j'ai également dit que je ne ferais pas beaucoup d'autres choses dans un code de production.

0 votes

"Je me suis laissé distraire en écrivant ma propre bibliothèque de bases de données" ha ha ha :) et oui, c'est intéressant, et non, je ne l'utiliserais jamais en production non plus :)

1 votes

@ChristopherMahan J'ai pris ma retraite il y a quelques années et j'ai donc le temps d'explorer des idées parfois mauvaises. Si vous êtes curieux github.com/devdave/dcdb Il y a une longue liste de fonctionnalités manquantes mais c'est très bien ainsi car j'ai le temps de les implémenter ou de les abandonner et de retourner à sqlalchemy.

-3voto

BallpointBen Points 3265

Vous pourriez l'utiliser pour le dynamisme. Par exemple, disons que vous avez une variable définie par le nom d'une fonction :

func = 'my_func'

Alors vous pourriez écrire :

f"{f'{func}'()}" 

ce qui serait équivalent à :

'{}'.format(locals()[func]()) 

ou, de manière équivalente :

'{}'.format(my_func())

0 votes

J'ai essayé et ça n'a pas marché. TypeError: 'str' object is not callable

0 votes

Ce n'est pas vrai. f'{func}' est une chaîne. On ne peut pas appeler des chaînes de caractères.

0 votes

Si vous aimez les trucs peu sûrs comme ceux-là, vous recherchez probablement eval .

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