Nhiều cách định dạng chuỗi của Python - những cách cũ hơn (sẽ bị) không được dùng nữa?


106

Python có ít nhất sáu cách định dạng một chuỗi:

In [1]: world = "Earth"

# method 1a
In [2]: "Hello, %s" % world
Out[2]: 'Hello, Earth'

# method 1b
In [3]: "Hello, %(planet)s" % {"planet": world}
Out[3]: 'Hello, Earth'

# method 2a
In [4]: "Hello, {0}".format(world)
Out[4]: 'Hello, Earth'

# method 2b
In [5]: "Hello, {planet}".format(planet=world)
Out[5]: 'Hello, Earth'

# method 2c
In [6]: f"Hello, {world}"
Out[6]: 'Hello, Earth'

In [7]: from string import Template

# method 3
In [8]: Template("Hello, $planet").substitute(planet=world)
Out[8]: 'Hello, Earth'

Sơ lược về lịch sử của các phương pháp khác nhau:

  • printfđịnh dạng kiểu đã có từ khi Pythons còn nhỏ
  • Các Templatelớp học được giới thiệu vào Python 2.4
  • Các formatphương pháp được giới thiệu vào Python 2.6
  • f-strings được giới thiệu trong Python 3.6

Câu hỏi của tôi là:

  • Định printfdạng -style không được dùng nữa hay sẽ không được dùng nữa?
  • Trong Template class, substitutephương thức không được chấp nhận hay sẽ không được dùng nữa? (Tôi không nói về safe_substituteđiều này, theo tôi hiểu thì nó cung cấp các khả năng độc đáo)

Các câu hỏi tương tự và tại sao tôi nghĩ chúng không trùng lặp:

  • Định dạng chuỗi trong Python:% so với .format - chỉ xử lý các phương pháp 1 và 2 và hỏi phương thức nào tốt hơn; câu hỏi của tôi rõ ràng là về việc không dùng nữa theo Zen of Python

  • Tùy chọn định dạng chuỗi: ưu và nhược điểm - chỉ xử lý các phương pháp 1a và 1b trong câu hỏi, 1 và 2 trong câu trả lời và cũng không có gì về việc không dùng nữa

  • định dạng chuỗi nâng cao so với chuỗi mẫu - chủ yếu là về phương pháp 1 và 3 và không giải quyết việc không dùng nữa

  • Biểu thức định dạng chuỗi (Python) - câu trả lời đề cập rằng phương pháp tiếp cận '%' ban đầu được lên kế hoạch không được dùng nữa . Nhưng sự khác biệt giữa dự kiến ​​sẽ không dùng nữa , đang chờ xử lý và thực tế không dùng nữa là gì? Và printfphương thức kiểu không tăng thậm chí a PendingDeprecationWarning, vì vậy điều này có thực sự không được chấp nhận không? Bài này cũng khá cũ nên thông tin có thể bị lỗi thời.

Xem thêm


1
Tôi có cần chỉ ra rằng bạn quên Formatterlớp học không?
Martijn Pieters

Câu trả lời:


14

Mặc dù có nhiều chỉ dẫn khác nhau trong tài liệu .formatvà chuỗi f vượt trội hơn %chuỗi ký tự, nhưng không có kế hoạch nào còn tồn tại để không bao giờ phản đối cái sau.

Trong cam kết Sự cố # 14123: Đề cập rõ ràng rằng định dạng chuỗi% kiểu cũ có những lưu ý nhưng sẽ không sớm biến mất. , lấy cảm hứng từ sự cố Cho biết rằng không có kế hoạch hiện tại nào để ngừng sử dụng định dạng kiểu printf , các tài liệu về- %format đã được chỉnh sửa để chứa cụm từ này:

Vì cú pháp định dạng chuỗi mới linh hoạt hơn và xử lý các bộ dữ liệu và từ điển một cách tự nhiên, bạn nên sử dụng mã mới. Tuy nhiên, hiện tại không có kế hoạch nào để ngừng định dạng kiểu printf .

(Nhấn mạnh của tôi.)

Cụm từ này đã bị xóa sau đó, trong cam kết Close # 4966: sửa đổi tài liệu trình tự để giải thích rõ hơn trạng thái của Python hiện đại . Điều này có vẻ giống như một dấu hiệu cho thấy kế hoạch ngừng %định dạng đã quay trở lại trên thẻ ... nhưng khi đi sâu vào trình theo dõi lỗi cho thấy mục đích ngược lại. Trên trình theo dõi lỗi, tác giả của cam kết mô tả sự thay đổi như sau :

  • đã thay đổi đoạn văn xuôi mô tả mối quan hệ giữa định dạng kiểu printf và phương thức str.format (cố tình loại bỏ hàm ý rằng phương thức trước là bất kỳ nguy cơ thực sự nào sẽ biến mất - đơn giản là chúng ta không thực tế khi nghiêm túc xem xét việc loại bỏ nó)

