15 điểm bởi GN⁺ 2025-04-22 | 2 bình luận | Chia sẻ qua WhatsApp
  • t-string (chuỗi mẫu)tính năng xử lý chuỗi an toàn và linh hoạt mới được giới thiệu trong Python 3.14
  • Khác với f-string hiện có, t-string trả về đối tượng Template thay vì chuỗi, nên có thể xử lý an toàn mà không tự động xuất ra ngay
  • t-string có cấu trúc cho phép escape an toàn dữ liệu đầu vào động như HTML, SQL, v.v.
  • Đây là khái niệm tương tự tagged templates của JavaScript, cho phép mở rộng nhiều kiểu biến đổi và xử lý khác nhau
  • Nếu hệ sinh thái công cụ phát triển Python hỗ trợ tốt tính năng này, nó có thể tạo ra thay đổi lớn trong cách xử lý chuỗi theo hướng web/bảo mật

Tính năng mới của Python: t-string (Template Strings)

  • Từ Python 3.14, chuỗi Template (t-strings) dùng cú pháp t"..." sẽ được đưa vào như một tính năng chính thức
  • Khác với f-string hiện có, t-string được đánh giá thành đối tượng string.templatelib.Template chứ không phải chuỗi ngay lập tức
  • Đối tượng này cần một bước xử lý riêng trước khi xuất ra, và thông qua bước đó có thể xử lý, chuyển đổi giá trị động một cách an toàn

Vì sao f-string có thể nguy hiểm?

  • Vì f-string được đánh giá thành chuỗi ngay lập tức, trong mã có chứa đầu vào người dùng có thể phát sinh SQL Injection hoặc XSS
    • Ví dụ: f"<div>{user_input}</div>" → mã tấn công có thể bị chèn trực tiếp
  • t-string trì hoãn việc đánh giá này, khiến nó chỉ có thể được sử dụng sau khi đã xử lý một cách tường minh

Ví dụ sử dụng t-string

  • Ví dụ xử lý escape HTML:

    evil = "<script>alert('bad')</script>"  
    template = t"<p>{evil}</p>"  
    safe = html(template)  
    # safe는 "<p>&lt;script&gt;alert('bad')&lt;/script&gt;</p>"  
    
  • Cũng có thể xử lý phức tạp hơn như tự động chèn thuộc tính:

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

Cấu trúc và API

  • Đối tượng Template cung cấp riêng văn bản gốc và các giá trị nội suy thông qua thuộc tính .strings, .values

  • Qua thuộc tính interpolations, có thể truy cập cả chi tiết định dạng như !s, :>8

  • Thông qua iteration, cũng có thể trực tiếp xử lý trạng thái trộn giữa văn bản và giá trị

  • Cũng có thể tạo thủ công:

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

Ví dụ thú vị: bộ chuyển đổi Pig Latin

  • Ví dụ biến đổi các từ trong nội dung của đối tượng Template sang Pig Latin bằng cách duyệt qua nó:

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

Hướng phát triển trong tương lai

  • t-strings có thể mang lại tính an toàn và khả năng mở rộng cho cách xử lý chuỗi theo hướng web/bảo mật
  • Kỳ vọng các công cụ phát triển như black, ruff, VS Code sẽ hỗ trợ định dạng/highlighting cho t-string
  • Vì tương tự cách tagged template mà các lập trình viên JavaScript đã quen thuộc, nó cũng có tiềm năng được ứng dụng trong nhiều framework

Hợp tác với cộng đồng lập trình viên

  • Tính năng này được hoàn thiện nhờ sự tham gia và hợp tác của nhiều thành viên trong cộng đồng Python
  • Đặc biệt có nhắc đến việc trao đổi với các nhân vật chủ chốt như Jim, Paul, Koudai, Lysandros và Guido
  • Có thể xem PEP 750 và kho ví dụ của nó trên GitHub

Tính năng t-string của Python 3.14 đồng thời đảm bảo tính an toàn và khả năng mở rộng cho chuỗi, là một bước tiến quan trọng vượt qua giới hạn của f-string hiện có

