Formatowanie ciągów:% vs. .format

1348

Python 2.6 wprowadził str.format()metodę z nieco inną składnią niż istniejący %operator. Które jest lepsze i na jakie sytuacje?

  1. Poniżej zastosowano każdą metodę i ma ten sam wynik, więc jaka jest różnica?

    #!/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. Ponadto, kiedy formatowanie łańcucha występuje w Pythonie? Na przykład, jeśli mój poziom rejestrowania jest ustawiony na WYSOKI, czy nadal będę otrzymywać trafienie za wykonanie następującej %operacji? A jeśli tak, to czy można tego uniknąć?

    log.debug("some debug info: %s" % some_info)
NorthIsUp
źródło
2
Dla początkujących: Oto bardzo fajny samouczek, który uczy obu stylów. Osobiście %częściej używam starszego stylu, ponieważ jeśli nie potrzebujesz ulepszonych możliwości format()stylu, %styl jest często o wiele wygodniejszy.
Lutz Prechelt
2
Dla odniesienia: dokumentacja Python 3 dla nowszego format()stylu formatowania i starszego %stylu formatowania .
Lutz Prechelt
1
Aby odpowiedzieć na drugie pytanie, od wersji 3.2 możesz użyć formatu {}, jeśli korzystasz z niestandardowego formatyzatora (patrz docs.python.org/3/library/logging.html#logging.Formatter )
yanjost

Odpowiedzi:

953

Odpowiedź na twoje pierwsze pytanie ... .formatwydaje się bardziej skomplikowana na wiele sposobów. Irytujące %jest także to, jak może przyjmować zmienną lub krotkę. Można by pomyśleć, że zawsze będą działać następujące rzeczy:

"hi there %s" % name

ale jeśli nametak się stanie (1, 2, 3), to rzuci TypeError. Aby zagwarantować, że zawsze drukuje, musisz to zrobić

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

co jest po prostu brzydkie. .formatnie ma tych problemów. Również w drugim podanym przez ciebie .formatprzykładzie przykład jest znacznie bardziej przejrzysty.

Dlaczego tego nie używałbyś?

  • nie wiedząc o tym (ja przed przeczytaniem tego)
  • musi być kompatybilny z Python 2.5

Aby odpowiedzieć na twoje drugie pytanie, formatowanie łańcucha odbywa się w tym samym czasie, co każda inna operacja - gdy oceniane jest wyrażenie formatujące łańcuch. Python, nie będąc leniwym językiem, ocenia wyrażenia przed wywołaniem funkcji, więc w twoim log.debugprzykładzie wyrażenie "some debug info: %s"%some_infonajpierw oceni, na przykład "some debug info: roflcopters are active", a następnie ten ciąg zostanie przekazany log.debug().

Claudiu
źródło
113
co"%(a)s, %(a)s" % {'a':'test'}
ted
128
Zauważ, że zmarnujesz czas na, log.debug("something: %s" % x)ale nie na log.debug("something: %s", x) Formatowanie łańcucha zostanie obsłużone w metodzie i nie dostaniesz spadku wydajności, jeśli nie zostanie zarejestrowany. Jak zawsze Python przewiduje twoje potrzeby =)
darkfeline
63
ted: to gorszy hack do robienia tego samego '{0}, {0}'.format('test').
latające owce
19
Chodzi o to: Jednym z powtarzających się argumentów, że nowa składnia umożliwia zmianę kolejności elementów, jest kwestia sporna: możesz zrobić to samo ze starą składnią. Większość ludzi nie wie, że jest to już zdefiniowane w Ansi C99 Std! Sprawdź ostatnią kopię man sprintfi dowiedz się o $notacji w %
symbolach
29
@ cfi: Jeśli masz na myśli coś takiego, wypisanie printf("%2$d", 1, 3)„3” jest określone w POSIX, a nie w C99. Sama strona podręcznika, do której się odnosiłeś, zauważa: „Standard C99 nie zawiera stylu używającego„ $ ”…”.
Thanatos,
307

Coś, czego operator modulo (%) nie może zrobić, afaik:

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

wynik

12 22222 45 22222 103 22222 6 22222

Bardzo przydatne.