Nói cách khác, chúng tôi đã có hai thay đổi liên tiếp đối với %tài liệu định dạng nhằm nhấn mạnh rõ ràng rằng tài liệu này sẽ không bị phản đối, chứ đừng nói là bị xóa. Các tài liệu vẫn kiên định về giá trị tương đối của các loại định dạng chuỗi khác nhau, nhưng chúng cũng rõ ràng rằng định dạng-định dạng %sẽ không bị phản đối hoặc bị loại bỏ.

Hơn nữa, thay đổi gần đây nhất đối với đoạn đó , vào tháng 3 năm 2017, đã thay đổi nó từ đoạn này ...

Các thao tác định dạng được mô tả ở đây cho thấy nhiều lỗi khác nhau dẫn đến một số lỗi phổ biến (chẳng hạn như không hiển thị chính xác các bộ giá trị và từ điển). Sử dụng các ký tự chuỗi được định dạng mới hơn hoặc str.formatgiao diện giúp tránh những lỗi này. Các lựa chọn thay thế này cũng cung cấp các cách tiếp cận mạnh mẽ, linh hoạt và có thể mở rộng hơn để định dạng văn bản.

... đến đây:

Các thao tác định dạng được mô tả ở đây cho thấy nhiều lỗi khác nhau dẫn đến một số lỗi phổ biến (chẳng hạn như không hiển thị chính xác các bộ giá trị và từ điển). Sử dụng các ký tự chuỗi được định dạng mới hơn, str.formatgiao diện hoặc chuỗi mẫu có thể giúp tránh những lỗi này. Mỗi lựa chọn thay thế này cung cấp những đánh đổi và lợi ích của riêng chúng về tính đơn giản, linh hoạt và / hoặc khả năng mở rộng.

Lưu ý sự thay đổi từ "giúp tránh" thành "có thể giúp tránh" và cách khuyến nghị rõ ràng về .formatvà chuỗi f đã được thay thế bằng văn xuôi mượt mà, trang trọng về cách mỗi phong cách "mang lại những đánh đổi và lợi ích riêng" . Có nghĩa là, không chỉ thẻ chính thức không còn nữa, mà các tài liệu hiện tại đang công khai thừa nhận rằng %định dạng ít nhất cũng có một số "lợi ích" so với các phương pháp tiếp cận khác.

Từ tất cả những điều này, tôi suy ra rằng phong trào phản đối hoặc xóa %định dạng không chỉ bị chững lại mà còn bị đánh bại một cách triệt để và vĩnh viễn.


2
Sự thay đổi ngôn ngữ mượt mà đã được thêm vào để xoa dịu những người bảo trì Mercurial (trong số những người khác) không muốn thấy Mercurial bị bỏ lại phía sau với một cơ sở mã quá lớn để loại bỏ việc sử dụng %. Giờ đây, chính sách 'không có mod mã quy mô lớn' đã bị loại bỏ, sự phản đối của họ cũng đang mờ dần. Về lâu dài, việc duy trì cả hai biểu mẫu mà không có lợi ích nào còn lại % tại một thời điểm nào đó , cú pháp printf sẽ bị loại bỏ. Chúng tôi chỉ chưa biết khi nào, và vì vậy ngôn ngữ này có giá trị giảm xuống.
Martijn Pieters

@MartijnPieters Thật thú vị. Có vẻ như bạn có rất nhiều kiến ​​thức về quyết định này mà tôi thiếu. Đối với những gì nó có giá trị, tôi nghĩ rằng một câu trả lời được tham khảo tốt từ bạn nêu ra những điểm này (dưới dạng câu trả lời mới hoặc chỉnh sửa cho câu trả lời hiện có của bạn) sẽ có giá trị.
Mark Amery,

58

.format()Phương thức mới nhằm thay thế %cú pháp định dạng cũ . Sau đó đã được de-nhấn mạnh, (nhưng chưa chính thức phản đối chưa ). Tài liệu phương pháp cho biết càng nhiều:

Phương pháp này của định dạng chuỗi là tiêu chuẩn mới trong Python 3, và nên được ưa thích với %định dạng được mô tả trong chuỗi định dạng hoạt động trong mã mới.

(Nhấn mạnh của tôi).

Để duy trì khả năng tương thích ngược và giúp quá trình chuyển đổi dễ dàng hơn, định dạng cũ đã được giữ nguyên hiện tại . Từ đề xuất PEP 3101 ban đầu :

Tương thích ngược

Khả năng tương thích ngược có thể được duy trì bằng cách giữ nguyên các cơ chế hiện có. Hệ thống mới không xung đột với bất kỳ tên phương thức nào của các kỹ thuật định dạng chuỗi hiện có, vì vậy cả hai hệ thống có thể cùng tồn tại cho đến khi hệ thống cũ không dùng nữa.

Lưu ý đến thời điểm không chấp nhận hệ thống cũ hơn ; nó vẫn chưa bị phản đối, nhưng hệ thống mới sẽ được sử dụng bất cứ khi nào bạn viết mã mới .

Hệ thống mới có một lợi thế là bạn có thể kết hợp phương pháp tiếp cận tuple và từ điển của trình %định dạng cũ :

"{greeting}, {0}".format(world, greeting='Hello')

và có thể mở rộng thông qua object.__format__()hook được sử dụng để xử lý định dạng các giá trị riêng lẻ.

Lưu ý rằng hệ thống cũ có %Templatelớp, nơi hệ thống sau cho phép bạn tạo các lớp con để thêm hoặc thay đổi hành vi của nó. Hệ thống kiểu mới có Formatterlớp để lấp đầy cùng một ngách.

Python 3 đã tiếp tục thoát khỏi việc không dùng nữa, thay vào đó đưa ra cảnh báo cho bạn trong phần printfĐịnh dạng chuỗi kiểu :

Lưu ý : Các thao tác định dạng được mô tả ở đây có nhiều lỗi khác nhau dẫn đến một số lỗi phổ biến (chẳng hạn như không hiển thị chính xác các bộ giá trị và từ điển). Sử dụng các ký tự chuỗi được định dạng mới hơn hoặc str.format()giao diện giúp tránh những lỗi này. Các lựa chọn thay thế này cũng cung cấp các cách tiếp cận mạnh mẽ, linh hoạt và có thể mở rộng hơn để định dạng văn bản.

Python 3.6 cũng thêm các ký tự chuỗi được định dạng , giúp xếp dòng các biểu thức vào chuỗi định dạng. Đây là phương pháp nhanh nhất để tạo chuỗi với giá trị nội suy và nên được sử dụng thay vì str.format()bất cứ nơi nào bạn có thể sử dụng một ký tự.


4
Và với Formatterbạn có thể tạo các định dạng tùy chỉnh như những định dạng mà datetimecác đối tượng sử dụng. Ngoài ra, vì .formatlà một hàm, bạn có thể sử dụng nó để tạo định dạng lười biếng có thể gọi trực tiếp hơn: ví dụ:fmt = '{} - {}'.format; fmt(a, b)
Jon Clements

Tôi không thấy Templatecó liên quan như thế nào đến %hoặc với hệ thống cũ . Cụ thể, PEP bạn liên kết nêu rõ Mặc dù có một số trùng lặp giữa đề xuất này và string.Template, chúng tôi cảm thấy rằng mỗi đề xuất phục vụ một nhu cầu riêng biệt và cái này không phủ nhận cái kia. Trong câu trả lời của bạn, người ta có thể nhầm lẫn rằng Templateđịnh dạng, là một phần của hệ thống cũ , cũng không được dùng nữa.
Bakuriu

@Bakuriu: Đúng vậy, tôi nghĩ rằng tôi đã bỏ lỡ phần đó; nhưng theo ý kiến ​​của tôi, Formatterlớp có thể đáp ứng các nhu cầu tương tự như string.Template().
Martijn Pieters

1
[...]should be preferred to the % formatting[...]phần này đã bị xóa khỏi tài liệu. docs.python.org/3/library/stdtypes.html#str.format
AXO

Tôi nghĩ rằng câu trả lời này hiện đang gây hiểu lầm; đoạn văn đầu tiên được trích dẫn đã bị xóa khỏi tài liệu Python 3 và tôi thấy khá rõ ràng rằng không có ý định còn lại cho việc ngừng sử dụng. Câu trả lời này vẫn có giá trị lịch sử, nhưng tôi sẽ có xu hướng điều chỉnh từ ngữ để tránh bất kỳ gợi ý nào rằng sự không chấp nhận vẫn còn trong các thẻ và chỉnh sửa phần lớn nửa đầu của câu trả lời thành thì quá khứ. Tôi sẽ tự mình làm như vậy vào một lúc nào đó nếu bạn không phản đối, nhưng tôi nghĩ tôi sẽ bình luận trước để bạn có cơ hội tự mình thực hiện những thay đổi đó nếu bạn muốn.
Mark Amery

45

Các %nhà điều hành để định dạng chuỗi không được chấp nhận, và sẽ không được gỡ bỏ - mặc dù câu trả lời khác.
Mỗi khi chủ đề được nêu ra trong danh sách phát triển Python, sẽ có tranh cãi gay gắt về việc cái nào tốt hơn, nhưng không có tranh cãi về việc liệu có nên loại bỏ cách cổ điển hay không - nó sẽ vẫn tồn tại. Mặc dù được ký hiệu trên PEP 3101, Python 3.1 đã xuất hiện và biến mất, và %định dạng vẫn còn xung quanh.

Các tuyên bố cho việc giữ phong cách cổ điển rất rõ ràng: nó đơn giản, nó nhanh chóng, nó nhanh chóng để làm cho những việc ngắn. Sử dụng .formatphương pháp này không phải lúc nào cũng dễ đọc hơn - và hầu như không ai - kể cả trong số các nhà phát triển cốt lõi, có thể sử dụng cú pháp đầy đủ được cung cấp bởi .formatmà không cần phải xem tài liệu tham khảo Thậm chí vào năm 2009, một người đã có những thông báo như thế này: http: // mail. python.org/pipermail/python-dev/2009-October/092529.html - chủ đề hầu như không hiển thị trong danh sách kể từ đó.

Cập nhật năm 2016

Trong phiên bản phát triển Python hiện tại (sẽ trở thành Python 3.6), có một phương pháp nội suy chuỗi thứ ba, được mô tả trên PEP-0498 . Nó định nghĩa một tiền tố quote mới f""(ngoài hiện tại u"", b""r"").

Tiền tố một chuỗi bằng fsẽ gọi một phương thức trên đối tượng chuỗi trong thời gian chạy, phương thức này sẽ tự động nội suy các biến từ phạm vi hiện tại vào chuỗi:

>>> value = 80
>>> f'The value is {value}.'
'The value is 80.'

3
Sẽ đẹp hơn nhiều khi cho phép các loại thực hiện riêng của chúng __format__. Ví dụ, format(Decimal('0.1'), '.20f')vs '%.20f' % Decimal('0.1'). Sau đó ép buộc Thập phân thành một số thực.
Eryk Sun

2
NB. Tôi không tranh luận rằng phong cách cũ tốt hơn về mọi mặt - chỉ là nó ngắn hơn và đôi khi dễ đọc hơn (và đôi khi không). Chắc chắn cách mới linh hoạt hơn nhiều.
jsbueno

Có tương đương cho ftrong Python 3 không?
Daniel

Các f-stringsnhư được sử dụng ở trên là tính năng mới trong ngôn ngữ như Python 3.6. Nó không tồn tại trong các phiên bản trước và sẽ gây ra Lỗi cú pháp trên những phiên bản đó.
jsbueno

20

Vị trí mới nhất của Guido về điều này dường như được chỉ ra ở đây:

Có gì mới trong Python 3.0

PEP 3101: Phương pháp tiếp cận mới để định dạng chuỗi

Một hệ thống mới cho các hoạt động định dạng chuỗi tích hợp thay thế toán tử định dạng chuỗi%. (Tuy nhiên, toán tử% vẫn được hỗ trợ; nó sẽ không được chấp nhận trong Python 3.1 và bị loại bỏ khỏi ngôn ngữ này vào một thời gian sau.) Đọc PEP 3101 để biết tin tức đầy đủ.

Và bản thân PEP3101 , có lần sửa đổi gần đây nhất kể từ (Thứ Sáu, ngày 30 tháng 9 năm 2011), vì vậy tôi cho rằng không có tiến triển nào về cuối phiên bản đó.


18

Nhìn vào các tài liệu Python cũ hơn và PEP 3101, có một tuyên bố rằng toán tử% sẽ không được chấp nhận và bị loại bỏ khỏi ngôn ngữ trong tương lai. Câu lệnh sau nằm trong tài liệu Python cho Python 3.0, 3.1 và 3.2:

Vì str.format () khá mới, rất nhiều mã Python vẫn sử dụng toán tử%. Tuy nhiên, vì kiểu định dạng cũ này cuối cùng sẽ bị loại bỏ khỏi ngôn ngữ, nên str.format () thường được sử dụng.

Nếu bạn đi đến cùng một phần trong tài liệu Python 3.3 và 3.4, bạn sẽ thấy câu lệnh đó đã bị loại bỏ. Tôi cũng không thể tìm thấy bất kỳ câu lệnh nào khác ở bất kỳ nơi nào khác trong tài liệu chỉ ra rằng toán tử sẽ không được chấp nhận hoặc bị xóa khỏi ngôn ngữ. Cũng cần lưu ý rằng PEP3101 đã không được sửa đổi trong hơn hai năm rưỡi (Thứ sáu, ngày 30 tháng 9 năm 2011).

Cập nhật

PEP461 Thêm% định dạng vào byte và bytearray được chấp nhận và phải là một phần của Python 3.5 hoặc 3.6. Đó là một dấu hiệu khác cho thấy toán tử% còn sống và đang hoạt động.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.