2 bình luận

 
GN⁺ 2025-04-22
Ý kiến Hacker News
  • Nhìn chung, tính năng này khá hay. Về cơ bản, nó biến đoạn mã như sau

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

    thành

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

    Có một câu hỏi là liệu lớp "đường" cú pháp này có đủ lợi ích để biện minh cho sự phức tạp của một tính năng ngôn ngữ mới hay không. Tôi nghĩ là có trong trường hợp này vì hai lý do

    • Việc cho phép các nhà phát triển thư viện làm điều họ muốn thông qua mở rộng `{}`` là điều tốt, và có khả năng tạo ra các trường hợp sử dụng hay
    • Việc khái quát hóa cú pháp template trên toàn ngôn ngữ để mọi thư viện giải quyết vấn đề theo cùng một cách có lẽ là điều tốt
  • Tôi cũng hy vọng hệ sinh thái công cụ sẽ thích nghi để hỗ trợ t-strings. Ví dụ, sẽ rất tốt nếu black và ruff có thể định dạng nội dung t-string, và vscode có thể tô màu các kiểu nội dung phổ biến như HTML hoặc SQL

    • Cách nhìn này về t-strings khá kỳ lạ. Cách duy nhất để suy ra rằng một template string phải được chuyển thành HTML hoặc SQL hợp lệ là dựa trên cú pháp bề ngoài của chuỗi, điều này cùng lắm chỉ làm tạm được và không liên quan đến tính năng template string
    • Với cách tính năng này được thiết kế, không có dấu hiệu nào trên chính chuỗi cho biết đó là loại nội dung gì hoặc cuối cùng nó sẽ được chuyển thành gì. Mọi thứ đều do hàm chuyển đổi xử lý
    • Như những người khác đã bổ sung, kiểu như sql”select * from {table}” có thể làm được việc này, nhưng cũng không có gì đảm bảo rằng nội dung trong template sẽ được hàm chuyển đổi biến thành SQL hợp lệ. t“give me {table} but only {columns}” vẫn có thể được chuyển thành SQL hợp lệ sau khi template được xử lý
  • Có thể dùng cú pháp SQL gọn gàng như sau không?

    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}
    ')
    

    Nếu hàm db.get() chấp nhận template thì có thể. Đây sẽ là cách dùng SQL gọn gàng nhất mà tôi từng thấy cho đến nay

  • Cá nhân tôi thấy tính năng này tập trung quá nhiều vào một vấn đề cụ thể để trở thành tính năng phổ dụng. Python đang ngày càng phình to. Khi người ta hỏi liệu Python có dễ học và đơn giản không, tôi phải trả lời rằng "phần cơ bản thì có, nhưng để học toàn bộ ngôn ngữ thì không"

    • Xét ở khía cạnh này thì Go khá thú vị vì gần như từ chối mọi tính năng. Thành thật mà nói, tôi không chắc generics có đáng giá hay không vì nó thêm rất nhiều độ phức tạp. Tôi nghĩ ý tưởng chung là giữ ngôn ngữ bám vào trọng tâm ban đầu của nó là đúng. C++ có lẽ là trường hợp cực đoan, nơi bản thân ngôn ngữ gần như không còn giống lúc mới bắt đầu
  • Cuộc thảo luận lớn (414 điểm, 10 ngày trước, 324 bình luận) liên kết

  • Khá hay. Nếu đang port các tính năng từ JS, liệu tiếp theo chúng ta có thể có dictionary unpacking/destructuring không?

    • Tôi cực kỳ muốn có tính năng này. Đây là lý do chính khiến tôi quay lại JS
    >>> {a, b=45, c=None, **d} = {'a': 234, xzy: 32456}
    >>> print(a, b, c, d)
    234 45 None {'xyz': 32456}
    
  • Việc chỉ tích hợp sẵn tính năng x-string mới khiến nó có cảm giác như một "mánh". Sẽ rất hay nếu có thể làm như thế này

    from foo import bar
    bar"zoop"
    
  • Zen of Python năm 2025:

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

    Định dạng chuỗi trong Python năm 2025:

    • t-strings
    • f-strings
    • %-operator
    • +-operator
    • str.format()
  • Tôi không hiểu nó khác gì so với việc áp dụng hàm lên biến trong f-string. Vậy nên thay vì:

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

    tại sao không đơn giản làm thế này:

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

    Hoặc làm trước khi tạo f-string. Chỉ là để bạn không quên phần làm sạch/thao tác chuỗi và buộc phải đi qua bước đó thôi sao?

  • Xin chào! Tôi là người đã viết bài này :-)

    • Tôi vào cuộc trò chuyện hơi muộn và cũng khá bất ngờ khi thấy bài này thành xu hướng trên HN, nhưng tôi rất sẵn lòng trả lời câu hỏi. Tôi sẽ cố gắng tham gia rải rác trong ngày