previous up next hi englisch index

9. Seznamy

  1. Hodnoty seznamu
  2. Přístup k položkám
  3. Délka seznamu
  4. Příslušnost položky
  5. Operace se seznamy
  6. Úseky seznamu
  7. Funkce 'range'
  8. Seznamy jsou měnitelné
  9. Smazání položek
  10. Objekty a hodnoty
  11. Další jméno - alias
  12. Klonování seznamů
  13. Seznamy a smyčky 'for'
  14. Seznam jako parametr
  15. Čisté funkce a modifikátory
  16. Co je lepší?
  17. Vnořené seznamy
  18. Matice
  19. Testem podnícený rozvoj (TDD)
  20. Řetězce a seznamy
  21. Glosář
  22. Cvičení

Seznam (list) je uspořádaná řada hodnot s připojeným indexem. Jednotlivým hodnotám říkáme položky seznamu. Seznamy jsou podobné řetězcům, jež jsou uspořádané řady znaků; položky seznamu mohou být však libovolného typu. Seznamy, řetězce a jiné entity, které se chovají jako uspořádané řady, nazýváme sekvence.

9.1 Hodnoty seznamu

Nový seznam vytvoříme nejjednodušeji uzavřením položek do hranatých závorek [ ].

[10, 20, 30, 40]
["spam", "bungee", "swallow"]

Prvním příkladem je seznam čtyř celých čísel. Druhým je seznam tří řetězců. Položky seznamu nemusí být stejného typu. Následující seznam obsahuje řetězec, float (číslo v plovoucí řádové čárce), integer (celé číslo) a (mirabile dictu) další seznam:

["hello", 2.0, 5, [10, 20]]

Seznamu uvnitř jiného seznamu říkáme, že je vnořený.

Konečně, existuje speciální seznam, který neobsahuje žádné položky. Nazývá se prázdný seznam a značí se [ ].

Stejně jako číselná hodnota 0 a prázdný řetězec, je prázdný seznam nepravdivý v booleovských výrazech:.

>>> if []:
...    print "This is true."
... else :
...    print "This is false."
...
This is false.
>>>

Při všech těchto možnostech tvorby seznamů by bylo zklamáním, kdybychom nemohli přiřadit seznam hodnot k proměnné, nebo zadat seznam jako parametr funkce. Věc se má tak, že můžeme.

>>>vocabulary = ["ameliorate", "castigate", "defenestrate"]
>>>numbers = [17, 123]
>>>empty = []
>>>print vocabulary, numbers, empty
['ameliorate', 'castigate', 'defenestrate'] [17, 123] []

9.2 Přístup k položkám

Syntaxe pro přístup k položkám seznamu je stejná jako syntaxe pro přístup ke znakům řetězce – pomocí hranatých závorek [ ] (nezaměňovat s prázdným seznamem). Výraz v závorkách určuje index položky. Nezapomeňme, že indexy začínají nulou:

>>> print numbers[0]
17

Jako index lze použít jakýkoli celočíselný výraz:

>>> numbers[9-8]
5
>>> numbers[1.0]
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: list indices must be integers    

Pokusíme-li se číst nebo psát položku, která neexistuje, dostaneme chybu při běhu programu:

>>> numbers[2]
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
IndexError: list index out of range   

Má-li index zápornou hodnotu, počítá se od konce seznamu:

>>> numbers[-1]
5
>>> numbers[-2]
17
>>> numbers[-3]
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
IndexError: list index out of range    

numbers[-1] je poslední položka seznamu, numbers[-2] je předposlední a numbers[-3] neexistuje.

Je obvyklé použít proměnnou smyčky jako index seznamu:

horsemen = ["war", "famine", "pestilence", "death"]

i = 0
while i < 4:
    print horsemen[i]
    i = i + 1

Tato smyčka počítá od 0 do 4. Jakmile má proměnná smyčky hodnotu 4, podmínka nevyhoví a smyčka končí. Takže tělo smyčky je provedeno pro i = 0, 1, 2 a 3.

Při každém cyklu smyčky je proměnná i použita jako index položky, která se tiskne. Tento způsob výpočtu se nazývá traverzování seznamem.

9.3 Délka seznamu

Funkce len vrací délku seznamu, což je počet jeho položek. Tato hodnota se výhodně používá jako horní mez smyčky místo konstanty. Tím si zajistíme, že pokaždé, když se změní velikost seznamu, nemusíme procházet programem, abychom opravili všechny dotčené smyčky:

horsemen = ["war", "famine", "pestilence", "death"]

i = 0
while i < len(horsemen):
    print horsemen[i]
    i = i + 1