Kolejna kwestia: format()będąc funkcją, może być używana jako argument w innych funkcjach:

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

Prowadzi do:

['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
eyquem
źródło
17
Możesz używać formatowania w starym stylu maptak łatwo, jak formatowania. map('some_format_string_%s'.__mod__, some_iterable)
agf
3
@ cfi: udowodnij, że masz rację, przepisując powyższy przykład w C99
MarcH
9
@MarcH: printf("%2$s %1$s\n", "One", "Two");skompilowany gcc -std=c99 test.c -o test, wynikiem jest Two One. Ale poprawiłem się: to właściwie rozszerzenie POSIX, a nie C. Nie mogę go znaleźć ponownie w standardzie C / C ++, gdzie myślałem, że go widziałem. Kod działa nawet z flagą std „c90”. sprintfstrona man . Nie ma go na liście, ale pozwala libsowi zaimplementować nadzbiór. Mój oryginalny argument jest nadal aktualny, zastępując CgoPosix
cfi
8
Mój pierwszy komentarz tutaj nie dotyczy tej odpowiedzi. Żałuję frazowania. W Pythonie nie możemy używać operatora modulo %do zmiany kolejności symboli zastępczych. Nadal chciałbym nie usuwać tego pierwszego komentarza ze względu na spójność komentarzy tutaj. Przepraszam, że wyładowałem tutaj swój gniew. Jest skierowany przeciwko często składanemu stwierdzeniu, że stara składnia per se nie pozwala na to. Zamiast tworzyć zupełnie nową składnię, moglibyśmy wprowadzić rozszerzenia std Posix. Moglibyśmy mieć jedno i drugie.
cfi
17
„modulo” odnosi się do operatora, który ocenia pozostałą część po podziale. w tym przypadku znak procentu nie jest operatorem modulo.
Ośmiornica
148

Zakładając, że używasz loggingmodułu Pythona , możesz przekazać argumenty formatujące ciąg znaków jako argumenty do .debug()metody zamiast samodzielnie formatować:

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

co pozwala uniknąć formatowania, chyba że program rejestrujący coś faktycznie rejestruje.

Wooble
źródło
10
Oto kilka przydatnych informacji, których właśnie się nauczyłem. Szkoda, że ​​nie ma własnego pytania, ponieważ wydaje się oddzielne od pytania głównego. Szkoda, że ​​OP nie podzielił swojego pytania na dwa osobne pytania.
snth
12
Możesz użyć formatowania dict w następujący sposób: log.debug("some debug info: %(this)s and %(that)s", dict(this='Tom', that='Jerry')) Nie możesz jednak użyć tutaj nowej .format()składni stylu , nawet w Pythonie 3.3, co jest wstydem.
Cito,
15
@Cito: Zobacz: plumberjack.blogspot.co.uk/2010/10/...
Vinay Sajip
26
Podstawową korzyścią tego nie jest wydajność (interpolacja ciągów będzie szybka w porównaniu z tym, co robisz z danymi wyjściowymi z rejestrowania, np. Wyświetlaniem w terminalu, zapisywaniem na dysku) Chodzi o to, że jeśli masz agregator rejestrowania, to może powiedzieć „otrzymałeś 12 wystąpień tego komunikatu o błędzie”, nawet jeśli wszystkie miały różne wartości „some_info”. Jeśli formatowanie ciągu zostanie wykonane przed przekazaniem ciągu do pliku log.debug, jest to niemożliwe. Agregator może tylko powiedzieć „miałeś 12 różnych komunikatów dziennika”
Jonathan Hartley,
7
Jeśli obawiasz
trojjer
119

Począwszy od wersji Python 3.6 (2016) można używać ciągów F w celu podstawiania zmiennych:

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

Zwróć uwagę na f"prefiks. Jeśli spróbujesz tego w Pythonie 3.5 lub wcześniejszym, otrzymasz SyntaxError.

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

Pułkownik Panika
źródło
1
To nie odpowiada na pytanie. Inna odpowiedź, która wymienia f-stringi, przynajmniej mówi o wydajności: stackoverflow.com/a/51167833/7851470
Georgy
60

PEP 3101 proponuje zastąpienie %operatora nowym, zaawansowanym formatowaniem napisów w Pythonie 3, gdzie byłoby to ustawienie domyślne.

Burza mózgów
źródło
14
Nieprawda: „Kompatybilność wsteczna może być utrzymana przez pozostawienie istniejących mechanizmów.”; oczywiście .formatnie zastąpi % formatowania łańcucha.
Tobias
12
Nie, postulat BrainStorms jest prawdziwy: „przeznaczony jako zamiennik istniejącego„% ””. Cytat Tobiasza oznacza, że ​​oba systemy będą współistnieć przez pewien czas. RTFPEP
phobie
54

Ale proszę uważać, dopiero teraz odkryłem jeden problem, gdy próbuje zastąpić wszystko %ze .formatw istniejący kod: '{}'.format(unicode_string)będzie próbował zakodować unicode_string i prawdopodobnie nie uda.

Wystarczy spojrzeć na ten interaktywny dziennik sesji Pythona:

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'

sjest tylko łańcuchem (zwanym „tablicą bajtów” w Python3) i ułańcuchem Unicode (zwanym „łańcuchem” w Python3):

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

Gdy podasz %operatorowi obiekt Unicode jako parametr , wygeneruje on ciąg Unicode, nawet jeśli oryginalny ciąg nie był 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)

ale .formatfunkcja wywoła „UnicodeEncodeError”:

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

i będzie działał z argumentem Unicode w porządku, tylko jeśli oryginalny ciąg znaków był Unicode.

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

lub jeśli ciąg argumentu można przekonwertować na ciąg znaków (tak zwana „tablica bajtów”)

wobmene
źródło
12
Po prostu nie ma powodu, aby zmieniać działający kod, chyba że dodatkowe funkcje nowej formatmetody są naprawdę potrzebne ...
Tobias
absolutnie się z tobą zgadzam, Tobiaszu, ale czasem jest to potrzebne podczas aktualizacji do nowszych wersji Pythona
wobmene
2
Na przykład? AFAIK, nigdy nie był potrzebny; Nie uważam za prawdopodobne, aby %interpolacja łańcuchów kiedykolwiek zniknęła.
Tobias
4
Uważam, że funkcja .format () jest bezpieczniejsza niż% dla łańcuchów. Często widzę błędy początkujących jak ten "p1=%s p2=%d" % "abc", 2lub "p1=%s p2=%s" % (tuple_p1_p2,). Możesz pomyśleć, że to wina programisty, ale myślę, że to po prostu dziwna, błędna składnia, która wygląda ładnie dla szybkiego skryptu, ale źle wpływa na kod produkcyjny.
wobmene
3
Ale nie podoba mi się składnia .format (), byłbym szczęśliwszy z dobrym starym %s, %02djak "p1=%s p2=%02d".format("abc", 2). Obwiniam tych, którzy wymyślili i zatwierdzili formatowanie nawiasów klamrowych, które wymaga od ciebie ucieczki {{}}i wygląda brzydko imho.
wobmene
35

Kolejna zaleta .format(której nie widzę w odpowiedziach): może przyjmować właściwości obiektu.

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'

Lub jako argument słowa kluczowego:

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

O %ile mi wiadomo, nie jest to możliwe .

matiasg
źródło
4
Wygląda to bardziej nieczytelnie niż to konieczne w porównaniu do odpowiednika 'x is {0}, y is {1}'.format(a.x, a.y). Powinien być stosowany tylko wtedy, gdy a.xoperacja jest bardzo kosztowna.
dtheodor
13
@dtheodor Z wariację użyć argumentu słowa kluczowego zamiast argumentu pozycyjnym ... 'x is {a.x}, y is {a.y}'.format(a=a). Bardziej czytelny niż oba przykłady.
CivFan
1
@CivFan Lub, jeśli masz więcej niż jeden obiekt,'x is {a.x}, y is {a.y}'.format(**vars())
Jack
1
Należy również pamiętać, ten jeden w ten sam sposób: '{foo[bar]}'.format(foo={'bar': 'baz'}).
Antoine Pinsard,
3
Jest to niezwykle przydatne w aplikacjach przeznaczonych dla klientów, w których aplikacja zapewnia standardowy zestaw opcji formatowania z ciągiem formatu dostarczonym przez użytkownika. Używam tego cały czas. Na przykład plik konfiguracyjny będzie miał właściwość „Messagestring”, którą użytkownik może dostarczyć 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}lub cokolwiek zechce. Jest to o wiele czystsze niż próba oferowania tej samej funkcjonalności ze starym formatyzatorem. To sprawia, że ​​ciągi formatu dostarczone przez użytkownika są o wiele potężniejsze.
Taywee,
35

