15 puntos por GN⁺ 2025-04-22 | 2 comentarios | Compartir por WhatsApp
  • Los t-strings (cadenas t) son una nueva función de procesamiento de cadenas segura y flexible introducida en Python 3.14
  • A diferencia de los f-strings tradicionales, un t-string devuelve un objeto Template en lugar de una cadena, lo que permite un procesamiento seguro sin salida automática
  • Los t-strings tienen una estructura que permite escapar de forma segura entradas dinámicas como HTML, SQL y más
  • Es un concepto similar a los tagged templates de JavaScript, por lo que permite diversas extensiones de transformación y procesamiento
  • Si el ecosistema de herramientas para desarrolladores de Python da buen soporte a esta función, podría generar un gran cambio en el procesamiento de cadenas orientado a web/seguridad

Nueva función de Python: t-strings (Template Strings)

  • A partir de Python 3.14, las Template strings (t-strings) usadas con la sintaxis t"..." se incorporan como función oficial
  • A diferencia de los f-strings existentes, un t-string se evalúa como un objeto string.templatelib.Template en lugar de convertirse inmediatamente en una cadena
  • Este objeto requiere un proceso de transformación separado antes de mostrarse, y mediante ese proceso es posible el manejo y la conversión seguros de valores dinámicos

¿Por qué un f-string puede ser riesgoso?

  • Como un f-string se evalúa inmediatamente como cadena, puede provocar SQL Injection o XSS en código que incluya entrada del usuario
    • Ejemplo: f"<div>{user_input}</div>" → el código malicioso puede insertarse directamente
  • Un t-string retrasa esa evaluación, haciendo que solo pueda usarse tras un procesamiento explícito

Ejemplos de uso de t-strings

  • Ejemplo de escape de HTML:

    evil = "<script>alert('bad')</script>"  
    template = t"<p>{evil}</p>"  
    safe = html(template)  
    # safe es "<p>&lt;script&gt;alert('bad')&lt;/script&gt;</p>"  
    
  • También es posible un procesamiento más complejo, como la inserción automática de atributos:

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

Estructura y API

  • El objeto Template ofrece el texto original y los valores interpolados por separado mediante las propiedades .strings y .values

  • A través de la propiedad interpolations, también se puede acceder a detalles de formato como !s, :>8 y más

  • Mediante la iteración, también es posible procesar directamente estados donde se mezclan texto y valores

  • También puede crearse manualmente:

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

Ejemplo curioso: convertidor a Pig Latin

  • Un ejemplo que recorre el contenido de un objeto Template y convierte las palabras a Pig Latin:

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

Dirección futura

  • Los t-strings pueden aportar seguridad y extensibilidad al procesamiento de cadenas orientado a web/seguridad
  • Se espera que herramientas de desarrollo como black, ruff y VS Code soporten el formato y resaltado de t-strings
  • Como se parecen al enfoque de tagged templates familiar para desarrolladores de JavaScript, también tienen alto potencial de uso en varios frameworks

Colaboración con la comunidad de desarrolladores

  • Esta función se completó gracias a la participación y colaboración de diversos miembros de la comunidad de Python
  • Se mencionan en particular intercambios con figuras clave como Jim, Paul, Koudai, Lysandros y Guido
  • El PEP 750 y su repositorio de ejemplos pueden consultarse en GitHub

La función de t-strings de Python 3.14 logra al mismo tiempo seguridad y extensibilidad en las cadenas, y representa un avance importante que supera las limitaciones de los f-strings existentes

2 comentarios

 
GN⁺ 2025-04-22
Comentarios de Hacker News
  • En general, esta función está bastante genial. Básicamente cambia código como este

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

    por esto

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

    Hay una duda sobre si este azúcar sintáctico aporta lo suficiente como para justificar la complejidad de una nueva función del lenguaje. Creo que en este caso sí, por dos razones

    • Es bueno permitir que los desarrolladores de librerías hagan lo que quieran mediante la expansión de {}, y eso probablemente genere buenos casos de uso
    • Generalizar la sintaxis de plantillas en todo el lenguaje para que todas las librerías resuelvan el problema de la misma manera probablemente también sea algo bueno
  • También espero que el ecosistema de herramientas se adapte para soportar t-strings. Por ejemplo, estaría bien que black y ruff formatearan el contenido de los t-strings, y que vscode resaltara con colores contenidos de tipos comunes como HTML o SQL

    • Esta perspectiva sobre los t-strings es muy extraña. La única forma de inferir que una cadena de plantilla debería convertirse en HTML o SQL válido sería basarse en la sintaxis aparente de la cadena, y eso solo se podría hacer como un parche improvisado, no tiene relación con la funcionalidad de cadenas de plantilla
    • En la forma en que está diseñada la función, no hay ninguna indicación en la propia cadena sobre qué tipo de contenido es ni en qué terminará convirtiéndose. Todo lo maneja la función de transformación
    • Como agregaron otros, algo como sql”select * from {table}” podría haber hecho esto, pero aun así no habría garantía de que lo que está en la plantilla se convierta en SQL válido por la función de transformación. t“give me {table} but only {columns}” podría convertirse en SQL válido después de procesar la plantilla
  • ¿Se podría usar una sintaxis SQL tan limpia como esta?

    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 función db.get() acepta plantillas, entonces sí. Sería la forma más limpia de usar SQL que he visto hasta ahora

  • Personalmente, siento que esta función está demasiado enfocada en un problema específico como para volverse una función general. Python cada vez es más grande. Cuando la gente pregunta si Python es fácil de aprender y simple, hay que responder: “lo básico sí, pero aprender todo el lenguaje no”

    • En ese sentido, Go resulta interesante porque rechaza casi cualquier funcionalidad. Sinceramente, no estoy seguro de que los genéricos valgan la pena porque añaden mucha complejidad. Creo que la idea general de mantener el lenguaje enfocado en su propósito original es correcta. C++ sería un caso extremo donde el lenguaje ya casi no se parece a lo que era cuando empezó
  • Gran discusión (414 puntos, hace 10 días, 324 comentarios) enlace

  • Bastante genial. Si van a portar funciones de JS, ¿entonces lo siguiente podría ser unpacking/destructuring de diccionarios?

    • Quiero muchísimo esta función. Es la razón principal por la que vuelvo a JS
    >>> {a, b=45, c=None, **d} = {'a': 234, xzy: 32456}
    >>> print(a, b, c, d)
    234 45 None {'xyz': 32456}
    
  • Se siente como una “trampa” que solo la nueva función x-string venga integrada. Estaría genial si se pudiera hacer algo como esto

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

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

    Formateo de cadenas en Python en 2025:

    • t-strings
    • f-strings
    • operador %
    • operador +
    • str.format()
  • No entiendo en qué se diferencia aplicar una función a la plantilla de aplicar la función a una variable dentro de un f-string. Entonces, en lugar de esto:

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

    ¿por qué no simplemente hacer esto?

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

    O antes de crear el f-string. ¿Es simplemente para que no olvides la parte de sanitización/manipulación de cadenas y te obligue a pasar por ella?

  • ¡Hola! Yo escribí esta publicación :-)

    • Llegué un poco tarde a la conversación y me sorprendió un poco ver que este post se volvió tendencia en HN, pero con gusto responderé preguntas. Voy a intentar participar durante el día en mis ratos libres