Po posledním provedením těla smyčky je i=len(horsemen)-1, což je index poslední položky. Je-li i=len(horsemen), podmínka není splněna a tělo se neprovede, což je dobré, protože len(horsemen) není přípustný index.

I když jeden seznam může obsahovat další seznam, ten vnořený se stále počítá jako jedna položka. Délka tohoto seznamu je 4:

['spam!', 1, ['Brie', 'Roquefort', 'Pol le Veq'], [1, 2, 3]]

9.4 Příslušnost

Klíčové slovo in je booleovský operátor, který testuje příslušnost prvku k sekvenci. Použili jsme jej už u řetězců a pracuje také se seznamy a jinými uspořádanými množinami:

>>> horsemen = ['war', 'famine', 'pestilence', 'death']
>>> 'pestilence' in horsemen
True
>>> 'debauchery' in horsemen
False

Protože pestilence je částicí seznamu horsemen, vrátí operátor in hodnotu True. Jelikož debauchery v seznamu není, vrátí False.

Můžeme použít slovo not ve spojení s in, abychom ověřili, že položka není částicí seznamu:

>>> 'debauchery' not in horsemen
True

9.5 Operace se seznamy

Operátor + zřetězí seznamy:

>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = a + b
>>> print c
[1, 2, 3, 4, 5, 6]

Podobně, operátor * opakuje seznam v zadaném počtu:

>>> [0] * 4
[0, 0, 0, 0]
>>> [1, 2, 3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]

První příklad opakuje [0] čtyřikrát. Druhý příklad opakuje seznam [1, 2, 3] třikrát.

9.6 Úseky seznamu

Operace s úseky, které jsme poznali u řetězců, platí také u seznamů:

>>> list = ['a', 'b', 'c', 'd', 'e', 'f']
>>> list[1:3]
['b', 'c']
>>> list[:4]
['a', 'b', 'c', 'd']
>>> list[3:]
['d', 'e', 'f']
>>> list[:]
['a', 'b', 'c', 'd', 'e', 'f']

9.7 Funkce 'range'

Seznamy, které obsahují po sobě jdoucí celá čísla jsou tak běžné, že Python poskytuje jednoduchý způsob jejich tvorby:

>>> range(1, 5)
[1, 2, 3, 4]

Funkce range přijímá dva argumenty a vrací seznam, který obsahuje všechna mezilehlá celá čísla; včetně prvního, vyjma druhého (argumentu).

Jsou dvě další formy fce range. S jediným argumentem vytvoří seznam, který začíná nulou:

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Případný třetí argument určí rozdíl mezi sousedními hodotami a nazývá se krok. Následující příklad počítá od 1 do 10 s krokem 2:

>>> range(1,10, 2)
[1, 3, 5, 7, 9]

Je-li hodnota kroku záporná, potom počátek musí být větší než konec,

>>> range(10,4, -5)
[20, 15, 10, 5]

jinak bude výsledkem prázdný seznam.

>>> range(10,20, -5)
[]

9.8 Seznamy jsou měnitelné

Na rozdíl od řetězců jsou seznamy měnitelné, což znamená, že můžeme měnit jejich položky. Použitím závorkového operátoru na levé straně můžeme obměnit jednu z položek:

>>> fruit = ["banana", "apple", "quince"]
>>> fruit[0] = "pear"
>>> fruit[-1] = "orange"
>>> print fruit
['pear', 'apple', 'orange']

Závorkový operátor můžeme u seznamu použít kdekoliv ve výrazu. Objeví-li se na levé straně přiřazení, mění jednu z položek seznamu. Přiřazení hodnoty položce se nazývá položkové přiřazení (item assignment). Takovéto přiřazení nejde použít u řetězců:

>>> my_string = 'TEST'
>>> my_string[2] = 'X'
Traceback (most recent call last):
  File "<stdin >", line 1, in <module > 
TypeError: 'str' object does not support item assignment 
(objekt 'str' nepodporuje položkové přiřazení)

ale podporuje je pro seznamy:

>>> my_list = ['T', 'E', 'S', 'T']
>>> my_list[2] = 'X'
>>> my_list
['T', 'E', 'X', 'T']

Úsekovým operátorem můžeme změnit několik položek najednou:

>>> a_list = ['a', 'b', 'c', 'd', 'e', 'f']
>>> a_list[1:3] = ['x', 'y']
>>> print a_list
['a', 'x', 'y', 'd', 'e', 'f']

Můžeme také odstranit položky ze seznamu tím, že je nahradíme prázdným seznamem:

>>> a_list = ['a', 'b', 'c', 'd', 'e', 'f']
>>> a_list[1:3] = []
>>> print a_list
['a', 'd', 'e', 'f']

A můžeme také přidat položky do seznamu vmáčknutím do prázdného úseku v potřebném místě:

>>> a_list = ['a', 'd', 'f']
>>> a_list[1:1] = ['b', 'c']
>>> print a_list
['a', 'b', 'c', 'd', 'f']
>>> a_list[4:4] = ['e']
>>> print a_list
['a', 'b', 'c', 'd', 'e', 'f']

9.9 Smazání položek

Použití úseků k výmazu položek je neohrabané a proto náchylné k chybám. Python poskytuje šikovnější alternativu.

Příkaz del odstraní položku ze seznamu:

>>> a = ['one', 'two', 'three']
>>> del a[1]
>>> a
['one', 'three']

Nepřekvapí nás, že del manipuluje také se zápornými indexy a vyvolá chybu při běhu programu, je-li index mimo dovolený rozsah.

Jako indexy pro del můžeme použít také úseky:

>>> list = ['a', 'b', 'c', 'd', 'e', 'f']
>>> del list[1:5]
>>> print list
['a', 'f']

Jako obvykle, úseky vyberou všechny položky zadaného rozsahu, kromě druhého indexu.

9.10 Objekty a hodnoty

Provedeme-li tyto příkazy přiřazení,

a = "banana"
b = "banana"

víme, že a a b poukazují na řetězec s písmeny "banana". Není však zřejmé, zda se jedná o tentýž řetězec.

Jsou dvě možné situace:

V prvním případě odkazují a a b ke dvoum různým věcem, které mají stejnou hodnotu. Ve druhém případě odkazují k téže věci. Těmto "věcem" říkáme objekty. Objekt je něco, na co může proměnná odkazovat.

Každý objekt má jedinečný identifikátor, k němuž máme přístup prostřednictvím funkce id. Jeho vytištěním můžeme zjistit, zda se obě proměnné a i b odkazují ke stejnému objektu:

>>> id(a)
135044008
>>> id(b)
135044008

Dostali jsme dvakrát stejný identifikátor, což znamená, že Python vytvořil pouze jeden řetězec a jak a, tak b se k němu odkazují.

Je zajímavé, že seznamy se chovají odlišně. Vytvoříme-li dva seznamy, dostaneme dva objekty:

>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> id(a) == id(b)
False

Zobrazení vztahů vypadá tedy takto:

Proměnné a a b mají stejnou hodnotu ale nevztahují se ke stejnému objektu.

9.11 Další jméno - alias

Proměnné odkazují k objektům; přiřadíme-li jednu proměnnou ke druhé, potom obě proměnné odkazují ke stejnému objektu:

>>> a = [1, 2, 3]
>>> b = a
>>> id(a) == id(b)
True

V tomto případě vypadá schema vztahů takto:

Protože tentýž seznam má dvě různá jména (a, b), říkáme, že je aliasován. Změny provedené s jedním aliasem se projeví i u druhého:

>>> b[0] = 5
>>> print a
[5, 2, 3]

I když toto chování může být užitečné, je někdy nečekané, ba přímo nežádoucí. Obecně vzato, pracujeme-li s měnitelnými objekty, je bezpečnější se aliasování vyhnout. S neměnitelnými objekty ovšem žádný problém není. Proto Python aliasuje řetězce docela běžně.

9.12 Klonování seznamů

Chceme-li provést úpravy v seznamu a zároveň si uchovat kopii originálu, potřebujeme zkopírovat samotný seznam, nikoliv jen jeho odkaz. Tomuto procesu někdy říkáme klonování, abychom se vyhnuli dvojznačnosti slova "kopírování".

Nejjednodušší způsob klonování je užití úsekového operátoru:

>>> a = [1, 2, 3]
>>> b = a[:]
>>> print b
[1, 2, 3]

Vytvoření úseku vytváří nový seznam. V tomto případě je úsekem celý seznam.

Nyní můžeme měnit b bez obav o a.

>>> b[0] = 5
>>> print a
[1, 2, 3]

9.13 Seznamy a smyčky 'for'

Smyčku for lze použít i u seznamů. Zobecněná skladba je tato:

for VARIABLE in LIST:
    BODY    

Tento příkaz je rovnocenný zápisu:

i = 0
while i < len(LIST):
    VARIABLE = LIST[i]
    BODY
    i += 1   

Smyčka for je stručnější, protože se obejdeme bez její proměnné i. Zde je dříve vytvořená smyčka s použitím for:

for horseman in horsemen:
    print horseman

