![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Až dosud jsme poznali pět typů dat: int, float, bool, NoneType a str . Řetězce (strings) jsou kvalitativně odlišné od ostatních čtyř typů, protože se skládají z menších částic - alfanumerických znaků.
Typy, které se skládají z menších částic, se nazývají složené datové typy. Se složeným datovým typem můžeme chtít zacházet jako s jednou věcí, nebo můžeme chtít mít přístup k jeho částem. Tato dvojí možnost je užitečná.
Hranaté závorky slouží jako operátor, který vybere jednotlivé znaky z řetězce:
>>> fruit = "banana"
>>> letter = fruit[1]
>>> print letter
Výraz fruit[1] vybere znak číslo 1 z řetězce fruit. Proměnná letter se vztahuje k výsledku. Zobrazíme-li letter, dostaneme překvapení:
a
První písmeno slova 'banana' není a - alespoň ne pro obyčejného smrtelníka. Programátoři však z jakýchsi perverzních důvodů vždy počítají od nuly. Nulté písmeno ("nula-té") z banana je b, 1. pímeno ("jedna-té") je a a 2. ("dvě-té") je n.
Chceme-li první písmeno řetězce, zadáme 0 nebo jakýkoliv výraz s hodnotou 0 do hranatých závorek:
>>> letter = fruit[0]
>>> print letter
b
Výrazu v hranatých závorkách se říká index. Index označuje člena uspořádané sestavy, v tomto případě sestavy znaků v řetězci. Může jím být jakýkoliv celočíselný výraz.
Funkce len 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:
length = len(fruit)
last = fruit[length] # chyba!
Toto nepůjde. Způsobí to chybu při běhu programu IndexError: string index out or range (index řetězce mimo rozsah). Důvod je ten, že ve slově banana není "6-té" písmeno. Protože jsme začali počítat od nuly, je šest písmen očíslováno od 0 do 5. Abychom dostali poslední znak, musíme od length odečíst 1:
length = len(fruit) last = fruit[length-1]
Alternativně můžeme použít záporné indexy, které počítají od konce řetězce. Výraz fruit[-1] poskytne poslední písmeno, fruit[-2] předposlední, a tak dále.
Mnohé výpočty zahrnují probírání znaků v řetězci postupně jeden za druhým. Počínaje prvním, s každým něco provedou, končí posledním. Tento způsob pojednání se jmenuje traverzování . Možný zápis tohoto postupu je pomocí příkazu while:
index = 0 while index < len(fruit): letter = fruit[index] print letter index = index + 1
Tato smyčka prochází řetězcem a zobrazí každé písmeno na samostatném řádku. Podmínka smyčky je index < len(fruit), takže když je index roven délce řetězce, je podmínka nepravdivá a tělo smyčky se neprovede. Poslední procházený znak je s indexem len(fruit)-1, což je poslední znak řetězce.
Použití indexu k traverzování sady hodnot je tak běžné, že Python poskytuje alternativu - jednodušší smyčku for:
for char in fruit: print char
V každém cyklu smyčky se přiřadí znak řetězce proměnné char. Smyčka projde postupně všemi znaky.
Následující příklad ukazuje použití zřetězení (concatenation) a smyčku for pro tvorbu abecedních řad. Abecedním je míněno uspořádání prvků řady či seznamu podle abecedy. Například, v knize Roberta McCloskeyho: Uvolněte cestu pro káčata se kachňata jmenují: Jack, Kack, Lack, Mack, Nack, Ouack, Pack a Quack. Tato smyčka vydá jejich jména v pořadí:
prefixes = "JKLMNOPQ" suffix = "ack"
for letter in prefixes: print letter + suffix
Výstup programu je tento:
Jack Kack Lack Mack Nack Oack Pack Qack
V pořádku to úplně není, protože Ouack a Quack nejsou zapsáni správně. Tuto chybu napravíme v rámci cvičení.
Část řetězce se nazývá úsek (slice). Výběr úseku je podobný jako výběr znaku:
>>> s = "Peter, Paul, and Mary" >>> print s[0:5] Peter >>> print s[7:11] Paul >>> print s[17:21] Mary
Operátor [n:m] vrací část řetězce od n-tého znaku včetně po znak před m-tým. Toto chování se příčí intuitivnímu přístupu; bude mít větší smysl, když si představíme, že indicie ukazují před jednotlivé znaky, viz obrázek:

Vynecháme-li první index (před dvojtečkou), začíná úsek na počátku řetězce. Vynecháme-li druhý index, úsek jde až ke konci řetězce. Takže:
>>> fruit = "banana" >>> fruit[:3] 'ban' >>> fruit[3:] 'ana'
Co asi znamená s[:]?
Porovnávací operátory pracují také s řetězci. Rovnost řetězců zjistíme:
if word == "banana": print "Yes, we have bananas!"
Jiné porovnávací operátory jsou užitečné při uspořádávání slov podle abecedy:
if word < "banana": print "Your word," + word + ", comes before banana." elif word > "banana": print "Your word," + word + ", comes after banana." else: print "Yes, we have bananas!"
Musíme si však být vědomi toho, že Python zachází s malými a velkými písmeny jinak, než jsme zvyklí. Všechna velká písmena řadí před všechna malá. V důsledku toho:
Your word, Zebra, comes before banana.
Obvyklý způsob řešení tohoto problému je přeměna řetězce do standardního formátu (např. všechna písmena malá) před prováděním porovnávání. Svízelnější problém je přinutit program, aby si uvědomil, že zebry nejsou ovoce.
Může být lákavé použít operátor [] na levé straně přiřazení se záměrem změnit znak v řetězci. Na příklad:
greeting = "Hello, world!" greeting[0] ='J' # chyba! print greeting
Místo výstupu Jello, world!, tento kód způsobí chybu při běhu programu: TypeError: 'str' object doesn´t support item assignment.
Řetězce jsou neměnitelné, což znamená, že existující řetězec nelze změnit. Nejlepší věc, kterou lze udělat, je vytvořit nový řetězec, který je variací původního:
greeting = "Hello, world!"
new_greeting = 'J' + greeting[1:]
print new_greeting
Řešením je zřetězení nového prvního písmena s úsekem řetězce greeting. Tato operace nemá žádný vliv na původní řetězec.
Operátorin přezkoumá, zda je zadaný řetězec součástí jiného:
>>> 'p' in 'apple' True >>> 'i' in 'apple' False >>> 'ap' in 'apple' True >>> 'pa' in 'apple' FalseVšimněmež si, že řetězec může byt 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(s): samohl = "aeiouyAEIOUY" s_bez_samohl = "" for letter in s: if letter not in samohl: &nb s_bez_samohl += letter return s_bez_samohl
Ověřme si, že funkce dělá to co jsme chtěli
Co dělá následující funkce?
def find(strng, ch): index = 0 while index < len(strng): if strng[index] == ch: return index index += 1 return -1
V jistém smyslu je funkce find opakem operátoru [ ]. Místo přijmutí indexu a vyjmutí odpovídajícího znaku z řetězce, find přijme znak a nalezne index místa, kde se znak nachází. Není-li znak nalezen, funkce vrací -1.
V této funkci se poprvé setkáváme s příkazem return uvnitř smyčky. Je-li str[index] == ch, je funkce ukončena předčasným přerušením smyčky.
Není-li znak v řetězci obsažen, potom program opustí smyčku normálně a vrátí -1.
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í.
Následující program počítá kolikrát se písmeno a vyskytne v řetězci a je dalším příkladem počítadla, uvedeného v kapitole 6:
fruit = "banana" count = 0 for char in fruit: if char == 'a': count += 1 print count
Pro nalezení místa prvního výskytu znaku po zadaném počátku hledání můžeme přidat třetí parametr do funkce find:
def find2(strng, ch, start): index = start whileindex < len(strng): if strng[index] == ch: return index index += 1 return -1Volání find2("banana","a",2) nyní vrátí pozici prvního a za indexem 2.
Ještě výhodnější bude kombinace fcí find a find2 přidáním volitelného parametru:
def find(strng, ch, start=0): index = start while index < len(strng): if strng[index] == ch: return index index += 1 return -1Výsledek volání find("banana","a",2) pro tuto verzi fce find bude stejný jako find2, zatímco při volání find("banana","a") bude parametr start nastaven na počáteční hodnotu 0.
Přidáním dalšího volitelného parametru do fce find zajistíme prohledávání jak dopředu, tak dozadu:
def find(strng, ch, start=0, step=1): index = start while 0 <= index < len(strng): if strng[index] == ch: return index index += step return -1Zadání hodnoty -1 pro step způsobí zmenšování stavu počítadla. Pro tuto změnu bylo nutné ošetřit jak horní tak i dolní mez proměnné index.
Modul string obsahuje užitečné funkce 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 prvků:
['Template', '_TemplateMetaclass', '__builtins__', '__doc__', '__file__',
'__name__', '_float', '_idmap', '_idmapL', '_int', '_long', '_multimap',
'_re', 'ascii_letters', 'ascii_lowercase', 'ascii_uppercase', 'atof',
'atof_error', 'atoi', 'atoi_error', 'atol', 'atol_error', 'capitalize',
'capwords', 'center', 'count', 'digits', 'expandtabs', 'find', 'hexdigits',
'index', 'index_error', 'join', 'joinfields', 'letters', 'ljust', 'lower',
'lowercase', 'lstrip', 'maketrans', 'octdigits', 'printable', 'punctuation',
'replace', 'rfind', 'rindex', 'rjust', 'rsplit', 'rstrip', 'split',
'splitfields', 'strip', 'swapcase', 'translate', 'upper', 'uppercase',
'whitespace', 'zfill']
Typ prvku zjistíme příkazem type. Při zadávání argumentu použijeme tečkovou notaci
>>> type (string.digits) <type 'str'> >>> type (string.find) <type 'function'>Protože string.digits je řetězec, můžeme jej vytisknout a zjistit co obsahuje:
>>> print(string.digits) 0123456789Že obsahuje všechny dekadické číslice nás nepřekvapí.
string.find je funkce, která dělá skoro to samé jako funkce, kterou jsme sami napsali. Bližší informaci získáme vytištěním jejího dokumentačního řetězce (docstring) __doc__:
>>> print string.find.__doc__
find(s,sub [,start [,end]]) -> in
Return the lowest index in s where substring sub is found,
such that sub is contained within s[start,end]. Optional
arguments start and end are interpreted as in slice notation.
Return -1 on failure.
Parametry v hranatých závorkách jsou nepovinné. Fci string.find můžeme použít stejně jako naši find:
>>> fruit = "banana" >>> index = string.find(fruit, "a") >>> print index 1
Tento příklad ukazuje jednu z výhod modulů - s jejich použitím se můžeme vyhnout kolizím mezi jmény vestavěných a uživatelsky definovaných funkcí. Pomocí tečkové notace můžeme určit kterou verzi find chceme.
Funkce string.find je ve skutečnosti všestrannější než naše verze. Umí nalézt i části řetězců, nejenom pouhé znaky:
>>> string.find("banana", "na")
2
Jako naše i tato přijímá dodatečný argument, který určuje index u kterého má začít:
>>> string.find("banana", "na",3)
4
Odlišně od naší, její druhý nepovinný parametr určuje index, u kterého má hledání skončit:
>>> string.find("bob", "b",1,2)
-1
V tomto případě skončí hledání nezdarem, protože se písmeno b nevyskytuje v intervalu od 1 do 2 (nikoliv včetně).
Často bývá užitečné otestovat jednotlivý znak a zjistit, zda je to velké či malé písmeno, nebo zda to je číslice. Modul string poskytuje několik konstant, které jsou pro tyto účely vhodné.
Funkce string.lowercase obsahuje všechna písmena, která systém řadí mezi malá. Podobně string.uppercase obsahuje všechna velká písmena. Vyzkoušejme si následující a uvidíme, co dostaneme:
>>> print string.lowercase >>> print string.uppercase >>> print string.digits
Tyto konstanty a funkci find můžeme použit k vyhodnocení znaků. Vrátí-li například string.lowercase,ch) hodnotu jinou než -1, pak ch musí být malé písmeno:
def is_lower(ch): return string.find(string.lowercase, ch) != -1
Případně můžeme využít operátoru in, který určí, zda se znak nachází v řetězci:
def is_lower(ch): return ch in string.lowercase
Jako další alternativu můžeme použít porovnávací operátor:
def is_lower(ch): return 'a' <= ch <= 'z'
Je-li ch mezi a a z, pak to musí být malé písmeno.
Další konstanta z modulu string nás možná překvapí, když ji vytiskneme:
>>> print string.whitespace
Znaky whitespace posouvají kurzor, aniž by se cokoli tisklo. Vytvářejí bílé místo (alespoň na bílém papíře) mezi viditelnými znaky. Konstanta string.whitespace obsahuje všechny znaky whitespace, včetně space, tab (\t) a newline (\n).
V modulu string je ještě celá řada dalších užitečných funkcí, ale tato kniha není míněna jako referenční příručka na rozdíl od Python Library Reference. Spolu s haldou další dokumentace je přístupná na www.python.org.
Nejjednodušší a přitom účinný způsob formátování řetězce je s použitím operátoru pro formátování řetězce % spolu s formátovacími operacemi Pythonu. Nejlépe si to ukážeme na několika příkladech:
>>> "Jmenuje se %s." % "Arthur" 'Jmenuje se Arthur' >>> name = "Alice" >>> age = 10 >>> "I am %s" and I am %d years old." % (name, age) 'I am Alice and I am 10 years old' >>> n1 = 4 >>> n2 = 5 >>> "2**10 = %d and %d*%d = %f" % (2**10, n1, n2, n1*n2) '2**10 = 1024 and 4*5 = 20.000000' >>>
Schema formátování řetězce vypadá takto:
"<FORMAT >" % "<VALUES >"Část format obsahuje pořadí znaků a konverzní specifikace. Konverzní specifikace se skládají z operátoru % a označení typu hodnoty. Následuje samotný znak % a poté pořadí hodnot, pro každou specifikaci jedna. Závorky jsou nepovinné, je-li hodnota pouze jedna.
V prvním uvedeném příkladě je jediná konverzní specifikace %s, která označuje řetězec. K ní se přiřazuje jediná hodnota "Arthur" a není uzavřena v závorkách.
Ve druhém příkladě má name hodnotu řetězce "Alice" a age má hodnotu celého čísla 10. Tyto se přiřazují ke dvěma konverzním specifikacím %s a %d; druhá specifikace je označením celého dekadického čísla.
Ve třetí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. Čtyři hodnoty, které se vztahují k uvedeným čtyřem konverzním specifikacím jsou: 2**10,n1,n2 a n1*n2.
Znaky s,d a f jsou všechny konverzní typy, které v této knize budeme potřebovat. Jejich úplný seznam můžeme nalézt v části String Formatting Operations referenční příručky Python Library Reference.
Následujicí problém ilustruje praktické užití formátování řetězce:
i = 1 print "i\ti**2\ti**3\ti**5\ti**10\ti**20" 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é 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 :
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
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
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.
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
prefixes = "JKLMNOPQ" suffix = "ack" for letter in prefixes: print letter + suffix
fruit = "banana" count = 0 for char in fruit: if char == 'a': count = count + 1 print counta zobecni ji tak, aby brala řetězec a písmeno jako argument.
def reverse (s): """ >>> reverse ('happy') 'yppah' >>> reverse ('Python') 'nohtyP' >>> reverse ('') '' >>> reverse ('P') 'P' """ if __name__ == '__main__': import doctest doctest.testmod()Přidej tělo funkce tak, aby prošla zkouškou doctestů.
def mirror (s): """ >>> mirror ('good') 'gooddoog' >>> mirror ('yes') 'yessey' >>> mirror ('Python') 'PythonnohtyP' >>> mirror ('') '' >>> mirror ('a') 'aa' """Napiš tělo funkce tak, aby pracovala tak, jak naznačují doctesty.
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' """Napiš tělo funkce tak, aby pracovala tak, jak naznačují doctesty.
def is_palindrome (s): """ >>> is_palindrome('abba') True >>> is_palindrome('abab') False >>> is_palindrome('tenet') True >>> is_palindrome('banana') False >>> is_palindrome('straw warts') True """ def count (sub, s): """ >>> count('is', 'Mississippi') 2 >>> count('an', 'banana') 2 >>> count('ana', 'banana') 2 >>> count('nana', 'banana') 1 >>> count('nanan', 'banana') 0 """ def remove (sub, s): """ >>> remove('an', 'banana') 'bana' >>> remove('cyc', 'bicycle') 'bile' >>> remove('iss', 'Mississippi') 'Missippi' >>> remove('egg', 'bicycle') 'bicycle' """ def remove_all (sub, s): """ >>> remove_all('an', 'banana') 'ba' >>> remove_all('cyc', 'bicycle') 'bile' >>> remove_all('iss', 'Mississippi') 'Mippi' >>> remove('eggs', 'bicycle') 'bicycle' """až všechny doctesty budou vyhovovat.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |