Định dạng chuỗi:% so với .format


1349

Python 2.6 đã giới thiệu str.format()phương thức với cú pháp hơi khác so với %toán tử hiện có . Cái nào tốt hơn và cho tình huống nào?

  1. Sau đây sử dụng từng phương pháp và có cùng kết quả, vậy sự khác biệt là gì?

    #!/usr/bin/python
    sub1 = "python string!"
    sub2 = "an arg"
    
    a = "i am a %s" % sub1
    b = "i am a {0}".format(sub1)
    
    c = "with %(kwarg)s!" % {'kwarg':sub2}
    d = "with {kwarg}!".format(kwarg=sub2)
    
    print a    # "i am a python string!"
    print b    # "i am a python string!"
    print c    # "with an arg!"
    print d    # "with an arg!"
  2. Hơn nữa khi định dạng chuỗi xảy ra trong Python? Ví dụ: nếu mức ghi nhật ký của tôi được đặt thành CAO thì tôi vẫn sẽ nhấn để thực hiện %thao tác sau chứ? Và nếu vậy, có cách nào để tránh điều này?

    log.debug("some debug info: %s" % some_info)


2
Dành cho người mới bắt đầu: Đây là một hướng dẫn rất hay dạy cả hai phong cách. Cá nhân tôi sử dụng %phong cách cũ thường xuyên hơn, bởi vì nếu bạn không cần các khả năng cải tiến của format()phong cách, %phong cách thường thuận tiện hơn rất nhiều.
Lutz Prechelt



1
Để trả lời câu hỏi thứ hai của bạn, vì 3.2, bạn có thể sử dụng định dạng {} nếu bạn sử dụng một định dạng tùy chỉnh (xem docs.python.org/3/library/logging.html#logging.Formatter )
yanjost

Câu trả lời:


953

Để trả lời câu hỏi đầu tiên của bạn ... .formatcó vẻ phức tạp hơn theo nhiều cách. Một điều khó chịu %cũng là làm thế nào nó có thể mất một biến hoặc một tuple. Bạn sẽ nghĩ rằng những điều sau đây sẽ luôn hoạt động:

"hi there %s" % name

Tuy nhiên, nếu namexảy ra (1, 2, 3), nó sẽ ném a TypeError. Để đảm bảo rằng nó luôn được in, bạn cần phải làm

"hi there %s" % (name,)   # supply the single argument as a single-item tuple

mà chỉ là xấu xí. .formatkhông có những vấn đề đó Cũng trong ví dụ thứ hai bạn đưa ra, .formatví dụ này trông gọn gàng hơn nhiều.

Tại sao bạn không sử dụng nó?

  • không biết về nó (tôi trước khi đọc nó)
  • phải tương thích với Python 2.5

Để trả lời câu hỏi thứ hai của bạn, định dạng chuỗi xảy ra cùng lúc với mọi thao tác khác - khi biểu thức định dạng chuỗi được ước tính. Và Python, không phải là một ngôn ngữ lười biếng, đánh giá các biểu thức trước khi gọi các hàm, vì vậy trong log.debugví dụ của bạn , biểu thức "some debug info: %s"%some_infotrước tiên sẽ đánh giá, ví dụ "some debug info: roflcopters are active", sau đó chuỗi đó sẽ được chuyển đến log.debug().


113
những gì về"%(a)s, %(a)s" % {'a':'test'}
ted

128
Lưu ý rằng bạn sẽ lãng phí thời gian cho log.debug("something: %s" % x)nhưng không cho log.debug("something: %s", x) định dạng chuỗi sẽ được xử lý trong phương thức và bạn sẽ không đạt được hiệu suất nếu nó không được ghi lại. Như mọi khi, Python dự đoán nhu cầu của bạn =)
darkfeline

63
ted: đó là một hack trông tệ hơn để làm tương tự như '{0}, {0}'.format('test').
cừu bay

19
Vấn đề là: Đối số định kỳ cho rằng cú pháp mới cho phép sắp xếp lại các mục là một điểm cần thiết: Bạn có thể làm tương tự với cú pháp cũ. Hầu hết mọi người không biết rằng điều này thực sự đã được xác định trong Ansi C99 Std! Kiểm tra một bản sao gần đây man sprintfvà tìm hiểu về $ký hiệu bên trong %giữ chỗ
cfi

29
@cfi: Nếu bạn muốn nói điều gì đó như, printf("%2$d", 1, 3)để in ra "3", điều đó được chỉ định trong POSIX, không phải C99. Trang rất đàn ông mà bạn tham chiếu ghi chú, "Tiêu chuẩn C99 không bao gồm kiểu sử dụng '$' '".
Thanatos

307

Một cái gì đó mà toán tử modulo (%) không thể làm được, afaik:

tu = (12,45,22222,103,6)
print '{0} {2} {1} {2} {3} {2} {4} {2}'.format(*tu)

kết quả

12 22222 45 22222 103 22222 6 22222

Rất hữu ích.

Một điểm khác : format(), là một hàm, có thể được sử dụng làm đối số trong các hàm khác:

li = [12,45,78,784,2,69,1254,4785,984]
print map('the number is {}'.format,li)   

print

from datetime import datetime,timedelta

once_upon_a_time = datetime(2010, 7, 1, 12, 0, 0)
delta = timedelta(days=13, hours=8,  minutes=20)

gen =(once_upon_a_time +x*delta for x in xrange(20))

print '\n'.join(map('{:%Y-%m-%d %H:%M:%S}'.format, gen))

Kết quả trong:

['the number is 12', 'the number is 45', 'the number is 78', 'the number is 784', 'the number is 2', 'the number is 69', 'the number is 1254', 'the number is 4785', 'the number is 984']

2010-07-01 12:00:00
2010-07-14 20:20:00
2010-07-28 04:40:00
2010-08-10 13:00:00
2010-08-23 21:20:00
2010-09-06 05:40:00
2010-09-19 14:00:00
2010-10-02 22:20:00
2010-10-16 06:40:00
2010-10-29 15:00:00
2010-11-11 23:20:00
2010-11-25 07:40:00
2010-12-08 16:00:00
2010-12-22 00:20:00
2011-01-04 08:40:00
2011-01-17 17:00:00
2011-01-31 01:20:00
2011-02-13 09:40:00
2011-02-26 18:00:00
2011-03-12 02:20:00

17
Bạn có thể sử dụng định dạng kiểu cũ mapdễ dàng như định dạng. map('some_format_string_%s'.__mod__, some_iterable)
agf

3
@cfi: vui lòng chứng minh bạn đúng bằng cách viết lại ví dụ trên trong C99
MarcH

9
@MarcH: printf("%2$s %1$s\n", "One", "Two");biên dịch với gcc -std=c99 test.c -o test, đầu ra là Two One. Nhưng tôi đã sửa: Nó thực sự là một phần mở rộng POSIX chứ không phải C. Tôi không thể tìm thấy nó một lần nữa trong tiêu chuẩn C / C ++, nơi tôi nghĩ tôi đã thấy nó. Mã này hoạt động ngay cả với cờ std 'c90'. sprintftrang người đàn ông . Điều này không liệt kê nó, nhưng cho phép libs thực hiện một superset. Đối số ban đầu của tôi vẫn hợp lệ, thay thế CbằngPosix
cfi

8
Nhận xét đầu tiên của tôi ở đây, không áp dụng cho câu trả lời này. Tôi hối tiếc phrasing. Trong Python, chúng ta không thể sử dụng toán tử modulo %để sắp xếp lại các chỗ dành sẵn. Tôi vẫn không muốn xóa bình luận đầu tiên đó vì mục đích thống nhất bình luận ở đây. Tôi xin lỗi vì đã trút cơn giận của tôi ở đây. Nó được định hướng chống lại tuyên bố thường được thực hiện rằng cú pháp cũ sẽ không cho phép điều này. Thay vì tạo một cú pháp hoàn toàn mới, chúng tôi có thể đã giới thiệu các phần mở rộng stix Posix. Chúng ta có thể có cả hai.
cfi

17
'modulo' dùng để chỉ toán tử đánh giá phần còn lại sau khi chia. trong trường hợp này, dấu phần trăm không phải là toán tử modulo.
Bạch tuộc

148

Giả sử bạn đang sử dụng loggingmô-đun của Python , bạn có thể chuyển các đối số định dạng chuỗi dưới dạng đối số cho .debug()phương thức thay vì tự định dạng:

log.debug("some debug info: %s", some_info)

mà tránh thực hiện định dạng trừ khi logger thực sự ghi nhật ký một cái gì đó.


10
Đây là một số thông tin hữu ích mà tôi vừa học được. Thật đáng tiếc, nó không có câu hỏi riêng vì nó dường như tách biệt với câu hỏi chính. Đáng tiếc là OP đã không chia câu hỏi của anh ấy thành hai câu hỏi riêng biệt.
snth

12
Bạn có thể sử dụng định dạng chính tả như thế này: log.debug("some debug info: %(this)s and %(that)s", dict(this='Tom', that='Jerry')) Tuy nhiên, bạn không thể sử dụng .format()cú pháp kiểu mới ở đây, ngay cả trong Python 3.3, điều này thật đáng xấu hổ.
Cito


26
Lợi ích chính của việc này không phải là hiệu năng (thực hiện phép nội suy chuỗi sẽ nhanh so với bất cứ điều gì bạn đang làm với đầu ra từ việc ghi nhật ký, ví dụ như hiển thị trong một thiết bị đầu cuối, lưu vào đĩa) Đó là nếu bạn có bộ tổng hợp ghi nhật ký, thì đó là có thể cho bạn biết "bạn đã nhận được 12 trường hợp thông báo lỗi này", ngay cả khi tất cả chúng đều có các giá trị 'some_info' khác nhau. Nếu định dạng chuỗi được thực hiện trước khi chuyển chuỗi sang log.debug, thì điều này là không thể. Trình tổng hợp chỉ có thể nói "bạn có 12 thông điệp tường trình khác nhau"
Jonathan Hartley

7
Nếu bạn lo ngại về hiệu suất, hãy sử dụng cú pháp dict {} theo nghĩa đen thay vì khởi tạo lớp dict (): doughellmann.com/2012/11/iêu
trojjer

119

Kể từ Python 3.6 (2016), bạn có thể sử dụng chuỗi f để thay thế các biến:

>>> origin = "London"
>>> destination = "Paris"
>>> f"from {origin} to {destination}"
'from London to Paris'

Lưu ý f"tiền tố. Nếu bạn thử điều này trong Python 3.5 hoặc sớm hơn, bạn sẽ nhận được SyntaxError.

Xem https://docs.python.org/3.6/reference/lexical_analysis.html#f-strings


1
Điều này không trả lời câu hỏi. Một câu trả lời khác đề cập đến chuỗi f ít nhất nói về hiệu suất: stackoverflow.com/a/51167833/7851470
Georgy

60

PEP 3101 đề xuất thay thế %toán tử bằng định dạng chuỗi mới, nâng cao trong Python 3, trong đó nó sẽ là mặc định.


14
Không đúng sự thật: "Khả năng tương thích ngược có thể được duy trì bằng cách để các cơ chế hiện có tại chỗ."; Tất nhiên, .formatsẽ không thay thế % định dạng chuỗi.
Tobias

12
Không, định đề BrainStorms là đúng: "dự định thay thế cho '%'" hiện có. Tobias quote có nghĩa là cả hai hệ thống sẽ cùng tồn tại trong một thời gian. RTFPEP
phobie

54

Nhưng hãy cẩn thận, vừa rồi tôi đã phát hiện ra một vấn đề khi cố gắng thay thế tất cả %bằng .formatmã hiện có: '{}'.format(unicode_string)sẽ cố mã hóa unicode_ chuỗi và có thể sẽ thất bại.

Chỉ cần nhìn vào nhật ký phiên tương tác Python này:

Python 2.7.2 (default, Aug 27 2012, 19:52:55) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
; s='й'
; u=u'й'
; s
'\xd0\xb9'
; u
u'\u0439'

schỉ là một chuỗi (được gọi là 'mảng byte' trong Python3) và ulà một chuỗi Unicode (được gọi là 'chuỗi' trong Python3):

; '%s' % s
'\xd0\xb9'
; '%s' % u
u'\u0439'

Khi bạn cung cấp một đối tượng Unicode làm tham số cho %toán tử, nó sẽ tạo ra một chuỗi Unicode ngay cả khi chuỗi ban đầu không phải là Unicode:

; '{}'.format(s)
'\xd0\xb9'
; '{}'.format(u)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u0439' in position 0: ordinal not in range(256)

nhưng .formatchức năng sẽ nâng cao "UnicodeEncodeError":