Čte se to téměř jako prostá čeština: "Pro každého žokeje v (seznamu) žokejů vytiskni (jméno) žokeje."

Použití smyčky for je velmi rozmanité:

for number in range(20):
    if number%3 == 0:
        print number

for fruit in ["banana", "apple", "quince"]:
    print "I like to eat" + fruit +"s!" 

První příklad vytiskne všechny násobky 3 mezi 0 a 19. Druhý příklad vyjádří nadšení pro různé druhy ovoce.

Měnitelnost seznamu nám umožňuje upravit při traverzování každou jeho položku. Následující kód vytvoří druhé mocniny čísel od 1 do 5:

numbers = [1, 2, 3, 4, 5]
for index in range(len(numbers)):
   numbers[index] = numbers[index]**2

Zamyslete se nad příkazem range(len(numbers)) a snažte se pochopit, jak tento příkaz pracuje. Uvnitř seznamu nás zajímá jak hodnota položky, tak i její index.

Tento postup je natolik běžný, že Python nabízí k použití i jiný způsob:

numbers = [1, 2, 3, 4, 5]
for index, value in enumerate(numbers):
   numbers[index] = value**2

enumerate generuje při traverzování seznamem jak index, tak i odpovídající hodnotu. Pro lepší pochopení práce příkazu enumerate si vyzkoušej následující příklad:

>>> for index, value in enumerate(['banana', 'apple', 'pear', 'quince', ]):
...    print index, value 
...
0 banana
1 apple
2 pear
3 quince
>>>    

9.14 Seznam jako parametr

Při zadávání seznamu jako argument se ve skutečnosti předává odkaz, nikoliv kopie seznamu. Protože jsou seznamy měnitelné, mohou být jeho položky použitou funkcí změněny. Například, následující funkce přijme seznam jako argument a vynásobí dvěma každou jeho položku:

def double_stuff(a_list):
    for index, value in enumerate(a_list):
        a_list[index] = 2 * value    

Vložíme-li double_stuff do souboru se jménem ch09.py, můžeme si postup vyzkoušet:

>>> from ch09 import double_stuff
>>> things = [2,5,'spam',9.5]
>>> double_stuff(things)
>>> things
[4, 10, 'spamspam', 19.0]
>>>

Parametr a_list a proměnná things jsou aliasy pro tentýž objekt.

9.15 Čisté funkce a modifikátory

Funkce, které přijmou seznam jako argument a změní jej při provádění, se nazývají modifikátory a změnám které provedou na zadaném argumentu, se říká vedlejší účinky. Funkci s uvedenými vlastnostmi jsme si zapsali v předchozím odstavci.

Čistá funkce neprodukuje vedlejší účinky. Komunikuje s okolním programem pouze prostřednictvím parametrů které nepřetváří a prostřednictvím výstupní hodnoty. Zde je double_stuff jako čistá funkce:

 def  double_stuff ( a_list ):
     new_list = [] 
     for  value in a_list:
         new_list += [2*value]       
     return  new_list    

Tato verze double_stuff nemění své argumenty:

>>> from ch09 import double_stuff
>>> things = [2,5,'spam',9.5]
>>> double_stuff(things)
[4, 10, 'spamspam', 19.0]
>>> things
[2, 5, 'spam', 9.5]
>>>

Chceme-li aby čistá funkce double_stuff změnila seznam things, přiřadíme mu výstupní hodnotu fce:

>>> thigs = double_stuff(things)
>>> things 
[4, 10, 'spamspam', 19.0]
>>>

9.16 Co je lepší?

Všechno, co může být provedeno pomocí modifikátorů, může být také provedeno čistými funkcemi. Některé programovací jazyky znají vlastně jenom čisté funkce. Má se zato, že čisté funkce se snadněji tvoří a jsou méně náchylné k chybám než programy, které používají modifikátory. Nicméně, modifikátory jsou někdy vhodné a v některých případech jsou programy s čistými funkcemi méně výkonné.

Doporučujeme tedy používat čisté funkce kdykoli je to účelné, a k modifikátorům se uchylovat jen při zjevné výhodnosti. Tento přístup lze označit jako funkcionální programovací styl.

9.17 Vnořené seznamy

Vnořený seznam je seznam, kteý se vyskytuje jako položka jiného seznamu. V naší ukázce je položka s indexem 3 vnořeným seznamem:

>>> nested = ["hello", 2.0, 5, [10,20]]

Zadáme-li nested[3], dostaneme [10,20]. Abychom vyjmuli položku z vnořeného seznamu, můžeme postupovat ve dvou krocích:

>>> elem = nested[3]
>>> elem[0]
10

Nebo tyto kroky můžeme zkombinovat:

>>> nested[3][1]
20

Operátory s hranatými závorkami jsou vyhodnocovány zleva doprava, takže tento výraz dává nejprve tři-tou položku seznamu nested a z ní vyjme položku s indexem 1.

9.18 Matice

Vnořené seznamy se často používají k vyjádření matic. Například, matice:

může být vyjádřena takto:

>>> matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

matrix je seznam se třemi položkami, kde každá položka je řadou matice. Můžeme vybrat celou řadu matice obvyklým způsobem:

>>> matrix[1]
[4, 5, 6]

Nebo můžeme vyjmout jedinou položku z matice s použitím dvojitého indexu:

>>> matrix[1][1]
5

První index vybere řadu, druhý index vybere sloupec. I když tento způsob prezentace matic je obvyklý, není jediný. Malou obměnou je použití seznamu sloupců místo seznamu řad. Později poznáme radikálnější alternativu s použitím slovníku.

9.19 Testem podnícený rozvoj

Testem podnícený rozvoj (Test-driven development - TDD) je způsob vyvíjení programu, při kterém se postupuje po malých, automaticky ověřovaných krocích.

Tento přístup si předvedeme na doctestech, které jsme poznali již v odstavci 5.8. Řekněmež, že chceme funkci, která vytvoří matici m krát n  (rows krát columns).

Nejprve pro tuto funkci sestavime test v souboru matrices.py:

def make_matrix (rows, columns):
    """ 
    >>> make_matrix(3,5)
    [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]       
    """ 

if  __name__ == '__main__':
    import doctest 
    doctest:testmod()  

Provedení skriptu skončí neúspěchem:

**********************************************************************
File "matrices.py", line 3, in __main__.make_matrix
Failed example:
    make_matrix(3, 5)
