A string formázás során értékeket alakítunk stringgé, majd beillesztjük őket egy string-sablonba. A Python zenéje szerint „egy nyilvánvaló módja van annak, hogy valamit megvalósítsunk Pythonban”. De ami a string formázást illeti, a dolgok egy kicsit... kevésbé zenek.
Meglepő lehet, hogy négy fő módja van a string formázásnak Pythonban, mindegyik más-más helyzetre.
Ennek egy része Python hosszú történetéből fakad, más része pedig olyan szempontokból, mint a nemzetköziesítés vagy a bemenet tisztítása.
A string formázás eszköztárának legújabb darabjaival kezdünk, és visszafelé haladva jutunk el a „régi stílusú”, azaz „printf() stílusú” string formázásig.
f-string
A Python 3.6-ban bevezetett f-string-ek (a „formatted strings”, azaz formázott stringek rövidítése) vagy a literál string interpoláció segítségével gyorsan és hatékonyan kiértékelhetünk (és formázhatunk) kifejezéseket és stringeket str típussá úgy, hogy az idézőjelek elé írjuk az f (vagy F) előtagot (például így: f'{object}').
Az f-string-ek mindenféle lezáró stringtípussal használhatók, például egysoros (' vagy ") és többsoros (''' vagy """) stringekkel.
A {} belsejébe írt változókat, kifejezéseket vagy más típusokat először kiértékeli, majd str típussá alakítja, végül összefűzi a kapcsos zárójeleken kívüli str-ekkel.
Ebben a példában két változó értékét illesztjük be egy mondatba (egy str és egy float):
>>> name = 'eighth'
>>> value = 1/8
# The f-string, using the two values.
# The .2f format code truncates, so the value displays as 0.12.
>>> f'An {name} is approximately {value:.2f}.'
'An eighth is approximately 0.12.'
A kiértékelt kifejezések szinte bármik lehetnek.
Néhány a kiértékelhető lehetőségek (széles skálájából): str-ek, számok, változók, aritmetikai kifejezések, feltételes kifejezések, beépített típusok, szeletek, függvények, lambdák, komprehenziók, vagy bármilyen objektum, amelynél definiálva van a __str__ vagy a __repr__ metódus.
Az egyszerűtől a bonyolult felé haladva:
Változó beillesztése: az f-string legegyszerűbb használata, hogy egy változót közvetlenül a stringbe írunk.
# Assigning a variable.
>>> name = "World"
# Inserting that variable.
>>> f'Hello, {name}!'
'Hello, World!'
Kifejezések a {} belsejében: a kapcsos zárójelek között bármilyen érvényes Python-kifejezés kiértékelhető.
Figyeld meg, hogy ha egy szimpla idézőjeles f-string-en belül dupla idézőjelet használsz (vagy fordítva), elkerülheted az escape-szekvenciákat:
# A dictionary of key:value pairs.
>>> waves = {'water': 1, 'light': 3, 'sound': 5}
# Inserting the whole dict.
>>> f'Wave ranks: {waves}'
"Wave ranks: {'water': 1, 'light': 3, 'sound': 5}"
# An expression can be evaluated inline:
>>> f"Tenfold the value of 'light' is {waves['light'] * 10}."
"Tenfold the value of 'light' is 30."
# A method call can also be evaluated inline:
>>> f'{"hello world!".title()} is a classic greeting.'
'Hello World! is a classic greeting.'
# An f-string can be nested inside another f-string:
>>> f"{f'hello world!'.title()} is a classic greeting."
'Hello World! is a classic greeting.'
Kimenet formázása: a formátumspecifikációs mini-nyelvvel szabályozhatod az igazítást, a numerikus pontosságot és még sok mást.
A formátumspecifikáció az érték után következik, tőle egy : választja el.
# Right-align a value to ten characters, and round it to 3 decimal places.
>>> value = 1 / 7
>>> f'One seventh is {value:10.3f}.'
'One seventh is 0.143.'
# A format specification can be set using variables as well.
>>> padding = 10
>>> precision = 3
>>> f'One seventh is {value:{padding}.{precision}f}.'
'One seventh is 0.143.'
Így áll mindez össze: változók, kifejezések, függvényhívások és kimenetformázás:
>>> precision = 3
>>> f"{30e8 * 111_000:6.{precision}e}"
'3.330e+14'
>>> verb = 'meet'
>>> the_end = ['end', 'of', 'transmission']
>>> f'"Have a {"NICE".lower()} day, I will {verb} you after {30e8 * 111_000:6.{precision}e} light-years."{the_end}'
'"Have a nice day, I will meet you after 3.330e+14 light-years."[\'end\', \'of\', \'transmission\']'
# Did you notice the escaped single-quotes in the previous example?
# Using double quotes instead of single quotes for the f-string means the list's single-quoted strings print cleanly.
>>> f"Have a nice day. {the_end}"
"Have a nice day. ['end', 'of', 'transmission']"
Két fő korlátot érdemes szem előtt tartani.
Az f-string-kifejezések nem lehetnek üresek.
Ráadásul a Python 3.12 előtt nem tartalmazhattak megjegyzéseket.
>>> f"An empty expression will error: {}"
SyntaxError: f-string: empty expression not allowed
>>> word = 'word'
>>> f"""A comment in a triple quoted f-string: {
word # I chose a nice variable
}"""
'A comment in a triple quoted f-string: word'
A string interpoláció nem használható együtt a GNU gettext API-val a nemzetköziesítéshez (I18N) és a lokalizációhoz (L10N), ezért minden „szöveg stringbe csomagolását” érintő fordítói helyzetben azt javasoljuk, hogy f-string helyett az alább ismertetett string.Template osztályt vagy a str.format() metódust használd.
Arra is gondolj, hogy a f-string zárójelein ({}) belüli kifejezések használata hasonló az eval() vagy az exec() használatához, ezért nem túl biztonságos, és soha nem szabad felhasználói bemenettel használni.
str.format() metódusA str.format() metódus a stringen belüli helyőrzőket cseréli le a függvénynek átadott argumentumokra.
A helyőrzőket név ({price}), szám ({0} vagy indexek), vagy akár üres (pozíciós) helyőrző ({}) jelöli.
Például:
# A named placeholder and a positional placeholder.
>>> 'My text: {placeholder_1} and {}.'.format(12, placeholder_1='named placeholder')
'My text: named placeholder and 12.'
Az f-string-ekhez hasonlóan a Python str.format() metódusa is támogatja a mini-nyelv formátumspecifikációinak széles skáláját, amelyekkel igazíthatsz szöveget, csonkíthatsz tizedes törteket és még sok mást.
A teljes formátumspecifikációs minta {[<name>][!<conversion>][:<format_specifier>]}:
<name> lehet névvel ellátott helyőrző, szám vagy üres.!<conversion> elhagyható, és a három konverzió egyike kell legyen: !s a str() konverzióhoz, !r a repr() konverzióhoz vagy !a az ascii() konverzióhoz.
Alapértelmezés szerint a str() konverziót használja.:<format_specifier> elhagyható, és azt szabályozza, hogyan jelenjen meg az érték.
A lehetséges beállításokról itt találsz bővebb információt.Példa a konverziókra egy ékezetes betű esetén:
# Fills in the object at index zero, converted to a string.
>>> 'An e with an umlaut: {0!s}'.format('ë')
'An e with an umlaut: ë'
# Fills in the object at index zero, converted to a repr.
>>> 'An e with an umlaut (object representation): {0!r}'.format('ë')
"An e with an umlaut (object representation): 'ë'"
# Fills in the object at index zero, converted to ASCII.
>>> 'An e with an umlaut converted into ASCII: {0!a}'.format('ë')
"An e with an umlaut converted into ASCII: '\xeb'"
# Fills in the object in the first position,
# then fills in the object in the second position formatted as a repr.
>>> 'She said her name is not {} but {!r}.'.format('Chloe', 'Zoë')
"She said her name is not Chloe but 'Zoë'."
Példák gyakori formátumspecifikációkra:
# Integer and binary/hex representations of the same number.
>>> my_num = 42
>>> f"{my_num} in binary is {my_num:b}. In hex, it is {my_num:x}"
"42 in binary is 101010. In hex, it is 2a"
# Alignment: left (<), right (>), and center (^) using up to ten characters total.
>>> f"[{"left":<10}] [{"right":>10}] [{"center":^10}]"
"[left ] [ right] [ center ]"
# Float precision and scientific notation (up to three decimal places).
>>> pi = 3.141592653589793
>>> f"Fixed: {pi:.3} Scientific: {pi:.3e}"
"Fixed: 3.142 Scientific: 3.142e+00"
# Thousands separator and percentage.
>>> balance = 1000
>>> rate = 0.0225
>>> f"Balance: ${balance:,.0f} Interest rate: {rate:.1%}"
"Balance: $1,000 Interest rate: 2.2%"
# Putting it all together:
>>> items = [("Widget", 1250, 9.991), ("Gadget", 37, 24.503), ("Doohickey", 4, 149.002)]
>>> header = f"{"Item":<12} {"Qty":>6} {"Price":>9}"
>>> print(header)
Item Qty Price
>>> for name, qty, price in items:
... print(f"{name:<12} {qty:>6} {price:>9.2f}")
Widget 1250 9.99
Gadget 37 24.50
Doohickey 4 149.00
További példák e dokumentáció végén találhatók.
% formázás, avagy printf() stílusú formázásA % operátor formázásra való használata a legrégebbi stringformázási módszer Pythonban.
A C nyelvből származik, és lehetővé teszi pozíciós argumentumok használatát egy str összeállításához.
Ezt a módszert felváltotta az f-string és a str.format(), ezért kapta a % formázás a „Old Style”, azaz „régi stílus” becenevet.
Még mindig találkozhatsz vele Python 2-es és/vagy örökölt kódban.
Bár ez a módszer Python 3.x-ben is működik, a % formázást általában kerülik, mert hajlamos a hibákra, kevésbé hatékony, kevesebb beállítást kínál, és a helyőrző és az argumentum bármilyen eltérése kivételt válthat ki.
A % operátor használata hasonlít a printf() függvényéhez, ezért néha printf formázásnak is nevezik.
# Assigning a variable.
>>> name = "Anna-conda"
# Building a string using %.
>>> "The snake's name is %s." % name
"The snake's name is Anna-conda."
A fenti példában a % operátor futásidőben a %s helyőrzőt a name változóra cseréli.
Ha több változót szeretnél hozzáadni egy stringhez, a % után egy tuple-t kell megadnod, amelyben minden helyőrzőhöz egy objektum tartozik:
# Assigning variables.
>>> name = "Billy the Kid"
>>> fruit = "grapes"
# Building a string using %.
>>> "Surprisingly, %s's favorite snack was %s." %(name, fruit)
"Surprisingly, Billy the Kid's favorite snack was grapes."
A string.Template() (nem tévesztendő össze a Python 3.14 t-strings funkciójával) a string modul egyik osztálya (szemben a beépített str típussal), amely a Python szabványos könyvtárának része, de a használatához importálni kell.
A string-sablonok $-alapú helyettesítést támogatnak, és sokkal egyszerűbbek, kevesebbre képesek, mint az itt említett többi lehetőség.
Ugyanakkor nagyon hasznosak lehetnek bonyolult nemzetköziesítési feladatokhoz vagy külső bemenetek tisztításához.
A string.Template biztonságosabbnak számít nem megbízható felhasználói bemenet esetén, mert megakadályozza tetszőleges kifejezések kiértékelését és az objektumattribútumok elérését, ami mérsékli a formátumstring-injektálásos támadásokat.
>>> from string import Template
>>> name = "Anna-Conda"
# Creating a Template with placeholder text.
>>> template_string = Template("The snake called `$snake_name` has escaped!")
# Calling .substitute() to replace the placeholder with a value.
>>> template_string.substitute(snake_name=name)
'The snake called `Anna-Conda` has escaped!'
A string.Template-ről több információt a Python dokumentációjában találsz.
Ennyi lehetőség és mini-nyelv közepette hogyan döntsd el, mihez nyúlj, amikor Python stringeket formázol? Íme néhány gyors irányelv:
Az f-string-ek a legújabbak és a legkönnyebben olvashatók.
Ha nincs szükséged nemzetköziesítésre, Python 3.6+ esetén ezt érdemes előnyben részesíteni.
A str.format() sokoldalú, hatékony, és kompatibilis a gnu gettext-tel meg a Python legtöbb verziójával.
Ha az egyszerűségre, a biztonságra és/vagy a nagy volumenű nemzetköziesítésre van szükséged, a string.Template() segíthet csökkenteni a kockázatokat, amikor felhasználói bemeneteket kell kezelni, és fordítási stringek körítésére is használható.
A % operátort új kódban általában elavultnak tartják, bár a modern Pythonban még működik.
Leginkább régebbi kódbázisokkal való kompatibilitás miatt érdemes használni.
A % formázás hajlamosabb a hibákra (és kevesebb funkciót kínál), mint a többi módszer, ráadásul gondot okozhat a nem ASCII karakterek megjelenítésében.
Ha használni szeretnéd, nézd meg a konkrét Python-disztribúciódat a támogatási részletekért.
Ha tovább szeretnél menni, az all about formatting és a Python String Formatting Best Practices jó kiindulópontok.