; u'{}'.format(s)
u'\xd0\xb9'
; u'{}'.format(u)
u'\u0439'

và nó sẽ hoạt động tốt với một đối số Unicode chỉ khi chuỗi gốc là Unicode.

; '{}'.format(u'i')
'i'

hoặc nếu chuỗi đối số có thể được chuyển đổi thành một chuỗi (được gọi là 'mảng byte')


12
Đơn giản là không có lý do để thay đổi mã làm việc trừ khi các tính năng bổ sung của formatphương thức mới thực sự cần thiết ...
Tobias

Tobias hoàn toàn đồng ý với bạn, nhưng đôi khi điều đó là cần thiết khi nâng cấp lên các phiên bản mới hơn của Python
wobmene

2
Ví dụ? AFAIK, nó chưa bao giờ cần thiết; Tôi không nghĩ rằng có khả năng %nội suy chuỗi sẽ biến mất.
Tobias

4
Tôi xem xét hàm .format () an toàn hơn% cho chuỗi. Thường thì tôi thấy những sai lầm của người mới bắt đầu như thế này "p1=%s p2=%d" % "abc", 2hoặc "p1=%s p2=%s" % (tuple_p1_p2,). Bạn có thể nghĩ rằng đó là lỗi của lập trình viên nhưng tôi nghĩ rằng đó chỉ là một cú pháp lỗi kỳ lạ, có vẻ tốt cho kịch bản nhanh nhưng lại không tốt cho mã sản xuất.
wobmene

3
Nhưng tôi không thích cú pháp của .format (), tôi sẽ hạnh phúc hơn với cái cũ %s, %02dnhư thế "p1=%s p2=%02d".format("abc", 2). Tôi đổ lỗi cho những người đã phát minh và phê duyệt định dạng dấu ngoặc nhọn cần bạn thoát khỏi chúng như thế nào {{}}và trông imho xấu xí.
wobmene

35

Một ưu điểm khác của .format(mà tôi không thấy trong các câu trả lời): nó có thể lấy các thuộc tính đối tượng.

In [12]: class A(object):
   ....:     def __init__(self, x, y):
   ....:         self.x = x
   ....:         self.y = y
   ....:         

In [13]: a = A(2,3)

In [14]: 'x is {0.x}, y is {0.y}'.format(a)
Out[14]: 'x is 2, y is 3'

Hoặc, như một đối số từ khóa:

In [15]: 'x is {a.x}, y is {a.y}'.format(a=a)
Out[15]: 'x is 2, y is 3'

Điều này là không thể với %như tôi có thể nói.


4
Điều này có vẻ khó đọc hơn cần thiết so với tương đương 'x is {0}, y is {1}'.format(a.x, a.y). Chỉ nên sử dụng khi a.xhoạt động rất tốn kém.
dtheodor

13
@dtheodor Với một tinh chỉnh để sử dụng một đối số từ khóa thay vì tranh luận về vị trí ... 'x is {a.x}, y is {a.y}'.format(a=a). Dễ đọc hơn cả hai ví dụ.
CivilFan

1
@CivFan Hoặc, nếu bạn có nhiều hơn một đối tượng,'x is {a.x}, y is {a.y}'.format(**vars())
Jack

1
Cũng lưu ý điều này trong cùng một cách : '{foo[bar]}'.format(foo={'bar': 'baz'}).
Antoine Pinsard

3
Điều này cực kỳ hữu ích cho các ứng dụng hướng tới khách hàng, nơi ứng dụng của bạn cung cấp một bộ tùy chọn định dạng tiêu chuẩn với chuỗi định dạng do người dùng cung cấp. Tôi sử dụng tất cả các thời gian. Ví dụ, tệp cấu hình sẽ có một số thuộc tính "messagestring" mà người dùng có thể cung cấp Your order, number {order[number]} was processed at {now:%Y-%m-%d %H:%M:%S}, will be ready at about {order[eta]:%H:%M:%S}hoặc bất cứ thứ gì họ muốn. Điều này sạch hơn nhiều so với việc cố gắng cung cấp chức năng tương tự với trình định dạng cũ. Nó làm cho chuỗi định dạng do người dùng cung cấp mạnh hơn.
Taywee

35

%cho hiệu suất tốt hơn so với formatthử nghiệm của tôi.

Mã kiểm tra:

Python 2.7.2:

import timeit
print 'format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')")
print '%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')")

Kết quả:

> format: 0.470329046249
> %: 0.357107877731

Python 3.5.2

import timeit
print('format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')"))
print('%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')"))

Kết quả

> format: 0.5864730989560485
> %: 0.013593495357781649

Nó nhìn vào Python2, sự khác biệt là nhỏ trong khi trong Python3, %nhanh hơn nhiều format.

Cảm ơn @Chris Cogdon cho mã mẫu.

Chỉnh sửa 1:

Đã thử nghiệm lại trong Python 3.7.2 vào tháng 7 năm 2019.

Kết quả:

> format: 0.86600608
> %: 0.630180146

Không có nhiều khác biệt. Tôi đoán Python đang dần cải thiện.

Chỉnh sửa 2:

Sau khi ai đó đề cập đến chuỗi f của python 3 trong bình luận, tôi đã thực hiện kiểm tra mã sau theo python 3.7.2:

import timeit
print('format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')"))
print('%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')"))
print('f-string:', timeit.timeit("f'{1}{1.23}{\"hello\"}'"))

Kết quả:

format: 0.8331376779999999
%: 0.6314778750000001
f-string: 0.766649943

Có vẻ như f-string vẫn chậm hơn %nhưng tốt hơn format.


42
Thay vào đó, str.formatcung cấp nhiều chức năng hơn (đặc biệt là định dạng chuyên biệt kiểu, ví dụ '{0:%Y-%m-%d}'.format(datetime.datetime.utcnow())). Hiệu suất không thể là yêu cầu tuyệt đối của tất cả các công việc. Sử dụng các công cụ thích hợp cho công việc.
minhee

36
"Tối ưu hóa sớm là gốc rễ của mọi tội lỗi" hay vì thế Donald Knuth từng nói ...
Yatharth Agarwal

22
Bám sát một sơ đồ định dạng nổi tiếng (miễn là phù hợp với nhu cầu, trong phần lớn các trường hợp), và nhanh gấp đôi, không phải là "tối ưu hóa sớm" mà đơn giản là hợp lý. BTW, %nhà điều hành cho phép sử dụng lại printfkiến thức; nội suy từ điển là một phần mở rộng rất đơn giản của nguyên tắc.
Tobias

5
Tôi thực sự đã trải nghiệm điều ngược lại trong một tình huống. Định dạng kiểu mới đã nhanh hơn. Bạn có thể cung cấp mã kiểm tra bạn đã sử dụng?
David Sanders

8
Có vẻ như một bài viết lãng phí nghiêm trọng mà không có bất kỳ ví dụ hoặc lý do, chỉ yêu cầu.
kevr

31

Như tôi đã khám phá ngày nay, cách định dạng cũ của các chuỗi thông qua %không hỗ trợ Decimal, mô-đun của Python cho số học điểm cố định thập phân và số học dấu phẩy động, ra khỏi hộp.

Ví dụ (sử dụng Python 3.3.5):

#!/usr/bin/env python3

from decimal import *

getcontext().prec = 50
d = Decimal('3.12375239e-24') # no magic number, I rather produced it by banging my head on my keyboard

print('%.50f' % d)
print('{0:.50f}'.format(d))

Đầu ra:

0,0000000000000000000000000312375239000000009907464850 0,0000000000000000000000000312375239000000000000000000

Chắc chắn có thể có cách giải quyết nhưng bạn vẫn có thể cân nhắc sử dụng format()phương pháp ngay lập tức.


1
Đó có thể là do các cuộc gọi định dạng kiểu mới str(d)trước khi mở rộng tham số, trong khi định dạng kiểu cũ có thể gọi float(d)trước.
David Sanders

3
Bạn sẽ nghĩ như vậy, nhưng str(d)trở về "3.12375239e-24", không phải"0.00000000000000000000000312375239000000000000000000"
Jack

18

Nếu python của bạn> = 3.6, chuỗi F được định dạng bằng chữ là người bạn mới của bạn.

Nó đơn giản hơn, sạch sẽ hơn và hiệu suất tốt hơn.

In [1]: params=['Hello', 'adam', 42]

In [2]: %timeit "%s %s, the answer to everything is %d."%(params[0],params[1],params[2])
448 ns ± 1.48 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [3]: %timeit "{} {}, the answer to everything is {}.".format(*params)
449 ns ± 1.42 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [4]: %timeit f"{params[0]} {params[1]}, the answer to everything is {params[2]}."
12.7 ns ± 0.0129 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)

