Formátovaný reťazec (f-string)

Takzvaný f-string ste už pravdepodobne videli v kurze Python 1 v lekcii Pokročilé vypisovanie výstupu. Tu si ukážeme ešte pokročilejšie vypisovanie.

F-string slúži na šikovnejšie formátovanie reťazcových literálov (literálom nazývame nejakú hodnotu natvrdo napísanú v kóde). F-string sa zapisuje ako f'text', čiže reťazec s f pred prvou úvodzovkou. Vieme ho potom používať napríklad takto:

first_name = 'Eugen'
last_name = 'Orechovník'
age = 25

text = f'Volám sa {first_name} {last_name} a mám {age} rokov.'
print(text)
# Volám sa Eugen Orechovník a mám 25 rokov.

Ako vidíte, Python si na miesta ohraničené kučeravými zátvorkami {} sám dosadí hodnoty premenných. Ak premenná nie je reťazec (ako napríklad naša premenná age), sám si ju prekonvertuje do reťazca.

Samozrejme, dovnútra {} nemusí ísť len premenná, môžeme tam dať napríklad výraz

a = 10
b = 1/2

print(f'{a} x {b} = {a * b}')
# 10 x 0.5 = 5.0

alebo volanie funkcie

a = [1, 2, 1e3, -4, 5.2]
print(f'Môj zoznam je {a}, má {len(a)} prvkov a jeho najväčší prvok je {max(a)}')
# Môj zoznam je [1, 2, 1000.0, -4, 5.2], má 5 prvkov a jeho najväčší prvok je 1000.0

alebo v zásade čokoľvek, čo nám vyprodukuje nejakú vypísateľnú hodnotu.

Možno sa zaujímate, čo sa stane, ak chceme vypísať { alebo } ako normálny text a nie použiť tieto zátvorky ako ohraničenie vypĺňaného miesta. Riešenie je jednoduché, zdvojíme zátvorky:

print(f'{')
# SyntaxError: f-string: expecting '}'

print(f'{{')
# {

Formátovanie čísel

Občas chceme pekne formátovať číslo do výpisu. Na toto f-stringy ponúkajú širokú škálu možností. Môžeme napríklad zaokrúhľovať:

# Namiesto
print('Približne ' + str(round(1/3, 3)))

# mozeme spravit
print(f'Približne {1/3:.3f}')
# Približne 0.333

Tu sme použili takzvaný modifikátor (modifier, tiež niekedy specifier), ktorý sa oddeľuje dvojbodkou od obsahu zátvorky. Čiže v našom prípade je to .3f. Ten nám hovorí, že pracujeme s desatinnými číslami (f), a že chceme len 3 desatinné miesta za bodkou. Aby toho nebolo málo, modifikátor sa tiež dá parametrizovať:

n = 5
print(f'{1/3:.{n}f}')
# 0.33333

V prípade čísel, môžeme s modifikátorom robiť aj iné veci:

length = 10

print(f'Číslo prefixované nulami tak, aby malo dĺžku {length} znakov: {1/3:0{length}.3f}')
# Číslo prefixované nulami tak, aby malo dĺžku 10 znakov: 000000.333

print(f'Číslo prefixované medzerami tak, aby malo dĺžku {length} znakov: {1/3:{length}.3f}')
# Číslo prefixované nulami tak, aby malo dĺžku 10 znakov:      0.333

print(f'Číslo so znamienkom: {42:+} a {-42:+}')
# Číslo so znamienkom: +42 a -42

print(f'Oddeľovanie tisícok: {1e10:,} alebo  {1e10:_}')
# Oddeľovanie tisícok: 10,000,000,000.0 alebo 10_000_000_000.0

c = 299_792_458
print(f'Vedecká notácia: {c:e} a {c:.3e}')
# Vedecká notácia: 2.997925e+08 a 2.998e+08

print(f'Percentá: {0.12345:.2%}')
# Percentá: 12.35%

Niekedy sa nám zíde vypisovanie čísel v iných sústavách:

print(f'Dvojková: {255:b} alebo {255:#b}')
print(f'Osmičková: {255:o} alebo {255:#o}')
print(f'Šestnástková: {255:x} alebo {255:#x}')
# Dvojková: 11111111 alebo 0b11111111
# Osmičková: 377 alebo 0o377
# Šestnástková: ff alebo 0xff

Zarovnávanie

Občas sa nám stane, že chceme vypisované dáta zarovnávať, napríklad do stĺpcov. Našťastie, namiesto pracného ručného vypĺňania medzerami, vieme opäť použiť f-string:

print(f'left: {"hello":<20}')
print(f'center: {"hello":^20}')
print(f'right: {"hello":>20}')
# left: hello
# center:        hello
# right:                hello

Podobne, ako sme mali v predošlej sekcii prefixovanie čísla nulami alebo medzerami, aj tu platí, že číslom v modifikátore špecifikujeme, aké má byť dané pole široké. Čiže, v našom prípade, Python sám dopočíta, koľko medzier má pridať na akú stranu, aby celé políčko s "hello" malo dokopy aj s medzerami 20 znakov. Ak mu zadáme šírku menšiu, ako je šírka pôvodného textu, nič sa zarovnávať nebude. Tu, napríklad "hello" má 5 znakov, ak použijeme modifikátor s dĺžkou 3, Python zarovnávanie odignoruje a "hello" nechá na pôvodnom mieste.

Tiež si môžete všimnúť, že už ako obsah poľa sme použili iný reťazec a nie číslo. Samozrejme, dá sa tu použiť akýkoľvek dátový typ, ktorý má zadefinovanú reťazcovú reprezentáciu, čiže ho vieme vypísať.

Ak používame reťazce v f-stringoch, je dôležité, aby mali iný typ úvodzoviek, ako f-string. V Pythone je jedno, či používate na označovanie reťazcov apostrofy ( ') alebo normálne úvodzovky ("). Tu sme napríklad f-string označili apostrofmi, ale vnútorný reťazec "hello" úvodzovkami. Ak by sme totiž použili opäť apostrofy, Python by si to vysvetlil ako koniec jedného reťazca, hello, čo už nie je reťazec, a začiatok ďalšieho reťazca, čo nechceme:

f'left: {'hello':<20}')
# |------|     |-----|
# String A     String B

Takéto zarovnanie ale nemusíme robiť len medzerami, môžeme použiť akýkoľvek znak, napríklad hviezdičku *. Znak, ktorý chceme použiť, špecifikujeme v modifikátore:

print(f'left: {"hello":*<20}')
print(f'center: {"hello":*^20}')
print(f'right: {"hello":*>20}')
# left: hello***************
# center: *******hello********
# right: ***************hello

Najčastejšie budete zarovnávanie asi používať, keď budete mať nejaké tabuľkové dáta, ktoré chcete pekne vypísať. Keďže ste v predošlej lekcii mali slovník, môžeme si ukázať jednoduché formátovanie dát zo slovníkov:

persons = [
    {
        'name': 'Guido van Rossum',
        'nationality': 'Dutch',
        'age': 67,
        'height': 173
    },
    {
        'name': 'Linus Torvalds',
        'nationality': 'Finnish',
        'age': 54,
        'height': 177
    }
]

print(f'{"Name":>20} {"Nationality":>20} {"Age":>10} {"Height":>10}')

for person in persons:
    print(f'{person["name"]:>20} {person["nationality"]:>20} {person["age"]:>10} {person["height"] / 100:>8.2f} m')

Výstup bude

                Name          Nationality        Age     Height
    Guido van Rossum                Dutch         67     1.73 m
      Linus Torvalds              Finnish         54     1.77 m