%daje lepszą wydajność niż formatz mojego testu.

Kod testowy:

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

Wynik:

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

Wynik

> format: 0.5864730989560485
> %: 0.013593495357781649

Wygląda w Python2, różnica jest niewielka, podczas gdy w Python3 %jest znacznie szybsza niż format.

Dzięki @Chris Cogdon za przykładowy kod.

Edycja 1:

Testowany ponownie w Pythonie 3.7.2 w lipcu 2019 r.

Wynik:

> format: 0.86600608
> %: 0.630180146

Nie ma dużej różnicy. Myślę, że Python stopniowo się poprawia.

Edycja 2:

Po tym, jak ktoś wspomniał w komentarzu o łańcuchu f Pythona 3, zrobiłem test dla następującego kodu w Pythonie 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\"}'"))

Wynik:

format: 0.8331376779999999
%: 0.6314778750000001
f-string: 0.766649943

Wydaje się, że f-string jest wciąż wolniejszy niż, %ale lepszy niż format.

lcltj
źródło
42
Zamiast tego str.formatdaje więcej funkcji (zwłaszcza np '{0:%Y-%m-%d}'.format(datetime.datetime.utcnow()). Formatowanie specjalistyczne ). Wydajność nie może być bezwzględnym wymogiem wszystkich zadań. Użyj odpowiedniego narzędzia do pracy.
minhee
36
„Przedwczesna optymalizacja jest źródłem wszelkiego zła” - tak powiedział kiedyś Donald Knuth…
Yatharth Agarwal,
22
Trzymanie się dobrze znanego schematu formatowania (pod warunkiem, że odpowiada on potrzebom, co robi w zdecydowanej większości przypadków) i które jest dwa razy szybsze, nie jest „przedwczesną optymalizacją”, ale po prostu uzasadnione. BTW, %operator pozwala ponownie wykorzystać printfwiedzę; interpolacja słownikowa jest bardzo prostym rozszerzeniem zasady.
Tobias
5
Rzeczywiście doświadczyłem czegoś przeciwnego w jednej sytuacji. Formatowanie w nowym stylu było szybsze. Czy możesz podać użyty kod testowy?
David Sanders
8
Wygląda na poważnie zmarnowany post bez żadnych przykładów ani uzasadnienia, po prostu twierdzi.
kevr
31

Jak dzisiaj odkryłem, stary sposób formatowania napisów za pomocą %nie obsługuje Decimalmodułu Pythona dla dziesiętnych stałych i arytmetyki zmiennoprzecinkowej, po wyjęciu z pudełka.

Przykład (przy użyciu 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))

Wynik:

0,00000000000000000000000312375239000000009907464850 0,00000000000000000000000312375239000000000000000000

Z pewnością mogą istnieć obejścia, ale nadal możesz rozważyć użycie tej format()metody od razu.

balu
źródło
1
Jest tak prawdopodobnie dlatego, że wywołuje formatowanie w nowym stylu str(d)przed rozwinięciem parametru, podczas gdy formatowanie w starym stylu prawdopodobnie wywołuje float(d)najpierw.
David Sanders
3
Myślałbyś tak, ale str(d)wraca "3.12375239e-24", nie"0.00000000000000000000000312375239000000000000000000"
Jack
18

Jeśli twój python> = 3.6, literał sformatowany w ciąg F jest twoim nowym przyjacielem.

To jest prostsze, czyste i lepsza wydajność.

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)
zhengcao
źródło
15

Na marginesie, nie musisz naciskać na wydajność, aby używać formatowania w nowym stylu z logowaniem. Możesz przejść do dowolnego obiektu logging.debug, logging.infoitp, który implementuje __str__metody magiczne. Gdy moduł rejestrujący zdecyduje, że musi wyemitować obiekt wiadomości (cokolwiek to jest), wywołuje go, str(message_object)zanim to zrobi. Więc możesz zrobić coś takiego:

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