15

Là một lưu ý phụ, bạn không cần phải thực hiện một cú đánh hiệu suất để sử dụng định dạng kiểu mới với ghi nhật ký. Bạn có thể vượt qua bất kỳ đối tượng logging.debug, logging.infovv mà thực hiện các __str__phương pháp kỳ diệu. Khi mô-đun đăng nhập đã quyết định rằng nó phải phát ra đối tượng tin nhắn của bạn (bất kể đó là gì), nó sẽ gọi str(message_object)trước khi thực hiện. Vì vậy, bạn có thể làm một cái gì đó như thế này:

import logging


class NewStyleLogMessage(object):
    def __init__(self, message, *args, **kwargs):
        self.message = message
        self.args = args
        self.kwargs = kwargs

    def __str__(self):
        args = (i() if callable(i) else i for i in self.args)
        kwargs = dict((k, v() if callable(v) else v) for k, v in self.kwargs.items())

        return self.message.format(*args, **kwargs)

N = NewStyleLogMessage

# Neither one of these messages are formatted (or calculated) until they're
# needed

# Emits "Lazily formatted log entry: 123 foo" in log
logging.debug(N('Lazily formatted log entry: {0} {keyword}', 123, keyword='foo'))


def expensive_func():
    # Do something that takes a long time...
    return 'foo'

# Emits "Expensive log entry: foo" in log
logging.debug(N('Expensive log entry: {keyword}', keyword=expensive_func))

