pre up next title end end

6. Řetězce

  1. Složený datový typ
  2. Operace s řetězci
    1. Pro řetězce, entice a seznamy
    2. Vestavěné metody pro řetězce
    3. Metoda join
    4. Metoda split
    5. Metoda find
  3. Modul 'string'
  4. Operátor 'in' a 'not in'
  5. Sestavení funkce 'find'
  6. Použití metod
  7. Porovnávání řetězců
  8. Formátování řetězců
    1. Interpolačním operátorem %
    2. Výměnným polem a metodou .format
    3. Formátovaným literálem (f-stringem)
  9. Formátování výstupů
  10. Únikové sekvence
  11. Dokumentační řetězce
  12. Testování s doctestem
  13. Cvičení

6.1 Složený datový typ

Řetězce (strings) jsou neměnitelné sekvence znaků Unicode, vymezené uvozovkami - jednoduchými, dvojitými či trojitými.
Výraz "bim" "bam" je automaticky konvertován na "bimbam".

Pořadí znaku v řetězci je interně indexováno zleva i zprava, neboli je vyjádřeno pořadovým číslem, které zleva začíná nulou - viz kap. 3.2.

Vymezená část řetězce se nazývá úsek (slice). Výběr úseku se provádí úsekovým operátorem nebo funkcí slice() - viz kap. 3.3.2

Délku řetězce určíme funkcí len, která vrací počet znaků v řetězci:

>>> fruit = "banana"
>>> len(fruit)
 6

Ve snaze získat poslední písmeno řetězce bychom mohli být v pokušení zkusit něco jako:

>>> délka = len(fruit)
>>> last = fruit[délka]
IndexError: string index out of range
>>> last = fruit[délka-1]; last
 a

6.2 Operace s řetězci

6.2.1   Operace pro řetězce, entice a seznamy

Obecně vzato, na řetězcích nelze provádět matematické operace. Následující výrazy nejsou přípustné :

"uno" - 1   "Hello / 123   "duo" * "Hello"   "15" + 2

Operátor + však s řetězci pracovat umí, i když jinak, než bychom očekávali. Pro řetězce, entice a seznamy představuje operátor + příkaz zřetězení (concatenation), což je spojení dvou operandů jejich připojením těsně k sobě. Například:

>>> "Chléb " + " a hry"       # spojení dvou řetězců
 Chléb a hry
>>> 1, 2, 3, + 4, 5, 6        # oba operandy jsou entice 
 (1, 2, 3, 4, 5, 6)
>>> 1, 2, 3 + 4, 5, 6         # jde o jednu entici s vloženým součtem 3+4 
 (1, 2, 7, 5, 6)            
>>> [1, 2, 3] + [4, 5, 6]     # spojení dvou seznamů
 [1, 2, 3, 4, 5, 6]

Řetězce jsou neměnitelné, což znamená, že existující řetězec nelze změnit. Jediná věc, kterou lze udělat, je vytvořit nový řetězec, který je variací původního:

>>> greeting = "Hello, world!"
>>> new_greeting = greeting[:5] + " all" + greeting[6:]
>>> print(new_greeting)
 'Hello all world!'

Řešením je zřetězení vložené části s úseky řetězce greeting. Tato operace nemá žádný vliv na původní řetězec.

Operátor násobení * rovněž pracuje s řetězci, enticemi i seznamy, způsobuje jejich zmnožení. Jeden z operandů musí být sekvence, druhým operandem musí být celé číslo, například:

>>> 3 * "bla " == "bla " * 3 == "bla bla bla "
 True
>>> (1, 2, 3) * 3              # zde entice jen v závorkách!
 (1, 2, 3, 1, 2, 3, 1, 2, 3)
>>> [1, 2, 3] * 3              # seznam rovněž
 [1, 2, 3, 1, 2, 3, 1, 2, 3]

6.2.2  Vestavěné metody pro řetězce

Kromě společných procedur pro řetězce a seznamy existuje také velké množství vestavěných metod, speciálně určených pro řetězce, které většinou evokujeme sestavou  'řetězec'.metoda():

  capitalize, casefold, center, count, encode, endswith, expandtabs,
  find, format, format_map, index, isalnum, isalpha, isdecimal,
  isdigit, isidentifier, islower, isnumeric, isprintable, isspace,
  istitle, isupper, join, ljust, lower, lstrip, maketrans, partition,
  replace, rfind, rindex, rjust, rpartition, rsplit, rstrip,
  split, splitlines, startswith, strip, swapcase, title, translate,
  upper, zfill

Například:

>>> he = "Hurvínek"
>>> he.upper()
 'HURVÍNEK'

6.2.3  Metoda join

Z řetězce umíme vytvořit seznam (list(arg)) a ze seznamu řetězec (str(arg)), dokonce to lze udělat jedním tahem:

>>> str(list("Žabička"))         # tato kumulace je však zbytečná
 "['Ž', 'a', 'b', 'i', 'č', 'k', 'a']"

Metoda join vrací řetězec, složený (concatenated) z prvků zadaného iteráblu (list, tuple, string, set a slovník). Prvky iteráblu musí být typu string.

  'separ'.join(iteráble)         # 'separ' je vkládaný separátor                
>>> li = ["k","o","š","i","k"]
>>> "^".join(li)
 'k^o^š^i^k'

Chceme-li z rozsypaného čaje sestavit zase žabičku, použijeme metodu join :

>>> frog = list("Žabička"); frog
 ['Ž', 'a', 'b', 'i', 'č', 'k', 'a']
>>> "".join(frog)                # "" je formálně povinný argument
 'Žabička'                       # bez něj by nešlo volat metodu
>>> gong = "Kravička"
>>> " * ".join(gong)
 'K * r * a * v * i * č * k * a'

Metoda .join() má zavádějící název. Jak vidíme, umí nejen spojovat ale i rozdělovat s vloženými znaky nebo mezerami.

6.2.4  Metoda  split

Metoda .split() rozloží řetězec na seznam úseků (substringů) v závislosti na zadaném separátoru. Separátorem může být libovolný znak řetězce - jenž se ve vráceném seznamu nahradí čárkou.

    string.split(separátor, počet jeho použití) 

Atributy metody split()jsou nepovinné. Implicitní hodnotou separátoru je mezera: string . split().
Nenachází-li se zadaný separátor či mezera v zadaném řetězci, řetězec se nerozdělí, pouze se vloží do listu.

>>> song = "Tam za vodou v rákosí ..."

>>> song.split()                       # vše zahrnující separace
 ['Tam', 'za', 'vodou', 'v', 'rákosí', '...']

>>> song.split(" ",2)                  # 2x použitý separátor
 ['Tam', 'za', 'vodou v rákosí ...']

>>> song.split(':')                    # seznam (list) bez separace
 ['Tam za vodou v rákosí ...']
Zajímavé případy:
>>> stig = "one,two,three" 

>>> stig.split(",")            # symetrické umístění separátoru
 ['one', 'two', 'three']       # OK, něma problema
>>> stig.split(", ")           # asymetrické umístění separátoru
 ['one,two,three']             # no toto!
  
>>> swig = 'a  b \nc d  \r\ne'
>>> swig.split("\nc")
 ['a  b ', ' d  \r\ne']        # vypouští se paremetr
>>> swig.split("\r")
 ['a  b \nc d ', '\ne']        # vypouští se paremetr

Vřele doporučuji otevřít si aplikaci Thonny a pohrávat si s variacemi uvedených ukázek.

6.2.5  Metoda  .find

Vestavěná (built-in) metoda vrací index prvního výskytu zadaného substringu v prohledávaném řetězci. Schéma volání metody find (parametry v hranatých závorkách jsou nepovinné) je toto:

string.find(sub [,start [, end]])

sub - hledaný substring
start - začátek hledání; implicitně je 0
end   - konec hledání; implicitně konec řetězce

Metoda find je ve skutečnosti všestrannější než naše uživatelská funkce find_u (viz 6.5). Umí nalézt i části řetězců, nejenom pouhé znaky:

>>> tanec = "Dokolečka dokola"
>>> tanec.find("leč")            # jen substring
 4

Jako naše funkce i tato metoda přijímá nepovinný argument, který určuje index u kterého má začít:

>>> tanec.find("kol", 4)         # substring a start
 12

Odlišně od naší funkce, druhý nepovinný parametr metody určuje index, kde má hledání skončit:

>>> tanec.find("Dok", 1, 15)     # substring, start a end
 -1                 # návratová hodnota v případě neúspěchu

V tomto případě skončí hledání nezdarem, protože se substring Dok nevyskytuje v intervalu od 1 do 15.

6.3 Modul string

Modul string obsahuje další užitečné objekty pro manipulaci s řetězci. Jako obvykle, modul musíme importovat dřív než jej použijeme:

>>> import string

Obsah modulu zjistíme vestavěnou fcí dir se jménem modulu jako argument:

>>> dir(string)

čímž dostaneme seznam specielních metod:

['Formatter', 'Template', '_ChainMap', 
'__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__',
'__package__', '_re', '__spec__', '_sentinel_dict', '_string',
 ...

a atributů:

... 'ascii_letters', ascii_lowercase', 'ascii_uppercase' 
'capwords', digits', hexdigits', 'octdigits', printable',
punctuation', 'whitespace']

Udělejte si průzkum a sami si zjistěte, co jednotlivé atributy vracejí:

>>> string.digits
 '0123456789'

>>> string.punctuation
 '!"#$%&\'()*+,-./:<=>?@[\\]^_`{|}~'

>>> string.whitespace
 '\t\n\r\x0b\x0c'        # escape sekvence pro whitespace

Znaky whitespace posouvají kurzor, aniž by se cokoli tisklo. Vytvářejí prázdné místo mezi viditelnými znaky.

Konstanty lze s výhodou použít v různých ověřovacích funkcích, například:

def is_lower(ch):
    return string.ascii_lowercase.find(ch) != -1

Nutno si uvědomit, že tato funkce neodpovídá na otázku, zda zkoumané písmeno je velké či malé ale zda patří do sady ascii_lowercase (kde se písmeno "ch" nevyskytuje - stejně jako česká písmena s diakritikou).

>>> is_lower("ch")
 False

Metoda "string.capwords ( str [, sep=None] )" rozdělí řetězec na jednotlivá slova (podle zadaného separátoru), počáteční písmena nahradí velkými a znovu spojí jednotlivá slova do jednoho řetězce. Použije-li se jako separátor znak, který není v původním řetězci obsažen, metoda vrátí řetězec s malými písmeny. Bez separátoru odstraní přebytečné mezery

>>> string.capwords("františkovy lázně")
 'Františkovy Lázně'

6.4 Operátor in a not in

Operátor příslušnosti in, not in přezkoumá, zda je zadaný řetězec součástí jiného:

>>> 'p' in 'apple'
 True
>>> 'i' in 'apple'
 False
>>> 'ap' not in 'apple'
 False
>>> 'pa' not in 'apple'
 True
Všimněme si, že řetězec může být součástí sebe sama:
>>> 'a' in 'a'
 True
>>> 'apple' in 'apple'
 True

Použitím operátoru in a zřetězení můžeme napsat funkci, která odstraní všechny samohlásky z řetězce:

def remove_vowels(str):
    samohl = "aeiouyAEIOUY"
    str_bez_samohl = ""                 # akumulátor
    for letter in str:
        if letter not in samohl:
            str_bez_samohl += letter
    return str_bez_samohl           
>>> remove_vowels("akumulátor")
 'kmlátr'

Prázdný objekt, označený jako akumulátor, je kontejner (zde řetězec) s rozšiřujícím se obsahem.
Podobným objektem je počítadlo, kde se mění počáteční stav čísla.


6.5 Sestavení funkce  find()

Uživatelská funkce find_u() pro dva parametry přijme řetězec a znak a vrátí index místa, kde se znak nachází. Zadaný řetězec se prohledává od počátku (start = 0). Není-li znak nalezen, funkce vrací "Znak nenalezen".

# find_u1.py

def find_u1(strng, znak):
    index = 0
    while index < len(strng):
        if strng[index] == znak:
            return index
        index += 1
    return "Znak nenalezen"

Z textu skriptu vyplývá, že funkce find2() nalezne pouze první výskyt hledaného znaku:

>>> %Run find_u1.py
>>> find_u1("košík", "š")
 2

V této funkci se opět setkáváme s příkazem return uvnitř smyčky. Je-li str[index] == znak, je funkce ukončena předčasným přerušením smyčky.

Tento způsob výpočtu je někdy nazýván traverzování Heuréka, protože jakmile nalezneme co hledáme, můžeme zvolat „Heuréka” a skončit hledání.

Funkci si vylepšíme přidáním parametru start. Připojením hodnoty z něj učiníme paramter s počáteční hodnotou, který je volitelný v tom smyslu, že jej můžeme při volání případně vynechat nebo změnit:

# find_u2.py

def find_u2(strng, ch, start=0):
    index = start
    while index < len(strng):
        if strng[index] == ch:
            return index
        index += 1
    return "Jsme mimo"
>>> %Run find_u2.py
>>> find_u2("banana","a", 2)
 3

6.6 Použití metod

Řetězce jsou sice neměnitelné ale lze libovolně upravovat jejich (často interně vytvářené) kopie. Pro tento účel existuje řada funkcí a vestavěných metod.

Metoda  .removeprefix/suffix()

Těmito metodami lze změnit začátek a konec řetězce:

>>> "some Text".removeprefix("some ")
 'Text'
>>> "some Text".removesuffix("Text")
 'some '

Metoda  .replace()

Metoda string.replace(old, new [,count]) vytvoří kopii zadaného řetězce, v němž nahradí stávající substring novým substringem a to pro zadaný počet substringů (implicitně pro všechny).

>>> ring = "horo, horo, vysoká jsi"
>>> (fing := ring.replace("horo", "Horo", 1))
 'Horo, horo, vysoká jsi'

Použitím metody replace lze částečně kompenzovat neexistenci procedury remove pro řetězce:

>>> abr = "abrakadabra"
>>> abr.replace("a", "")
 'brkdbr'

V případě potřeby si můžeme napsat proceduru (zde funkci) sami, například chceme-li zbavit řetězec předdefinované sady znaků, prezentované jako punctuation.
K vlastnímu vyzkoušení použijte prostředí IDLE nebo Thonny:

# punctuation.py

import string

def remove_punct(s): 
    s_without_punct = ""           # proměnná zvaná akumulátor
    for letter in s:
        if letter not in string.punctuation:
            s_without_punct += letter
    return s_without_punct
	
str = "Až na severní pól, běží liška!"	
print(remove_punct(str))
>>> %Run punctuation.py    
 Až na severní pól běží liška
Poznámka: Řetězec punctuation obsahuje všechna interpunkční znaménka a znaky:
>>> import string as str
>>> print("interpunkce: ", str.punctuation)
 interpunkce:  !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
Cvičení: Můžeme si definovat vlastní soubor znaků, napříkad 
"žšěíó".
Pro jeho použití upravte funkci remove_punct(s).

Metoda   .count

Vestavěnou metodu count použijeme při počítání výskytu zadaného znaku či skupiny znaků v řetězci:

string.count(value [, start [, end]])
>>> "abrakadabra".count("a")
 5
>>> "abrakadabra".count("ra")
 2
>>> "Až na severní pól".count(" ")
 3

6.7 Porovnávání řetězců

Při porovnávání řetězců se postupně porovnávají kódová čísla znaků se stejným indexem; postupuje se zleva doprava. ("Z" --> 90 a "b" --> 98). Python řadí velká písmena v důsledku svých číselných hodnot před malá.

Rovnost řetězců zjistíme:

>>> slovo = "třešně"
>>> if slovo == "banana":                 # nesplněné porovnání
    print ("Ano, banány máme!")
    else:
        print("Banány nejsou.")
 Banány nejsou.

Jiné relační operátory jsou užitečné při uspořádávání slov podle abecedy:

>>> word = "třešně"
>>> if word < "banana":
        print("Your word,"               # dělení logické věty!   
		+ word + ", comes before banana.")         
    elif word > "banana":
        print("Your word, " + word +  ", comes after banana.")
    else:
        print("Maybe, we have bananas!")
 Your word, třešně, comes after banana.

Souvislost znaku s číselnou hodnotou nám také umožňuje použít funkce min(), max(), ord() a chr():

>>> min("žoužel"), max("žoužel")
 ('e', 'ž')
>>> ord(min("žoužel")), ord(max("žoužel"))
 (101, 382)
>>> chr(101), chr(382)
 ('e', 'ž')

6.8 Formátování řetězců

6.8.1 Interpolačním operátorem %

Starší a v Pythonu 3.x stále použitelný způsob formátování řetězce je s použitím interpolačního operátoru % spolu s konverzními specifikacemi.

Konverzní specifikace jsou znaky, které zastupují zamýšlený formát vkládané hodnoty, například:

Schema formátovaného řetězce vypadá takto:

"řetězec se specifikací %i" % (hodnoty specifikace)

Část řetězec se specifikací obsahuje kombinaci textu a konverzní specifikace d, f, s. Následuje samotný interpolační operátor % a za ním výčet hodnot, dosazovaných za konverzní specifikace. Závorky jsou nepovinné, je-li hodnota pouze jedna.

Nejlépe si to ukážeme na několika příkladech:

>>> "Jmenuje se %s." % "Arthur"
 'Jmenuje se Arthur.'
>>> name  = "Alenka"
>>> age  = 16
>>> "Jsem %s a je mi %d let." %  (name, age)
 'Jsem Alenka a je mi 16 let.'
>>> n1, n2  = 4, 5              # enticové přiřazení
>>> "2**10 = %d a %d*%d = %f"  %  (2**10, n1, n2, n1*n2)
 '2**10 = 1024 a 4*5 = 20.000000'
>>> 

Ve třetím uvedeném příkladě mají proměnné n1 a n2 celočíselné hodnoty 4 a 5. Ve formátovaném řetězci jsou čtyři konverzní specifikace: tři %d a jedna %f. Písmeno f naznačuje, že příslušná hodnota má být ve tvaru čísla s plovoucí desetinnou čárkou (float). Čtyři hodnoty, které se vztahují k uvedeným čtyřem konverzním specifikacím jsou: 2**10,n1,n2 a n1*n2.

V následující ukázce vidíme příkaz k tisku, ve kterém k formátování řetězce použijeme únikový znak \t (viz tab. v 6.10):

# znak_t.py

i = 1
print("i\ti**2\ti**3\ti**5\ti**10\ti**20")   # záhlaví
while i <= 10:
   print(i,'\t',i**2,'\t',i**3,'\t',i**5,'\t',i**10,'\t',i**20)
   i += 1    

Tento program vytiskne tabulku různých mocnin čísel od 1 do 10. V uvedeném tvaru je rovnání výsledků do sloupců způsobené únikovým znakem tabelátoru \t, které selhává, jakmile hodnoty výsledků zaberou 8 míst:

i       i**2    i**3    i**5    i**10   i**20
1       1       1       1       1       1
2       4       8       32      1024    1048576
3       9       27      243     59049   3486784401
4       16      64      1024    1048576         1099511627776
5       25      125     3125    9765625         95367431640625
6       36      216     7776    60466176        3656158440062976
7       49      343     16807   282475249       79792266297612001
8       64      512     32768   1073741824      1152921504606846976
9       81      729     59049   3486784401      12157665459056928801
10      100     1000    100000      10000000000           100000000000000000000

Mohli bychom změnit šířku sloupce ale vidíme, že první sloupce již teď mají více místa než potřebují. Nejlepší bude určit šířku pro každý sloupec jednotlivě. Jak lze tušit, řešení poskytuje formátovaný řetězec :

# znak_tt.py
i = 1 
print("%-4s%-5s%-6s%-8s%-13s%-15s" %
    ('i', 'i**2', 'i**3', 'i**5', 'i**10', 'i**20'))
while i <= 10:
    print("%-4d%-5d%-6d%-8d%-13d%-15d" % (i, i**2, i**3, i**5, i**10, i**20))    
i += 1    

Pomlčka (-) za každou konverzní specifikací určuje zarovnání zleva. Číselné hodnoty určují minimální délku, takže %-13d je minimálně třináctimístné číslo zarovnané zleva.

Běh této verze dává následující výstup:

i   i**2 i**3  i**5    i**10        i**20          
1   1    1     1       1            1              
2   4    8     32      1024         1048576        
3   9    27    243     59049        3486784401     
4   16   64    1024    1048576      1099511627776  
5   25   125   3125    9765625      95367431640625 
6   36   216   7776    60466176     3656158440062976
7   49   343   16807   282475249    79792266297612001
8   64   512   32768   1073741824   1152921504606846976
9   81   729   59049   3486784401   12157665459056928801
10  100  1000  100000  10000000000  100000000000000000000

6.8.2 Výměnným polem a metodou .format

Novější způsob formátování výstupu je pomocí metody str.format() v sestavě

"řetězec_s_{výměnnými_poli}" .format(hodnoty výměnných polí)

Výměnná pole jsou instrukce, uzavřené ve složených závorkách {}. Nejjednodušší možná forma výměnného pole jsou prázdné složené závorky { }. Vše, co je mimo těchto závorek, je považováno za text, který je v nezměněném stavu kopírován do výstupu.

Výměnná pole jsou trojího druhu:

{označení, konverze, :specifikace} argumentu

Označení argumentu
je buď číslo, nebo klíčové slovo. Číslo odkazuje na poziční argument, klíčové slovo na pojmenovaný argument metody .format(). Tvoří-li čísla řadu 0, 1, 2, ..., lze je vynechat.

Více než slova řekne ukázka:

>>> "Od {} do {}" .format("rána", 22.00)  # dtto: "Od {0} do {1}"
 'Od rána do 22.00'
>>> "Jsem {osel}" .format(osel = "Pavel") 
 'Jsem se Pavel'

Konverze argumentu
způsobí změnu typu před formátováním. Používá se značení
!s, které volá funkci str(), jež vrací objekt coby řetězec
!r, které volá funkci repr(), jež vrací řetězec obsahující tisknutelnou prezentaci objektu
!a, které volá funkci ascii(), jež vrací řetězec, jehož non-ASCii znaky jsou nahrazeny escape sekvencí.

Ukázka přiblíží způsob použití:

>>> "Harold je chytrý {!s}" .format("chlapeček")
 'Harold je chytrý chlapeček'
>>> "Harold je chytrý {!r}" .format("chlapeček")
 "Harold je chytrý 'chlapeček'"   
>>> "Harold je chytrý {!a}" .format("chlapeček")
 "Harold je chytrý 'chlape\\u010dek'"   # ošetřené ne-ASCii

Specifikace argumentu
upřesňuje, jak má být hodnota prezentována, to jest určuje:
šířku - pole pro číselnou hodnotu
výplň - libovolný znak kromě závorek { }; následuje pokyn pro zarovnání
zarovnání - vlevo (<), vpravo (>), na střed (^) a mezi(=) signum a číslici
signum - +, -, " ", (také # a 0)
přesnost - počet desetinných míst čísla: . počet
typ - určuje způsob prezentace dat, například b je pro binární formát, d je pro decimální celé číslo, f pro formát float

Ukázka přiblíží způsob použití:

# číslice ve specifikaci určuje délku textového pole

>>> "{:<25}" .format("zarovnáno vlevo")
 'zarovnáno vlevo          '
>>> "{:>25}" .format("zarovnáno vpravo")
'         zarovnáno vpravo'   
>>> "{:ˇ^25}" .format("zarovnáno na střed")
 'ˇˇˇzarovnáno na středˇˇˇˇ'

Další zajímavé příklady namátkou:

>>> import math
>>> telef("Hodnota pí je asi {0:.3f}" .format(math.pi))
Hodnota pí je asi 3.142
>>>  
>>> telef = {"Jan":4127, "Dana":4098, "Ota":863678}
>>> for name, phone in telef.items():    
        print("{0:10} ==> {1:10d}" .format(name, phone))
 ...
 Jan        ==>      4127
 Dana       ==>      4098
 Ota        ==>    863678

Máme-li pojmenované argumenty uloženy ve slovníku, můžeme použít jeho hvězdičkové rozbalení:

>>> postava = {'name': 'Petr Parléř', 'age': 67}
>>> "Stavitel {name} se dožil {age} let." .format(**postava) 
 'Stavitel Petr Parléř se dožil 67 let.'

Další příklady lze nalézt v literatuře, například The Python Tutorial - Input and Output

Najde se tam také tento užitečný:

>>> for x in range(7,11):
        print("{0:2d} {1:3d} {2:4d}" .format(x, x*x, x*x*x))
  7  49  343
  8  64  512
  9  81  729
 10 100 1000
>>>

6.8.3 Formátovaným literálem (f-stringem)

Zjednodušený způsob formátování řetězců byl zaveden ve verzi Python 3.6. Označuje se jako formátovaný literál řetězce (formated string literal), stručně f-string. Literál f-stringu se uvozuje písmenem format nebo F a lze použít obdobné konverze argumentů (!s, !r, !a) jako u předchozího způsobu formátování.

Obdobně jako u předchozího způsobu může tento literál obsahovat výměnná pole, ohraničená složenými závorkami { }. Zatímco u předchozího způsobu odkazoval obsah těchto závorek pouze na konstantní hodnotu, u f-stringu může odkazovat také na výraz, funkci a metodu.

V této ukázce předvedeme f-string s výrazem (který se nejprve vyhodnotí):

>>> f"3 + 8/2 je {3 + 8/2}"
 '3 + 8/2 je 7.0'

V následující ukázce vidíme volání funkce a metody:

>>> name = "IDLE"
>>> def to_lowercase(input):
        return input.lower()

>>> f"{to_lowercase(name)} je zábavné."     # volání funkce
 'idle je zábavné.'

>>> f"{name.lower()} je zábavné."           # volání metody
 'idle je zábavné.'          

V další ukázce je odkaz na slovník:

>>> postava = {'name': 'Petr Parléř', 'age': 67}
>>> f"Stavitel {postava['name']} se dožil {postava['age']} let." 
 'Stavitel Petr Parléř se dožil 67 let.'
# konverzní flag !a pro ASCii - viz 6.8.2:
>>> f"Stavitel{postava['name']!a}"                 
 "Stavitel'Petr Parl\\xe9\\u0159'"

Python 3.8 přináší rozšíření f-stringu o rovnítko za jménem, které způsobí následné vytištění předem přiřazené hodnoty:

>>> python = 3.8                                
>>> f"{python}"; f"{python = }"
'3.8'                               # bez rovnítka
'python = 3.8'                      # s rovnítkem

Další možností je použití mrožího operátoru uvnitř f-stringu:

>>> import math
>>> r = 2.4
>>> f"Tyč o průměru {(d := 2 * r)} cm má obvod {math.pi * d:.2f} cm"
'Tyč o průměru 4.8 cm má obvod 15.08 cm'

6.9 Formátování výstupů

Formátování výstupů hodnot typu integer (d), float (f) a string (s) je uvedeno v následující tabulce (pro hodnoty mil = 1000000, mld = 1000000000, flt = 2.71828 a string = "aha"). Následující ukázky lze použít i bez příkazu "print".

   Hodnoty  Formát    Příklad použití    Výstup
   mil = 1000**2   {:,}    Comma separator:
            print(f'{mil:,}')
 1,000,000
   mld = 1000**3   {:.2e}    Exponent notation:
            print(f'{mld:.2e}')
 1.00e+09
   flt = 2.71828   {:.2f}   Format float:
            print(f'{flt:.2f}')
 2.72
   flt = 2.71828   round()              print(round(flt, 2)) 2.72
   0.35  {:.2%}   Procenta:
             print(f'{0.35:.2%}')
 35.00%
   x,y = string, 9  {x:>>y}    Dorovnání vlevo:
             print(f'{string:*>9}')
 ******aha
   x,y = string, 9   {x:<y}    Dorovnání vpravo:
             print(f'{string:*<9}')
 aha******
   x,y = string, 9   {x:^y}    Zarovnání na střed:
             print(f'{string:*^9}')
 ***aha***

Pro poslední tři ukázky si můžeme pamatovat, že výraz ve složených závorkách má obecně tuto skladbu:

{ arg : fill align width }          kde:

arg    upravovaná hodnota typu int, float, string
fill   doplňovaný znak (zde asterix)
align  dorovnání vlevo, vpravo, na střed (>, <, ^) 
width  celková šířka zaplňovaného pole (počet míst)

Pro čísla i řetěce lze použít také tento formát, kde rovnítko za jménem proměnné způsobí následné vytištění předem přiřazené hodnoty (bez příkazu "print"):

>>> x = "aha"
>>> f"{x = :*>7}"       # formátování výstupu
'x = ****aha'           # aha dorovnáno na 7 míst zleva

V následné ukázce se nejedná o mroží operátor, nýbrž o formátování f-stringu pro celé či desetinné číslo.

>>> x = 3; f"{x := 8}"
'       3'              # řetězec o délce 8 (včetně čísla 3)

6.10 Únikové sekvence

Úniková sekvence (escape sequence) je tvořena zpětným lomítkem (backslash) a následným jedním či více znaky.
Používá se pro vkládání jinak nepřípustných znaků do řetězce.

  Kód    Význam    
  \', \"  Vloží apostrof
  \\  Vloží zpětné lomítko
  \n  Přejde na nový řádek
  \r  Aktivuje 'carriage return'
  \t   Aktivuje tabulátor
  \b   Smaže znak před lomítkem
  \f   Aktivuje 'form feed'
  \ooo   Octal value
  \xhh   Hex value

Příklad na použití únikové sekvence '\t' a '\n'si ukážeme v následující ukázce:

>>> strg = 'a\tb\nA\tB' 
>>> print(strg)
 a	 b
 A	 B

Takzvaný raw string potlačuje vliv zpětných lomítek, potažmo escape sekvencí v řetězci. Formát "raw string" vytvoříme předsazením znaku r, případně R před zápis řetězce.

>>> strg = r'a\tb\nA\tB'    # zpětné lomítko je běžný znak
>>> print(strg)
 a\tb\nA\tB

6.11 Dokumentační řetězce

Kromě jednoduchých a dvojitých uvozovek zná Python také řetězce s trojitými uvozovkami, tvořenými jednoduchými i dvojitými znaky. Řetězce mohou procházet přes více řádků.

>>> """Toto je jedna možnost."""

>>> '''Toto je druhá možnost.'''

Uvnitř řetězce s trojitými uvozovkami mohou být uvozovky jednoduché i dvojité:

>>> ''' "Ach ne", zvolala, "Benovo kolo je rozbité" '''
' "Ach ne", zvolala, "Benovo kolo je rozbité" '
>>> 

Trojité uvozovky se používají pro dokumentační řetězce (docstrings). Docstring je řetězec, umístěný jako první text v modulu, funkci, třídě nebo v definici metody:

def mocnina(m, n=3):
    '''
    Funkce počítá n-tou mocninu s pevně
    nastaveným exponentem n=3; lze jej změnit
    '''
    print(m**n)

Informaci o funkci získáme evokací (voláním, neboli také "aplikací") vestavěné metody .__doc__ pro objekt funkce:

>>> print(mocnina.__doc__)
 Funkce počítá n-tou mocninu s pevně
 nastaveným exponentem n=3; lze jej změnit

Dokumentačního řetězce použijeme k získání stručné informace o jakémkoli vestavěném objektu (funkci):

>>> print(len.__doc__)
 Return the number of items in a container.

6.12  Testování s doctestem

Při rozvoji programu se s oblibou provádí testování vybraných úseků zdrojového kódu. Pro toto testování poskytuje Python moduly doctest a unittest.

Popíšeme si práci s vestavěným modulem doctest. Zkoumané vzorky kódu se umístí do dokumentačního řetězce (viz 6.11) pod záhlavím funkce. V každém vzorku dokumentačního řetězce je na prvním řádku kód, jakoby zadaný v interaktivním režimu, na druhém řádku je očekávaná odezva.

Modul doctest automaticky spustí příkaz začínající >>> a jeho výstup porovná s následujícím řádkem.
Vyzkoušíme si to v aplikaci Thonny:

doctest-file.py  

def is_divisible_by_2_or_5(n):       # záhlaví funkce

    """                              # dokumentační řetězec   
    >>> is_divisible_by_2_or_5(8)
    True
    >>> is_divisible_by_2_or_5(7)
    False
    >>> is_divisible_by_2_or_5(5)
    True
    """
    return n % 2 == 0 or n % 5 == 0      # tělo funkce      
    
if __name__ == '__main__':
    import doctest
    doctest.testmod()

Poslední tři řádky spouští celou parádu. Umisťujeme je na konec každého souboru, který obsahuje doctesty.

Pokud procedura zjistí shodu mezi zkoumanými vzorky a zadanými výsledky, reaguje "mlčením" nebo je-li v konzole evokována funkce "doctest .testmod()", vrátí stručný komentář o průběhu doctestu .

>>> doctest.testmod()
TestResults(failed=0, aclr-ttempted=3)

Pokud narazí na rozpor, spustí rozsáhlé chybové hlášení.

Spuštění neúspěšného skriptu vyprodukuje například následující výstup, pro nějž jsme ve druhém vzorku změnili hodnocení na 'True':

Failed example:
    is_divisible_by_2_or_5(7)
Expected:
    True
Got:
    False
***********************************************************
1 items had failures:
   1 of   3 in __main__.is_divisible_by_2_or_5
***Test Failed*** 1 failures.

6.13 Cvičení

  1. V návaznosti na odstavec 5.3 upravte skript tak, aby se Ouack a Quack vytiskly správně:
    prefixes = "JKLMNOPQ"
    suffix = "ack"
    
    for letter in prefixes:
        print(letter + suffix)
    
  2. Zapouzdřete následující sekvenci příkazů do funkce count_letters_acc
    fruit = "banana"
    count = 0
    for char in fruit:
        if char == 'a':
            count = count + 1
    print(count)
    
    a zobecněte ji tak, aby přijímala řetězec a písmeno jako argument a vracela počet výskytů písmena v řetězci. Řešení vložte do skriptu whatLetters_str.py
  3. Tutéž úlohu (výskyt znaků) řešte vestavěnou metodou string.count(letters), která počítá výskyt nejenom písmen ale i zadaných substringů.
  4. V následujících úlohách použijeme k ověření správnosti vašeho řešení doctesty, se kterým jsme se seznámili v kapitole 5.10. Vytvořte soubor se jménem stringtools.py a na jeho spodní okraj vložte tento veršíček:

    if __name__ == '__main__':
        import doctest  
        doctest.testmod() 
    
    Přidávejte těla funkcí tak, aby prošla zkouškou doctestů. Ty budou u některých výsledků vyžadovat i apostrofy. Přičtete je k výstupu:
    print("'" + <výstup> + "'")
    nebo použijte funkci
    return <výstup>
    

    Návštěva stránky String Methods může být v případě potřeby prospěšná.

    1. def reverse (s):
         """
         >>> reverse('happy')
         'yppah'
         >>> reverse('Python') 
         'nohtyP'
         >>> reverse('')
         ''
         >>> reverse('P')
         'P'
         """
      

      Jednoduché řešení úsekovým operátorem

    2. def mirror (s):
          """
          >>> mirror ('good')
          'gooddoog'
          >>> mirror ('yes') 
          'yessey'
          >>> mirror ('Python')
          'PythonnohtyP'
          >>> mirror ('')
          ''
          >>> mirror ('a')
          'aa'
          """
      

      Prosté spojení dvou řetězců.

    3. def is_palindrome (s):
          """
          >>> is_palindrome('aclr-mma')
          True
          >>> is_palindrome('abab') 
          False
          >>> is_palindrome('tenet')
          True
          >>> is_palindrome('banana')
          False
          >>> is_palindrome('straw warts')
          True
          """
      

      Použijete řešení ad a).

    4. def remove_letter (letter, strng):
          """
          >>> remove_letter ('a', 'apple')
          'pple'
          >>> remove_letter ('a', 'banana') 
          'bnn'
          >>> remove_letter ('z', 'banana')
          'banana'
          >>> remove_letter ('i', 'Mississippi')
          'Msssspp'
          """
      

      Lze řešit prostřednictvím idiomu for .. in .. nebo metodou replace.

    5. def count_sub (sub, s):
          """
          >>> count('is', 'Mississippi')
          2
          >>> count('an', 'banana') 
          2
          >>> count('ana', 'banana')
          1
          >>> count('nana', 'banana')
          1
          >>> count('nanan', 'banana')
          0
          """
      

      Napoví stránka "String Methods".

    6. def remove_sub (sub, s):
          """
          >>> remove('an', 'banana') 
          'bana'
          >>> remove('cyc', 'bicycle')
          'bile'
          >>> remove('iss', 'Mississippi')
          'Missippi'
          >>> remove('egg', 'bicycle')
          'bicycle'
          """
      

      Napoví stránka "String Methods".

    7. def remove_all (sub, s):
          """
          >>> remove_all('an', 'banana') 
          'ba'
          >>> remove_all('cyc', 'bicycle')
          'bile'
          >>> remove_all('iss', 'Mississippi')
          'Mippi'
          >>> remove_all('egg', 'bicycle')
          'bicycle'
          """
      
  5. Vyzkoušejte následující formátující řetězcové operace v konzole Pythonu a zaznamenejte výsledky:
    >>> "%s %d %f" % (5,5,5)
    
    >>> "%-.2f" % 3
    
    >>> "%-10.2f %-10.2f" % (7, 1.0/2)
    
    >>> print(" $%6.2f\n $%6.2f\n $%6.2f" % (3, 4.5, 11.2))
    

    Totéž proveďte pomocí funkce .format().


previous up next title end end