Wszystko to opisano w dokumentacji Python 3 ( https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles ). Będzie jednak działać również z Pythonem 2.6 ( https://docs.python.org/2.6/library/logging.html#using-arbitrary-objects-as-messages ).

Jedną z zalet korzystania z tej techniki, poza faktem, że jest ona agnostyczna w stylu formatowania, jest to, że pozwala ona na leniwe wartości, np expensive_func. Powyższą funkcję . Zapewnia to bardziej elegancką alternatywę dla porad zawartych w dokumentach Pythona tutaj: https://docs.python.org/2.6/library/logging.html#optimization .

David Sanders
źródło
2
Chciałbym móc to jeszcze bardziej głosować. Umożliwia rejestrowanie formatbez spadku wydajności - robi to poprzez przesłonięcie __str__dokładnie tak, jak loggingzostało zaprojektowane - skraca wywołanie funkcji do pojedynczej litery ( N), która jest bardzo podobna do niektórych standardowych sposobów definiowania ciągów - I pozwala na leniwe wywołanie funkcji. Dziękuję Ci! +1
CivFan
2
Czy to różni się od używania logging.Formatter(style='{')parametru?
davidA
10

Jedną z sytuacji, w której %może pomóc, jest formatowanie wyrażeń regularnych. Na przykład,

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

podnosi IndexError. W tej sytuacji możesz użyć:

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

Pozwala to uniknąć pisania wyrażenia regularnego jako '{type_names} [a-z]{{2}}'. Może to być przydatne, gdy masz dwa wyrażenia regularne, z których jeden jest używany sam bez formatu, ale połączenie obu jest sformatowane.

Jorge Leitao
źródło
3
Lub po prostu użyj '{type_names} [a-z]{{2}}'.format(type_names='triangle|square'). To tak, jakby powiedzieć, że .format()może pomóc, gdy używa się ciągów, które już zawierają znak procentu. Pewnie. Musisz wtedy uciec.
Alfe
1
@Alfe Masz rację i dlatego odpowiedź zaczyna się od "One situation where % may help is when you are formatting regex expressions."Konkretnie, załóżmy, że a=r"[a-z]{2}"jest to fragment wyrażenia regularnego, że będziesz użyty w dwóch różnych wyrażeniach końcowych (np. c1 = b + aI c2 = a). Załóżmy, że c1należy go formatedytować (np. bNależy sformatować środowisko wykonawcze), ale c2nie robi tego. Następnie trzeba a=r"[a-z]{2}"na c2i a=r"[a-z]{{2}}"na c1.format(...).
Jorge Leitao
7

Dodałbym, że od wersji 3.6 możemy używać ciągów takich jak poniżej

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

Które dają

Nazywam się John Smith

Wszystko jest konwertowane na ciągi

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

Wynik:

mylist = [„foo”, „bar”]

możesz przekazać funkcję, jak w metodzie innych formatów

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

Dając na przykład

Witam, oto data: 16.04.2018

Sylvan LE DEUNFF
źródło
4

Dla wersji python> = 3.6 (patrz PEP 498 )

s1='albha'
s2='beta'

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

#output
'albha      beta'
Roushan
źródło
2

Porównywalny język Python 3.6.7:

#!/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()

Wynik:

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
-----
Felix Martinez
źródło
3
Powinieneś uruchomić każdy przykład kilka razy, jedno uruchomienie może wprowadzać w błąd, np. System operacyjny może być ogólnie zajęty, więc wykonanie kodu może być opóźnione. zobacz dokumentację: docs.python.org/3/library/timeit.html . (fajny awatar, Guybrush!)
jake77
1

Ale jedno jest takie, że jeśli masz zagnieżdżone nawiasy klamrowe, nie będą działać dla formatu, ale %będą działać.

Przykład:

>>> '{{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}'
>>> 
U10 do przodu
źródło
2
możesz to zrobić, ale zgadzam się, że jest on niepoprawny „{{{0}, {1}}}”. format (1, 2)
Sylvan LE DEUNFF
Zagnieżdżone nawiasy klamrowe działają i są ładne.
CivFan