Đây là tất cả được mô tả trong tài liệu Python 3 ( https://docs.python.org/3/howto/logging-cookbook.html#formatted-styles ). Tuy nhiên, nó cũng sẽ hoạt động với Python 2.6 ( https://docs.python.org/2.6/l Library / global.html #USE-arbitrary-objects-as- messages ).

Một trong những lợi thế của việc sử dụng kỹ thuật này, ngoài thực tế là thuyết bất khả tri kiểu định dạng, là nó cho phép các giá trị lười biếng, ví dụ như hàm expensive_functrên. Điều này cung cấp một giải pháp thay thế thanh lịch hơn cho lời khuyên được đưa ra trong các tài liệu Python tại đây: https://docs.python.org/2.6/l Library / loggging.html # optimization .


2
Tôi ước tôi có thể nâng cao điều này hơn nữa. Nó cho phép đăng nhập formatmà không cần nhấn hiệu năng - thực hiện bằng cách ghi đè __str__chính xác như loggingđược thiết kế cho - rút ngắn lệnh gọi hàm thành một chữ cái ( N) có cảm giác rất giống với một số cách tiêu chuẩn để xác định chuỗi - VÀ cho phép lười biếng gọi chức năng. Cảm ơn bạn! +1
CivilFan

2
Đây có phải là bất kỳ khác nhau trong kết quả để sử dụng logging.Formatter(style='{')tham số?
davidA

10

Một tình huống %có thể giúp là khi bạn định dạng biểu thức regex. Ví dụ,

'{type_names} [a-z]{2}'.format(type_names='triangle|square')

tăng IndexError. Trong tình huống này, bạn có thể sử dụng:

'%(type_names)s [a-z]{2}' % {'type_names': 'triangle|square'}

Điều này tránh viết regex như '{type_names} [a-z]{{2}}'. Điều này có thể hữu ích khi bạn có hai biểu thức chính, trong đó một biểu thức được sử dụng một mình mà không có định dạng, nhưng phần nối của cả hai được định dạng.


3
Hoặc chỉ sử dụng '{type_names} [a-z]{{2}}'.format(type_names='triangle|square'). Nó giống như nói .format()có thể giúp đỡ khi sử dụng các chuỗi đã chứa một phần trăm ký tự. Chắc chắn rồi. Bạn phải thoát khỏi chúng sau đó.
Alfe

1
@Alfe Bạn đã đúng, và đó là lý do tại sao câu trả lời bắt đầu bằng "One situation where % may help is when you are formatting regex expressions."Cụ thể, giả sử a=r"[a-z]{2}"là một đoạn regex mà bạn sẽ được sử dụng trong hai biểu thức cuối cùng khác nhau (ví dụ c1 = b + ac2 = a). Giả sử rằng c1cần phải được chỉnh sửa format(ví dụ: bcần phải được định dạng thời gian chạy), nhưng c2không. Sau đó, bạn cần a=r"[a-z]{2}"cho c2a=r"[a-z]{{2}}"cho c1.format(...).
Jorge Leitao

7

Tôi sẽ thêm rằng kể từ phiên bản 3.6, chúng ta có thể sử dụng fstrings như sau

foo = "john"
bar = "smith"
print(f"My name is {foo} {bar}")

Đưa ra

Tôi tên là John

Mọi thứ được chuyển đổi thành chuỗi

mylist = ["foo", "bar"]
print(f"mylist = {mylist}")

Kết quả:

mylist = ['foo', 'bar']

bạn có thể truyền hàm, giống như trong các định dạng khác

print(f'Hello, here is the date : {time.strftime("%d/%m/%Y")}')

Cho ví dụ

Xin chào, đây là ngày: 16/04/2018


4

Đối với phiên bản python> = 3.6 (xem PEP 498 )

s1='albha'
s2='beta'

f'{s1}{s2:>10}'

#output
'albha      beta'

2

Python 3.6.7 so sánh:

#!/usr/bin/env python
import timeit

def time_it(fn):
    """
    Measure time of execution of a function
    """
    def wrapper(*args, **kwargs):
        t0 = timeit.default_timer()
        fn(*args, **kwargs)
        t1 = timeit.default_timer()
        print("{0:.10f} seconds".format(t1 - t0))
    return wrapper


@time_it
def new_new_format(s):
    print("new_new_format:", f"{s[0]} {s[1]} {s[2]} {s[3]} {s[4]}")


@time_it
def new_format(s):
    print("new_format:", "{0} {1} {2} {3} {4}".format(*s))


@time_it
def old_format(s):
    print("old_format:", "%s %s %s %s %s" % s)


def main():
    samples = (("uno", "dos", "tres", "cuatro", "cinco"), (1,2,3,4,5), (1.1, 2.1, 3.1, 4.1, 5.1), ("uno", 2, 3.14, "cuatro", 5.5),) 
    for s in samples:
        new_new_format(s)
        new_format(s)
        old_format(s)
        print("-----")


if __name__ == '__main__':
    main()

Đầu ra:

new_new_format: uno dos tres cuatro cinco
0.0000170280 seconds
new_format: uno dos tres cuatro cinco
0.0000046750 seconds
old_format: uno dos tres cuatro cinco
0.0000034820 seconds
-----
new_new_format: 1 2 3 4 5
0.0000043980 seconds
new_format: 1 2 3 4 5
0.0000062590 seconds
old_format: 1 2 3 4 5
0.0000041730 seconds
-----
new_new_format: 1.1 2.1 3.1 4.1 5.1
0.0000092650 seconds
new_format: 1.1 2.1 3.1 4.1 5.1
0.0000055340 seconds
old_format: 1.1 2.1 3.1 4.1 5.1
0.0000052130 seconds
-----
new_new_format: uno 2 3.14 cuatro 5.5
0.0000053380 seconds
new_format: uno 2 3.14 cuatro 5.5
0.0000047570 seconds
old_format: uno 2 3.14 cuatro 5.5
0.0000045320 seconds
-----

3
Bạn nên chạy từng ví dụ một vài lần, một lần chạy có thể gây hiểu nhầm, ví dụ hệ điều hành có thể thường bận rộn nên việc thực thi mã của bạn bị trì hoãn. xem tài liệu: docs.python.org/3/l Library / timeit.html . (hình đại diện đẹp, Guybrush!)
jake77

1

Nhưng có một điều là nếu bạn có niềng răng lồng nhau, sẽ không hoạt động cho định dạng nhưng %sẽ hoạt động.

Thí dụ:

>>> '{{0}, {1}}'.format(1,2)
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    '{{0}, {1}}'.format(1,2)
ValueError: Single '}' encountered in format string
>>> '{%s, %s}'%(1,2)
'{1, 2}'
>>> 

2
bạn có thể làm điều này, nhưng tôi đồng ý rằng nó thật tuyệt vời '{{{0}, {1}}}'. định dạng (1, 2)
Sylvan LE DEUNFF

Từ khóa lồng nhau làm việc niềng răng và rất đẹp.
CivilFan
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.