15 points par GN⁺ 2025-04-22 | 2 commentaires | Partager sur WhatsApp
  • Les t-strings sont une nouvelle fonctionnalité de traitement de chaînes sûre et flexible introduite dans Python 3.14
  • Contrairement aux f-strings existantes, une t-string renvoie un objet Template plutôt qu’une chaîne, ce qui permet un traitement sûr sans rendu automatique
  • Les t-strings reposent sur une structure permettant d’échapper en toute sécurité des entrées dynamiques comme en HTML ou en SQL
  • Le concept est similaire aux tagged templates de JavaScript, avec des possibilités d’extension pour diverses transformations et traitements
  • Si l’écosystème des outils de développement Python prend bien en charge cette fonctionnalité, elle pourrait profondément faire évoluer le traitement des chaînes orienté web/sécurité

Nouvelle fonctionnalité de Python : les t-strings (Template Strings)

  • À partir de Python 3.14, les Template strings (t-strings) utilisées avec la syntaxe t"..." sont introduites comme fonctionnalité officielle
  • Contrairement aux f-strings existantes, une t-string est évaluée non pas immédiatement en chaîne, mais en objet string.templatelib.Template
  • Cet objet nécessite une étape de transformation distincte avant affichage, ce qui permet un traitement et une conversion sûrs des valeurs dynamiques

Pourquoi les f-strings peuvent-elles être risquées ?

  • Comme une f-string est évaluée immédiatement en chaîne, du code incluant des entrées utilisateur peut provoquer une injection SQL ou du XSS
    • Exemple : f"<div>{user_input}</div>" → du code malveillant peut être injecté directement
  • Les t-strings retardent cette évaluation, de sorte qu’elles ne peuvent être utilisées qu’après un traitement explicite

Exemples d’utilisation des t-strings

  • Exemple de traitement avec échappement HTML :

    evil = "<script>alert('bad')</script>"  
    template = t"<p>{evil}</p>"  
    safe = html(template)  
    # safe vaut "<p>&lt;script&gt;alert('bad')&lt;/script&gt;</p>"  
    
  • Des traitements plus complexes, comme l’insertion automatique d’attributs, sont également possibles :

    attributes = {"src": "roquefort.jpg", "alt": "Yum"}  
    template = t"<img {attributes} />"  
    element = html(template)  
    # résultat : "<img src='roquefort.jpg' alt='Yum' />"  
    

Structure et API

  • L’objet Template fournit séparément le texte d’origine et les valeurs interpolées via les attributs .strings et .values

  • L’attribut interpolations permet d’accéder jusqu’aux détails de formatage comme !s, :>8, etc.

  • Il est aussi possible de parcourir l’objet pour traiter directement un état mêlant texte et valeurs

  • Création manuelle également possible :

    from string.templatelib import Template, Interpolation  
    template = Template(  
      "Hello ",  
      Interpolation(value="World", expression="name"),  
      "!"  
    )  
    

Exemple amusant : un convertisseur en Pig Latin

  • Exemple qui parcourt le contenu d’un objet Template pour transformer les mots en Pig Latin :

    def pig_latin(template: Template) -> str:  
        ...  
    name = "world"  
    template = t"Hello {name}!"  
    assert pig_latin(template) == "Hello orldway!"  
    

Perspectives

  • Les t-strings peuvent apporter sécurité et extensibilité au traitement des chaînes orienté web/sécurité
  • On peut espérer que des outils comme black, ruff et VS Code prendront en charge le formatage et la coloration des t-strings
  • Le mécanisme est proche des tagged templates familiers aux développeurs JavaScript, ce qui lui donne un fort potentiel d’adoption dans divers frameworks

Collaboration avec la communauté des développeurs

  • Cette fonctionnalité a été finalisée grâce à la participation et à la collaboration de nombreux membres de la communauté Python
  • Sont notamment mentionnés les échanges avec Jim, Paul, Koudai, Lysandros et Guido, parmi les personnes clés
  • Le PEP 750 et son dépôt d’exemples sont disponibles sur GitHub

La fonctionnalité de t-strings de Python 3.14 constitue une avancée majeure qui assure à la fois la sécurité et l’extensibilité des chaînes, tout en dépassant les limites des f-strings existantes