Expected:
    [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
Got nothing
**********************************************************************
1 items had failures:
   1 of   1 in __main__.make_matrix
***Test Failed*** 1 failures.

Test nebyl úspěšný proto, že tělo funkce obsahuje pouze dokumentační řetězec a žádný příkaz return, takže je vráceno Got nothing. Náš test nám naznačuje, že jsme chtěli vrátit matici se samými nulami ve třech řadách a pěti sloupcích.

Při použití TDD zpravidla napíšeme to nejjednodušší, co projde testem, v našem případě to je příkaz return:

def make_matrix (rows, columns):
    """ 
    >>> make_matrix(3,5)
    [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]       
    """ 
    return [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]

Při provedení tohoto skriptu v testu obstojíme, ale fce make_matrix vrací stále týž výsledek, což zajisté není to, co jsme zamýšleli. Motivujme naše vylepšení přidáním testu:

def make_matrix (rows, columns):
    """ 
    >>> make_matrix(3,5)
    [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]      
    >>> make_matrix(4,2)
    [[0,0], [0,0], [0,0], [0,0]]
    """ 
    return [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]

což zcela nepochybně opět neprojde:

**********************************************************************
File "matrices.py", line 5, in __main__.make_matrix
Failed example:
    make_matrix(4, 2)
Expected:
    [[0, 0], [0, 0], [0, 0], [0, 0]]
Got:
    [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
**********************************************************************
1 items had failures:
   1 of   2 in __main__.make_matrix
***Test Failed*** 1 failures.

Tato technika se nazývá testem podnícená, protože se snažíme upravovat kód tak, abychom prošli testem. Motivováni nezdařeným pokusem, můžeme nyní zkusit obecnější řešení:

def make_matrix (rows, columns):
    """ 
    >>> make_matrix(3,5)
    [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]       
    >>> make_matrix(4,2)
    [[0,0], [0,0], [0,0], [0,0]]  
    """ 
    return [[0]* columns]* rows

Zdá se, že toto řešení chodí a můžeme si myslet, že jsme hotovi, ale později objevíme chybu:

 
>>> from matrices import *
>>> m = make_matrix(4, 3)
>>> m
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>>m[1][2] = 7
>>>m
[[0, 0, 7], [0, 0, 7], [0, 0, 7], [0, 0, 7]]
>>>

Chtěli jsme přiřadit hodnotu 7 položce ve druhé řadě a třetím sloupci a místo tohtoho mají všechny položky ve třetím sloupci hodnotu 7!

Po chvilce přemýšlení si uvědomíme, že v našem řešení je rows označení pro každou řadu (viz alias). To zcele určitě není to, co jsme chtěli a proto se pustíme do nápravy problému nejprve tím, že napíšeme test, o kterém předem víme, že neprojde:

def make_matrix (rows, columns):
    """ 
    >>> make_matrix(3,5)
    [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]       
    >>> make_matrix(4,2)
    [[0,0], [0,0], [0,0], [0,0]]
    >>> m = make_matrix(4, 2)
    >>> m[1][1] = 7
    >>> m
    [[0,0], [0,7], [0,0], [0,0]] 
    """ 
    return [[0]* columns]* rows

Maje co napravovat, jsme hnáni k lepšímu řešení:

def make_matrix (rows, columns):
    """ 
    >>> make_matrix(3,5)
    [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]       
    >>> make_matrix(4,2)
    [[0,0], [0,0], [0,0], [0,0]]
    >>> m = make_matrix(4, 2)
    >>> m[1][1] = 7
    >>> m
    [[0,0], [0,7], [0,0], [0,0]] 
    """ 
    matrix = []
    for row  in range(rows)):
        matrix += [[0]* columns]
    return matrix

Užití TDD poskytuje našemu programátorskému snažení několik výhod:

9.20 Řetězce a seznamy

Python má příkaz se jménem list který vezme uspořádanou řadu jako argument a vytvoří z jejích prvků seznam:

>>> list ("Crunchy Frog")
['C', 'r', 'u', 'n', 'c', 'h', 'y', ' ', 'F', 'r', 'o', 'g']

Existuje také příkaz str, který z libovolné hodnoty argumentu vytvoří řetězec:

>>> str (5)
'5'
>>> str (None)
'None'
>>> str (list("nope"))
"['n', 'o', 'p', 'e']"

Dostali jsme řetězec s dvaceti znaky, včetně tří mezer. Jak vidíme u tohoto příkladu, str nelze použít ke spojení seznamu znaků. Za tím účelem můžeme použít funkci join z modulu string:

>>> import string
>>> char_list = list("Frog")
>>> char_list
['F', 'r', 'o', 'g']
>>> string.join(char_list, '')
'Frog'

Další důležitá funcke v modulu string se týká seznamu řetězců. Funkce split rozloží řetězec na seznam slov. Libovolný počet znaků pro mezeru je implicitně považován za hranici slov:

>>> import string
>>> song = "The rain in Spain..."
>>> string.split(song)
['The', 'rain', 'in', 'Spain... ']
>>> 

Libovolný argument, nazvaný oddělovač (delimiter), může být použit k určení znaků, které mají sloužit jako hranice slov. Následující příklad používá jako oddělovač řetězec ai:

>>> string.split(song, 'ai')
['The r', 'n in Sp','n... ']
>>> 

Všimněte si, že se oddělovač v seznamu neobjevuje.

Fce string.join je inverzní funkcí k fci string.split. Přijímá dva argumenty: seznam řetězců a separátor, který bude umístěn mezi položky seznamu ve výsledném řetězci.

>>> import string
>>> words = ['crunchy', 'raw', 'unboned', 'real', 'dead', 'frog', ]
>>> string.join(words, '')
'crunchy raw unboned real dead frog'
>>> string.join(words, '**')
'crunchy**raw**unboned**real**dead**frog'

9.21 Glosář

seznam (list)
Pojmenovaný soubor objektů, kde každý objekt je označen indexem.
index
Celočíselná proměnná nebo hodnota, která označuje položku seznamu.
položka (element)
Jedna z hodnot seznamu (nebo jiné sekvence). Operátor z hranatých závorek vybere položku ze seznamu.
sekvence (sequence)
Jakýkoliv datový typ, skládající se z uspořadané řady položek, kde každá položka je určena indexem.
vnořený seznam (nested list)
Seznam, který je položkou jiného seznamu.
krok (step size)
Interval mezi sousedními položkami v lineární sekvenci. Také třetí (a nepovinný) argument fce range. Není-li zadán, jeho počáteční hodnota je 1.
traverzování seznamem (list traversal)
Postupný výběr každé položky seznamu.
měnitelný datový typ (mutable data type)
Datový typ, jehož položky mohou být měněny. Všechny měnitelné typy jsou složené typy. Seznamy jsou měnitelné datové typy, řetězce nikoliv.
objekt (object)
Něco, na co může být odkazováno proměnnou.
alias
Vícero proměnných, odkazujících na stejný objekt.
klonovat (clone)
Vytvořit nový objektu, který má stejnou hodnotu jako stávající objekt. Kopírování odkazu na objekt vytvoří alias, nikoliv klon.
modifikátor (modifier)
Funkce, která změní zadané argumenty. Pouze měnitelné datové typy mohou být měněny modifikátory.
vedlejší účinek (side effect)
Změna položek seznamu, který byl zadán jako argument volané funkci. Tuto schopnost mají modifikátory.
čistá funkce (pure funkction)
Funkce bez vedlejších účinků. Čisté funkce poskytnou změnu argumentu jen na svém výstupu.
testem podnícený rozvoj (test-driven development, TDD)
Postup při programování, při kterém se dospěje k žádanému cíli přes řadu malých, postupných kroků, jež jsou motivovány zautomatizovanými testy.
oddělovač (delimiter)
Znak nebo řetězec použitý k označení místa, kde má být jiný řetězec rozdělen.

9.22 Cvičení

  1. Napiš smyčku, která traverzuje seznamem:
    ['spam!', 1, ['Brie', 'Roquefort', 'Pol le Veq'], [1, 2, 3]]
    
    a vytiskne délku každé položky. Co se stane, zadáme-li funkci len jako argument celé číslo?
  2. Vytvoř soubor ch09e02.py s následujícím obsahem:
    # Zde zadej svoje doctesty:
    """
    """
    # Zde napis svoje programy:
    
    if __name__ == '__main__':
        import doctest
        doctest.testmod()   
    

    Přidávej následující doctesty do dokumentačního řetězce v předchozím skriptu a napiš k nim vyhovující kódy.

    1. """
        >>> a_list[3]
        42
        >>> a_list[6]
        'Ni!'
        >>> len(a_list)
        8
      """
      
    2. """
        >>> b_list[1:]
        ['Stills', 'Nash']
        >>> group = b_list + c_list
        >>> group[-1]
        'Young'
      """
      
    3. """
        >>> 'war' in mystery_list
        False
        >>> 'peace' in mystery_list
        True
        >>> 'justice' in mystery_list
        True
        >>> 'oppression' in mystery_list
        False
        >>> 'equality' in mystery_list
        True
      """
      
    4. """
        >>> range(a, b, c)
        [5,9,13,17]
      """
      

    Přidávej vždy jen jednu sadu doctestů a nepřidávej další, dokud předchozí sada neprošla zkouškami.

  3. Jaká je odezva IRP (interaktivní rozhraní překladače) na následující zápis?
    >>> range(10, 0, -2)
    

    Tři argumenty pro funkci range jsou start, stop a step. V našem příkladě je start větší než stop. Co se stane, když start<stop a step<0? Napiš pravidlo pro vztahy mezi start, stop a step.

  4. a = [1, 2, 3]
    b = a[:]
    b[0] = 5
    
    Nakresli schematické zobrazení vztahu mezi a a b před provedením třetího řádku a po jeho provedení.
  5. Jaký bude výstup následujícího programu?
    this = ['I', 'am', 'not', 'a', 'crook']
    that = ['I', 'am', 'not', 'a', 'crook']
    print "Test 1: %s" % (id(this) == id(that))
    that = this
    print "Test 2: %s" % (id(this) == id(that))
    
    Přidej podrobné vysvětlení výsledků.
  6. Vytvoř soubor ch09e06.py a použij stejný postup jako ve cvičení 2 pro zajištění shody s doctesty:
    1. """
        >>> 13 in junk
        True
        >>> del junk[4]
        >>> junk
        [3, 7, 9, 10, 17, 21, 24, 27]
        >>> del junk[a:b]
        junk
        [3, 7, 27]
      """
      
    2. """
        >>> nlist[2][1]
        0
        >>> nlist[0][2]
        17
        >>> nlist[1][1]
        5
      """
      
    3. """
        >>> import string
        >>> string.split(message, '??')
        ['this', 'and', 'that']
      """
      
  7. Napiš funkci add_lists(a,b) která přijme dva seznamy stejné délky s celými čísly a vrátí nový seznam se součty odpovídajících položek.
    def add_lists(a, b):
      """
       >>> add_lists([1,1], [1,1])     
       [2, 2]
       >>> add_lists([1,2], [1,4])     
       [2, 6]
       >>> add_lists([1,2,1], [1,4,3])     
       [2, 6, 4]
      """
    

    Fce add_lists musí být ve shodě s uvedenými doctesty.

  8. Napiš funkci mult_lists(a, b) která přijme dva seznamy stejné délky s celými čísly a vrátí součet součinů odpovídajících položek.
    def mult_lists(a, b):
      """
       >>> mult_lists([1,1], [1,1])     
       2
       >>> mult_lists([1,2], [1,4])     
       9
       >>> mult_lists([1,2,1], [1,4,3])     
       12
      """
    

    Ověř si, že fce mult_lists vyhovuje uvedeným doctestům.

  9. Přidej následující dvě funkce do soubouru matrices.py, který jsme vytvořili v odstavci 9.19 (TDD).
    def add_row (matrix): 
      """
       >>> m = [[0,0], [0,0]] 
       >>> add_row(m)    
       [[0, 0], [0, 0], [0, 0]]
       >>> n = [[3, 2, 5], [1, 4, 7]]
       >>> add_row(n)
       [[3,2,5], [1,4,7], [0,0,0]]
       >>> n
       [[3,2,5], [1,4,7]]
     """
    def add_column (matrix): 
      """
       >>> m = [[0,0], [0,0]] 
       >>> add_column(m)    
       [[0,0,0], [0,0,0]
       >>> n = [[3,2], [5,1], [4,7]]
       >>> add_column(n)
       [[3,2,0], [5,1,0], [4,7,0]]
       >>> n
       [[3,2], [5,1], [4,7]]
     """
    

    Nové funkce musí projít zkouškou doctestů. Všimni si, že poslední doctesty v každé funkci ověřují, že add_row a add_column jsou funkce čisté.

  10. Napiš funkci add_matrices(m1, m2), která vrátí novou matici, jež je součtem matic m1 a m2. Sečíst dvě matice znamená sečíst hodnoty odpovídajících členů. Můžeš předpokládat, že matice m1 a m2 mají stejnou velikost.
    def add_matrices (m1, m2): 
      """
       >>> a = [[1,2], [3,4]]
       >>> b = [[2,2], [2,2]] 
       >>> add_matrices(a, b)    
       [[3,4], [5,6]
       >>> c = [[8,2], [3,4], [5,7]]
       >>> d = [[3,2], [9,2], [10,12]]
       >>> add_matrices(c, d)
       [[11,4], [12,6], [15,19]]
       >>> c
       [[8,2], [3,4], [5,7]]
       >>> d
       [[3,2], [9,2], [10,12]]
     """
    
    Přidej své funkce do matrices.py a ujisti se, že projdou zkouškou uvedených doctestů. Poslední dva doctesty opět potvrzují, že add_matrices je čistá funkce.
  11. Napiš funkci scalar_mult(n, m), která násobí matici m skalárem n.
    def scalar_mult (n, m): 
      """
       >>> a = [[1,2], [3,4]]
       >>> scalar_mult(3, a)    
       [[3,6], [9,12]
       >>> b = [[3,5,7], [1,1,1], [0,2,0], [2,2,3]]
       >>> scalar_mult(10, b)
       [[30,50,70], [10,10,10], [0,20,0], [20,20,30]]
       >>> b
       [[3,5,7], [1,1,1], [0,2,0], [2,2,3]]
     """
    
    Přidej svoji novou funkci do matrices.py a ujisti se, že projde doctesty.
  12. def row_times_column (m1, row, m2, column): 
      """
       >>> row_times_column[[1,2], [3,4], 0, [5,6], [7,8], 0]
       19
       >>> row_times_column[[1,2], [3,4], 0, [5,6], [7,8], 1]
       22
       >>> row_times_column[[1,2], [3,4], 1, [5,6], [7,8], 0]
       43
       >>> row_times_column[[1,2], [3,4], 1, [5,6], [7,8], 1]
       50
     """
    
    def matrix_mult (m1, m2): 
      """
       >>> matrix_mult([[1,2], [3,4]], [[5,6], [7,8]])
       [[19,22], [43,50]]
       >>> matrix_mult([[1,2,3], [4,5,6]], [[7,8], [9,1], [2,3]])
       [[31,19], [85,55]]
       >>> matrix_mult([[7,8], [9,1], [2,3]], [[1,2,3], [4,5,6]])
       [[39,54,69], [13,23,33], [14,19,24]]
     """
    
    Přidej nové funkce do matrices.py a zajisti shodu s doctesty.
  13. import  string
    
    song = "The rain in Spain..."
    
    Popiš vztah mezi string.join(string.split(song)) a song. Jsou stejné pro všechny řetězce? Kdy se budou lišit?
  14. Napiš funkci replace(s, old, new), která zamění všechny výskyty old za new v řetězci s.
    def replace (s, old, new): 
      """
       >>> replace ('Mississippi','i', 'I')
       'MIssIssIppI'
       >>> s = 'I love spom! Spom is my favorite food. Spom, spom, spom, yum!'
       >>> replace(s, 'om', 'am')
       'I love spam! Spam is my favorite food. Spam, spam, spam, yum!'
       >>> replace(s, 'o', 'a')
       'I lave spam! Spam is my favarite faad. Spam, spam, spam, yum!'
     """
    
    Řešení musí zajité vyhovovat doctestům. Použije se string.split a string.join.

previous up next hi englisch index