2 commentaires

 
GN⁺ 2025-04-22
Avis Hacker News
  • Globalement, cette fonctionnalité est plutôt sympa. En gros, elle transforme un code comme

    db.execute("QUERY WHERE name = ?", (name,))
    

    en

    db.execute(t"QUERY WHERE name = {name}")
    

    On peut se demander si ce sucre syntaxique apporte assez pour justifier la complexité d’une nouvelle fonctionnalité du langage. Je pense que oui dans ce cas, pour deux raisons

    • c’est une bonne chose de permettre aux développeurs de bibliothèques de faire ce qu’ils veulent via l’expansion de {}, et cela pourrait donner lieu à de bons cas d’usage
    • généraliser la syntaxe des templates à l’échelle du langage, afin que toutes les bibliothèques résolvent le problème de la même manière, est probablement une bonne chose
  • J’espère aussi que l’écosystème d’outils s’adaptera pour prendre en charge les t-strings. Par exemple, ce serait bien que black et ruff formatent le contenu des t-strings, et que vscode colore le contenu pour des types courants comme le HTML ou le SQL

    • cette vision des t-strings est très étrange. La seule manière d’inférer qu’une chaîne template devrait se transformer en HTML ou SQL valide serait de se baser sur la syntaxe apparente de la chaîne, ce qui ne peut fonctionner que comme pis-aller et n’a rien à voir avec la fonctionnalité des chaînes template
    • dans la manière dont la fonctionnalité a été conçue, rien dans la chaîne elle-même n’indique de quel type de contenu il s’agit, ni en quoi elle sera finalement transformée. Tout est géré par la fonction de transformation
    • comme d’autres l’ont ajouté, quelque chose comme sql”select * from {table}” aurait pu permettre cela, mais rien ne garantit non plus que ce qui est dans le template sera transformé en SQL valide par la fonction de transformation. t“give me {table} but only {columns}” pourrait être transformé en SQL valide après traitement du template
  • Pourrait-on utiliser une syntaxe SQL aussi propre que celle-ci ?

    city = 'London'
    min_age = 21
    # Find all users in London who are 21 or older:
    users = db.get(t'
      SELECT * FROM users
      WHERE city={city} AND age>{min_age}
    ')
    

    Si la fonction db.get() accepte les templates, alors oui. Ce serait la manière la plus propre d’utiliser du SQL que j’aie vue jusqu’ici

  • Personnellement, j’ai l’impression que cette fonctionnalité est trop centrée sur un problème très spécifique pour devenir une fonctionnalité générale. Python devient de plus en plus gros. Quand les gens demandent si Python est facile à apprendre et simple, il faut répondre « les bases, oui, mais apprendre l’ensemble du langage, non »

    • à cet égard, Go est intéressant parce qu’il refuse pratiquement toute nouvelle fonctionnalité. Honnêtement, je ne suis pas sûr que les generics valent le coup vu toute la complexité qu’ils ajoutent. Je pense que l’idée générale de garder le langage aligné sur son objectif d’origine est juste. C++ serait probablement le cas extrême, au point que le langage ne ressemble presque plus à ce qu’il était au départ
  • Grosse discussion (414 points, il y a 10 jours, 324 commentaires) lien

  • Plutôt sympa. Si on porte des fonctionnalités de JS, est-ce qu’on pourrait avoir ensuite le dépaquetage/destructuring des dictionnaires ?

    • je veux tellement cette fonctionnalité. C’est la raison principale pour laquelle je retourne vers JS
    >>> {a, b=45, c=None, **d} = {'a': 234, xzy: 32456}
    >>> print(a, b, c, d)
    234 45 None {'xyz': 32456}
    
  • Le simple fait d’avoir une nouvelle fonctionnalité x-string intégrée donne l’impression d’un « gadget ». Ce serait cool si on pouvait faire quelque chose comme

    from foo import bar
    bar"zoop"
    
  • Zen of Python en 2025 :

    There should be one-- and preferably only one --obvious way to do it.
    

    Le formatage de chaînes en Python en 2025 :

    • t-strings
    • f-strings
    • opérateur %
    • opérateur +
    • str.format()
  • Je ne comprends pas en quoi cela diffère du fait d’appliquer la fonction au template en l’appliquant à la variable dans une f-string. Donc, au lieu de faire :

    evil = "<script>alert('bad')</script>"
    template = t"{evil}"
    safe = html(template)
    

    pourquoi ne pas simplement faire ceci :

    evil = "<script>alert('bad')</script>"
    safe = f"{html(evil)}"
    

    Ou bien avant de construire la f-string. Est-ce simplement pour éviter d’oublier l’étape d’assainissement/manipulation de chaîne et forcer son passage ?

  • Bonjour ! C’est moi qui ai écrit cet article :-)

    • je rejoins la conversation un peu tard, et j’ai été un peu surpris de voir ce billet devenir tendance sur HN, mais je répondrai volontiers aux questions. Je vais essayer de participer par intermittence tout au long de la journée