9. Zoznamy a n-tice (tuple)¶
Pripomeňme si z minulej prednášky, ako dve premenné referencujú na ten istý zoznam. Priraďme:
>>> a = [2, 3, 5, 7, 11]
>>> b = a
>>> b[3] = 'kuk'
>>> a
[2, 3, 5, 'kuk', 11]
Menili sme obsah premennej b
(zmenili sme jej prvok s indexom 3
), ale tým sa zmenil aj obsah premennej a
. Totiž obe premenné referencujú na ten istý zoznam:

Keď teraz meníme obsah premennej b
pomocou mutable operácií, zmení sa aj obsah premennej a
:

Toto samozrejme platí aj vo funkciách a aj s parametrami funkcií.
Zoznamy vo funkciách¶
Pozrime si takéto školské príklady, v ktorých dostávame chybné riešenie vďaka tomu, že si neuvedomíme, že dve premenné referencujú na ten istý zoznam.
Vytváranie dvoch zoznamov¶
Napíšeme funkciu, ktorá ako parameter dostáva zoznam čísel a jej úlohou je z tohto zoznamu vypísať dva zoznamy - zoznam záporných a zoznam nezáporných čísel; elegantným riešením by mohlo byť:
def vypis_dva_zoznamy(zoznam):
zoz1 = zoz2 = []
for prvok in zoznam:
if prvok < 0:
zoz1.append(prvok)
else:
zoz2.append(prvok)
print('zaporne =', zoz1)
print('nezaporne =', zoz2)
Prekvapením môže byť otestovanie tejto funkcie:
>>> vypis_dva_zoznamy([5, 7.3, 0, -3, 0.0, 1, -3.14])
zaporne = [5, 7.3, 0, -3, 0.0, 1, -3.14]
nezaporne = [5, 7.3, 0, -3, 0.0, 1, -3.14]
Všimnite si priradenie zoz1 = zoz2 = []
. Týmto priradením obe premenné získali referenciu v pamäti na ten istý zoznam. Keďže ďalej s oboma premenným pracujeme len pomocou mutable operácií (metóda append()
), stále sa uchovávajú referencie na ten istý zoznam. Riešením by mohlo byť, buď opraviť úvodnú inicializáciu premenných napríklad na zoz1, zoz2 = [], []
, alebo používanie immutable operácií (namiesto zoz1.append(prvok)
použijeme zoz1 = zoz1 + [prvok]
).
Vyhadzovanie prvkov z kópie zoznamu¶
Ďalšia funkcia z daného reťazca vytvorí kópiu, z ktorej ale vynechá všetky hodnoty, ktoré sú znakovými reťazcami (ponechá napríklad čísla):
def zoznam_bez_retazcov(zoznam):
kopia = zoznam
for prvok in zoznam:
if type(prvok) == str:
kopia.remove(prvok)
return kopia
Riešenie je dostatočne čitateľné. Otestujme:
>>> nejaky = [2, '+', 5, 'je', 7]
>>> zoznam_bez_retazcov(nejaky)
[2, 5, 7]
>>> nejaky
[2, 5, 7]
>>> nejaky = [1, 'prvy', 'druhy', 'treti', 'stvrty']
>>> zoznam_bez_retazcov(nejaky)
[1, 'druhy', 'stvrty']
>>> nejaky
[1, 'druhy', 'stvrty']
Prvý test dal dobrý výsledok, ale funkcia pokazila aj pôvodný zoznam. V druhom teste dokonca dostávame aj chybný výsledok aj pokazený vstupný zoznam. Aspoň trochu skúsenejší pythonista vidí problém v priradení kopia = zoznam
. Premenná kopia
referencuje ten istý zoznam ako je v parametri zoznam
. Preto vyhadzovanie prvkov z premennej kopia
ich bude vyhadzovať aj zo zoznam
. Stačí opraviť úvodné priradenie napríklad na kopia = list(zoznam)
a tým sa naozaj do kopia
vyrobí nový zoznam. Teraz to už funguje, hoci skúsenejšiemu pythonistovi sa nemusí páčiť konštrukcia kopia.remove(prvok)
. Táto metóda vyhľadá v zozname kopia
daný prvok a jeho prvý výskyt vyhodí. Skôr by tu (namiesto vyhadzovania) zapísal skladanie nového reťazca pomocou append()
ale už bez reťazcov, napríklad:
def zoznam_bez_retazcov(zoznam):
novy = []
for prvok in zoznam:
if type(prvok) != str:
novy.append(prvok)
return novy
Využitie metódy pop pri prechádzaní zoznamu¶
Funkcia vypis
má vypísať prvky zoznamu tak, aby v každom riadku (možno okrem posledného) bol presne zadaný počet prvkov; jedno zo študentských riešení vyzerá takto:
def vypis(zoznam, pocet):
p = 0
while zoznam:
print(zoznam.pop(0), end=' ')
p += 1
if p % pocet == 0:
print()
Hoci toto riešenie dáva správne výsledky, má jeden nepríjemný efekt: po výpise zoznamu zistíme, že obsah zoznamu sa zničil. Napríklad:
>>> a = list(range(5, 20, 2))
>>> a
[5, 7, 9, 11, 13, 15, 17, 19]
>>> vypis(a, 3)
5 7 9
11 13 15
17 19
>>> a
[]
Táto funkcia, hoci len vypisovala prvky zoznamu, tento zoznam vyčistila nielen vo vnútri funkcie (vďaka zoznam.pop(0)
), ale tým aj premennú, ktorá tento zoznam referencovala pred volaním funkcie. Mutable operácia pop
na parameter vždy zmení obsah tohto parametra.
Zisťovanie, či je zoznam utriedený¶
Ďalšia funkcia bude zisťovať, či je daný zoznam usporiadaný vzostupne, t.j. či pre každú dvojicu prvkov v zozname, ktoré sú vedľa seba platí, že prvý z nich nie je väčší ako druhý; jedným z riešení je postupne prechádzať celým zoznamom a kontrolovať túto podmienku:
def vzostupne(zoznam):
for i in range(len(zoznam) - 1):
if zoznam[i] > zoznam[i + 1]:
return False
return True
Toto je korektné riešenie, ale môžeme to vyriešiť aj trochu inak: ak mám funkciu, ktorá vie preusporiadať prvky v zozname tak, že budú vo vzostupnom poradí, potom stačí prekontrolovať, či pôvodný zoznam má prvky v rovnakom poradí ako po preusporiadaní (utriedení). Začiatočníci chcú často využiť metódu sort
a niekedy urobia takúto chybu:
def vzostupne(zoznam):
zoz1 = zoznam.sort()
return zoz1 == zoznam
Tu zrejme predpokladajú, že metóda sort
z pôvodného zoznamu vyrobí vzostupne usporiadanú postupnosť a tú potom celú porovnajú s pôvodným zoznamom. Táto funkcia ale vždy vráti False
, lebo metóda sort
nevyrába novú usporiadanú postupnosť, ale preusporiada v pamäti (mutable) pôvodný zoznam a nič nevracia - v skutočnosti vráti hodnotu None
. Tá sa potom priradí do premennej zoz1
a porovná s usporiadným zoznam
(čo je zrejme False
).
Niektorí začiatočníci to chcú opraviť takto:
def vzostupne(zoznam):
zoz1 = zoznam
zoz1.sort()
return zoz1 == zoznam
Teda asi najprv si chcú vytvoriť kópiu pôvodného zoznamu (aby si ho nepokazili triedením pomocou sort
) a až túto kópiu budú triediť metódou sort
. Idea nie je zlá, ale realizácia je opäť chybná: priradením zoz1 = zoznam
nevzniká kópia, ale iba ďalšia referencia na ten istý zoznam. Ďalšie volanie metódy sort
usporiada pôvodný zoznam a na koniec skontroluje, či sa rovná samému sebe (teda to vždy bude True
).
Už vieme, že kópia zoznamu sa najlepšie robí buď priradením zoz1 = zoznam[:]
alebo zoz1 = list(zoznam)
. Ak ale namiesto metódy sort
využijeme iný variant triedenia, riešenie sa ešte zjednoduší. Triediť môžeme pomocou funkcie sorted
, ktorá dostane ako parameter ľubovoľnú iterovateľnú postupnosť (napríklad zoznam, reťazec, …) a vráti uzporiadaný zoznam. Pôvodná postupnosť sa pritom nemení (je to immutable). Našu funkciu môžeme teraz zapísať takto:
def vzostupne(zoznam):
zoz1 = sorted(zoznam)
return zoz1 == zoznam
alebo ešte úspornejšie:
def vzostupne(zoznam):
return sorted(zoznam) == zoznam
Vyprázdenie zoznamu¶
Nasledovná funkcia by mala vyčistiť obsah zadaného zoznamu:
def cisti(zoznam):
zoznam = []
Samozrejme, že to nefunguje:
>>> ab = [1, 'dva', 3.14]
>>> cisti(ab)
>>> ab
[1, 'dva', 3.14]
Volanie funkcie cisti()
vytvorí lokálnu premennú zoznam
a ten dostáva hodnotu skutočného parametra, teda referenciu na zoznam [1, 'dva', 3.14]
. Lenže priradenie zoznam = []
je immutable operácia, teda do lokálnej premennej zoznam
priradíme novú referenciu na prázdny zoznam. Tým sa ale nezmení referencia pôvodnej premennej ab
, ktorá bola skutočným parametrom volania funkcie cisti()
. Riešením by asi bolo použitie nejakej mutable operácie, ktorá vyčistí obsah zoznamu, napríklad:
def cisti(zoznam):
zoznam.clear()
Zapamätajte si, že priradenie do premennej pracuje vždy s lokálnou premennou - buď ju vytvorí (ak ešte neexistovala), alebo jej zmení hodnotu.
Podzoznamy v zoznamoch¶
Predpokladáme, že takéto príklady vás presvedčia, že pri práci so zoznamami vo funkciách musíte byť veľmi ostražití a uvedomovať si dôsledky referencií na zoznamy.
S referenciami môžeme mať problémy nielen v situáciách, keď dve premenné odkazujú na ten istý zoznam, ale aj v prípadoch, keď zoznam obsahuje nejaký podzoznam, t.j. referenciu na iný zoznam. Vyskúšajme:
>>> x = ['prvy', [2, 3], 'styri']
>>> y = x[1]
>>> y
[2, 3]
>>> y.append('kuk')
>>> y
[2, 3, 'kuk']
Zatiaľ to vyzerá dobre: do premennej y
sme priradili prvok zoznamu x
s indexom 1. Vidíme, že je to dvojprvkový zoznam [2, 3]
a preto do neho na koniec pridáme nejaký reťazec pomocou y.append('kuk')
. Aj toto funguje dobre: v premennej y
je teraz [2, 3, 'kuk']
. Lenže teraz sa zmenil aj pôvodný zoznam x
:
>>> x
['prvy', [2, 3, 'kuk'], 'styri']
Pekne tento efekt vidieť aj na ďalšom príklade:
>>> a = ['a']
>>> zoz = [a, a, a]
>>> zoz
[['a'], ['a'], ['a']]
My už vieme, že zoznam zoz
má tri prvky a všetky tri sú referenciami na ten istý mutable objekt. Ak sa tento zmení mutable operáciou, zmenia sa obsahy všetkých troch prvkov zoznamu:
>>> a.insert(0, 'b')
>>> a
['b', 'a']
>>> zoz
[['b', 'a'], ['b', 'a'], ['b', 'a']]
Nielen začiatočníka prekvapí takáto chyba: plánujeme vytvoriť 100-prvkový zoznam, ktorý bude obsahovať len prázdne zoznamy []
. Potom budeme niektoré z týchto zoznamov meniť, napríklad:
>>> zoz = [[]] * 100
>>> zoz[3].append(1)
>>> zoz[7].insert(0, 0)
>>> zoz[9] += [2]
>>> zoz
[[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2],
[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2],
[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2],
[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2],
[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2],
...]
Vidíme, že napriek tomu, že sme menili len niektoré tri prvky zoznamu zoz
, malo to vplyv na všetkých 100 prvkov.
Pokračujme s týmto zoznamom. Zrejme platí:
>>> zoz[2] == zoz[3]
True
>>> zoz[3] = [0, 1, 2]
>>> zoz[2] == zoz[3]
True
Obsahy 2. a 3. prvkov sú rovnaké aj keď nemajú tú istú referenciu. Môžeme to vidieť, keď vymažeme obsah, napríklad 0. prvku:
>>> zoz[0].clear()
>>> zoz
[[], [], [], [0, 1, 2], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
[], []]
Všetky prvky s rovnakou referenciou sa vymazali okrem 3., ktorý mal rovnaký obsah, ale inú referenciu. V niektorých situáciách nám pomôže nová operácia is
, pomocou ktorej vieme zistiť, či majú dva objekty identickú referenciu. Napríklad:
>>> zoz[1] = []
>>> zoz[0] == zoz[1]
True
>>> zoz[0] is zoz[1]
False
>>> zoz[0] is zoz[2]
True
Zmenili sme 1. prvok na prázdny zoznam, preto platí zoz[0] == zoz[1]
, ale sú to rôzne referencie, preto neplatí zoz[0] is zoz[1]
.
Zoznamy a reťazce¶
V Pythone existuje niekoľko metód, v ktorých zoznamy spolupracujú so znakovými reťazcami. Ukážeme dve reťazcové metódy, ktoré budeme odteraz veľmi intenzívne využívať.
metóda split()¶
Najlepšie to pochopíte na niekoľkých príkladoch. Metóda split()
sa často využíva pri rozdelení prečítaného reťazca zo vstupu (input()
alebo subor.readline()
) na viac častí, napríklad:
>>> ret = input('zadaj 2 čísla: ')
zadaj 2 čísla: 15 999
>>> zoz = ret.split()
>>> zoz
['15', '999']
>>> a, b = zoz
>>> ai, bi = int(zoz[0]), int(zoz[1])
>>> a, b, ai, bi
('15', '999', 15, 999)
Niekedy môžeme vidieť aj takýto zápis:
>>> meno, priezvisko = input('zadaj meno a priezvisko: ').split()
zadaj meno a priezvisko: Janko Hraško
>>> meno
'Janko'
>>> priezvisko
'Hraško'
Metóda split()
môže dostať ako parameter oddeľovač, napríklad ak sme prečítali čísla oddelené čiarkami:
sucet = 0
for prvok in input('zadaj čísla: ').split(','):
sucet += int(prvok)
print('ich súčet je', sucet)
zadaj čísla: 10,20,30,40
ich súčet je 100
metóda join()¶
Ukážme to na príklade:
>>> zoz = ['prvý', 'druhý', 'tretí']
>>> zoz
['prvý', 'druhý', 'tretí']
>>> ''.join(zoz)
'prvýdruhýtretí'
>>> '...'.join(zoz)
'prvý...druhý...tretí'
>>> list(str(2021))
['2', '0', '2', '1']
>>> '.'.join(list(str(2021)))
'2.0.2.1'
>>> '.'.join('Python')
'P.y.t.h.o.n'
Preštudujte:
>>> veta = 'kto druhemu jamu kope'
>>> ' '.join(veta[::-1].split()[::-1])
'otk umehurd umaj epok'
>>> ' '.join(input('? ').split()[::-1])
? viem ze neviem javu ale viem python
'python viem ale javu neviem ze viem'
n-tice (tuple)¶
Sú to vlastne len nemeniteľné (immutable) zoznamy. Pythonovský typ tuple
dokáže robiť skoro všetko to isté ako list
okrem mutable operácií. Takže to najprv zhrňme a potom si ukážeme, ako to pracuje:
operácia
+
na zreťazovanie (spájanie dvoch n-tíc)operácia
*
na viacnásobné zreťazovanie (viacnásobné spájanie jednej n-tice)operácia
in
na zisťovanie, či sa nejaká hodnota nachádza v n-ticioperácia indexovania
[i]
na zistenie hodnoty prvku na zadanom indexeoperácia rezu
[i:j:k]
na zistenie hodnoty nejakej podčasti n-ticerelačné operácie
==
,!=
,<
,<=
,>
,>=
na porovnávanie obsahu dvoch n-tícmetódy
count()
aindex()
na zisťovanie počtu výskytov, resp. indexu prvého výskytuprechádzanie n-tice pomocou for-cyklu (iterovanie)
štandardné funkcie
len()
,sum()
,min()
,max()
ktoré zisťujú niečo o prvkoch n-tice
Takže n-tice, tak ako aj zoznamy sú štruktúrované typy, t.j. sú to typy, ktoré obsahujú hodnoty nejakých (možno rôznych) typov (sú to tzv. kolekcie):
konštanty typu n-tica uzatvárame do okrúhlych zátvoriek a navzájom oddeľujeme čiarkami
funkcia
len()
vráti počet prvkov n-tice, napríklad:>>> stred = (150, 100) >>> zviera = ('slon', 2013, 'gray') >>> print(stred) (150, 100) >>> print(zviera) ('slon', 2013, 'gray') >>> nic = () >>> print(nic) () >>> len(stred) 2 >>> len(zviera) 3 >>> len(nic) 0 >>> type(stred) <class 'tuple'>
Vidíte, že n-tica môže byť aj prázdna, označujeme ju ()
a vtedy má počet prvkov 0 (teda len(())
je 0). Ak n-tica nie je prázdna, hodnoty sú navzájom oddelené čiarkami.
n-tica s jednou hodnotou¶
n-ticu s jednou hodnotou nemôžeme zapísať takto:
>>> p = (12)
>>> print(p)
12
>>> type(p)
<class 'int'>
Ak zapíšeme ľubovoľnú hodnotu do zátvoriek, nie je to n-tica (v našom prípade je to len jedno celé číslo). Pre jednoprvkovú n-ticu musíme do zátvoriek zapísať aj čiarku:
>>> p = (12,)
>>> print(p)
(12,)
>>> len(p)
1
>>> type(p)
<class 'tuple'>
Pre Python sú dôležitejšie čiarky ako zátvorky. V mnohých prípadoch si Python zátvorky domyslí (čiarky si nedomyslí nikdy):
>>> stred = 150, 100
>>> zviera = 'slon', 2013, 'gray'
>>> p = 12,
>>> print(stred)
(150, 100)
>>> print(zviera)
('slon', 2013, 'gray')
>>> print(p)
(12,)
Uvedomte si rozdiel medzi týmito dvoma priradeniami:
>>> a = 3.14
>>> b = 3,14
>>> print(a, type(a))
3.14 <class 'float'>
>>> print(b, type(b))
(3, 14) <class 'tuple'>
Operácie s n-ticami¶
Operácie fungujú presne rovnako ako fungovali s reťazcami a zoznamami:
operácia
+
zreťazí dve n-tice, to znamená, že vyrobí novú n-ticu, ktorá obsahuje najprv všetky prvky prvej n-tice a za tým všetky prvky druhej n-tice; zrejme oba operandy musia byť n-tice: nemôžeme zreťazovať n-ticu s hodnotou iného typuoperácia
*
zadané číslo-krát zreťazí jednu n-ticu, to znamená, že vyrobí novú n-ticu, ktorá požadovaný-krát obsahuje všetky prvky zadanej n-tice; operácia viacnásobného zreťazovania má jeden operand typu n-tica a druhý musí byť celé číslooperácia
in
vie zistiť, či sa nejaký prvok nachádza v n-tici
Napríklad:
>>> stred = (150, 100)
>>> zviera = ('slon', 2013, 'gray')
>>> stred + zviera
(150, 100, 'slon', 2013, 'gray')
>>> zviera + stred
('slon', 2013, 'gray', 150, 100)
>>> stred * 5
(150, 100, 150, 100, 150, 100, 150, 100, 150, 100)
>>> 50 * (1)
50
>>> 50 * (1,)
(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
>>> 50 * (1, 2)
(1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1,
2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1,
2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2)
n-tica môže obsahovať ako svoje prvky aj iné n-tice:
>>> stred = (150, 100)
>>> p = ('stred', stred)
>>> p
('stred', (150, 100))
>>> len(p)
2
>>> p = (stred, stred, stred, stred)
>>> p
((150, 100), (150, 100), (150, 100), (150, 100))
>>> 4 * (stred,)
((150, 100), (150, 100), (150, 100), (150, 100))
>>> 4 * (stred) # čo je to isté ako 4 * stred
(150, 100, 150, 100, 150, 100, 150, 100)
>>> 4 * stred,
((150, 100, 150, 100, 150, 100, 150, 100),)
Operátorom in
vieme zistiť, či sa nejaká hodnota nachádza v n-tici ako jeden jeho prvok. Takže:
>>> p = (stred, stred, stred, stred)
>>> p
((150, 100), (150, 100), (150, 100), (150, 100))
>>> stred in p
True
>>> 150 in p
False
>>> 150 in stred
True
>>> zviera = ('slon', 2013, 'gray')
>>> 2013 in zviera
True
>>> (2013, 'gray') in zviera
False
Funkcia tuple()¶
Vyrobí n-ticu z ľubovoľnej postupnosti (z iterovateľného objektu, t.j. takého objektu, ktorý sa dá prechádzať for-cyklom), napríklad zo znakového reťazca, zo zoznamu, vygenerovanej postupnosti celých čísel pomocou range()
, ale iterovateľný je aj otvorený textový súbor. Znakový reťazec funkcia tuple()
rozoberie na znaky:
>>> tuple('Python')
('P', 'y', 't', 'h', 'o', 'n')
Vytvorenie n-tice pomocou range()
:
>>> tuple(range(1, 16))
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
>>> a = tuple(range(1000000))
>>> len(a)
1000000
Podobne môžeme skonštruovať n-ticu z textového súboru. Predpokladajme, že súbor obsahuje tieto 4 riadky:
prvy
druhy
treti
stvrty
potom
>>> with open('abc.txt') as t:
obsah = tuple(t)
>>> obsah
('prvy\n', 'druhy\n', 'treti\n', 'stvrty\n')
Riadky súboru sa postupne stanú prvkami n-tice.
for-cyklus s n-ticami¶
for-cyklus je programová konštrukcia, ktorá postupne prechádza všetky prvky nejakého iterovateľného objektu. Doteraz sme sa stretli s iterovaním pomocou funkcie range()
, prechádzaním prvkov reťazca str
a zoznamu list
, aj celých riadkov textového súboru. Ale už od 2. prednášky sme používali aj takýto zápis:
for i in 2, 3, 5, 7, 11, 13:
print('prvocislo', i)
V tomto zápise už teraz vidíme n-ticu (tuple
): 2, 3, 5, 7, 11, 13
. Len sme tomu nemuseli dávať zátvorky. Keďže aj n-tica je iterovateľný objekt, Môžeme ju používať vo for-cykle rovnako ako iné iterovateľné typy. To isté, ako predchádzajúci príklad, by sme zapísali napríklad aj takto:
cisla = (2, 3, 5, 7, 11, 13)
for i in cisla:
print('prvocislo', i)
Keďže teraz už vieme manipulovať s n-ticami, môžeme zapísať napríklad:
>>> rozne = ('retazec', (100, 200), 3.14, len)
>>> for prvok in rozne:
print(prvok, type(prvok))
retazec <class 'str'>
(100, 200) <class 'tuple'>
3.14 <class 'float'>
<built-in function len> <class 'builtin_function_or_method'>
Tu vidíme, že prvkami n-tice môžu byť najrôznejšie objekty, hoci aj funkcie (tu je to štandardná funkcia len
).
Pomocou operácií s n-ticami vieme zapísať aj zaujímavejšie postupnosti čísel, napríklad:
>>> for i in 10 * (1,):
print(i, end=' ')
1 1 1 1 1 1 1 1 1 1
>>> for i in 10 * (1, 2):
print(i, end=' ')
1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2
>>> for i in 10 * tuple(range(10)):
print(i, end=' ')
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
3 4 5 6 7 8 9
>>> for z in 'Python':
print(z, end=' ')
P y t h o n
>>> for z in 'Python',:
print(z, end=' ')
Python
Ďalej pomocou for-cyklu vieme n-tice skladať podobne, ako sme to robili so zoznamami. V nasledovnom príklade vytvoríme n-ticu zo všetkých deliteľov nejakého čísla:
cislo = int(input('zadaj cislo: '))
delitele = ()
for i in range(1, cislo+1):
if cislo % i == 0:
delitele = delitele + (i,)
print('delitele', cislo, 'su', delitele)
po spustení:
zadaj cislo: 124
delitele 124 su (1, 2, 4, 31, 62, 124)
Všimnite si, ako sme pridali jeden prvok na koniec n-tice: delitele = delitele + (i,)
. Museli, sme vytvoriť jednoprvkovú n-ticu (i,)
a tú sme zreťazili s pôvodnou n-ticou delitele
. Mohli sme to zapísať aj takto: delitele += (i,)
. Zrejme, keby sme toto riešili pomocou zoznamov, použili by sme metódu append()
.
Funkcia enumerate()¶
Už poznáme použitie štandardnej funkcie enumerate()
. Vieme ju využiť aj pre n-tice, napríklad:
zoz = (2, 3, 5, 7, 9, 11, 13, 17, 19)
for ix, pr in enumerate(zoz):
print(f'{ix}. prvocislo je {pr}')
0. prvocislo je 2
1. prvocislo je 3
2. prvocislo je 5
3. prvocislo je 7
4. prvocislo je 9
5. prvocislo je 11
6. prvocislo je 13
7. prvocislo je 17
8. prvocislo je 19
Funkcia enumerate()
v skutočnosti z jednej ľubovoľnej postupnosti vygeneruje postupnosť dvojíc (ktoré sú už typu tuple
). Túto postupnosť ďalej preliezame for-cyklom. Mohli by sme to zapísať aj takto:
zoz = (2, 3, 5, 7, 9, 11, 13, 17, 19)
for dvojica in enumerate(zoz):
ix, pr = dvojica
print(f'{ix}. prvocislo je {pr} ... dvojica = {dvojica}')
po spustení:
0. prvocislo je 2 ... dvojica = (0, 2)
1. prvocislo je 3 ... dvojica = (1, 3)
2. prvocislo je 5 ... dvojica = (2, 5)
3. prvocislo je 7 ... dvojica = (3, 7)
4. prvocislo je 9 ... dvojica = (4, 9)
5. prvocislo je 11 ... dvojica = (5, 11)
6. prvocislo je 13 ... dvojica = (6, 13)
7. prvocislo je 17 ... dvojica = (7, 17)
8. prvocislo je 19 ... dvojica = (8, 19)
Ak by sme skúmali výsledok z tejto funkcie, dozvedeli by sme sa:
>>> enumerate(zoz)
<enumerate object at 0x02F59B48>
>>> list(enumerate(zoz))
[(0, 2), (1, 3), (2, 5), (3, 7), (4, 9), (5, 11), (6, 13), (7, 17), (8, 19)]
>>> tuple(enumerate(zoz))
((0, 2), (1, 3), (2, 5), (3, 7), (4, 9), (5, 11), (6, 13), (7, 17), (8, 19))
čo sú naozaj postupnosti skutočných dvojíc.
Indexovanie¶
n-tice indexujeme rovnako ako sme indexovali zoznamy:
prvky postupnosti môžeme indexovať v
[]
zátvorkách, pričom index musí byť od 0 až po počet prvkov-1pomocou rezu (slice) vieme indexovať časť n-tice (niečo ako podreťazec) tak, že
[]
zátvoriek zapíšeme aj dvojbodku:ntica[od:do]
n-tica z prvkov s indexmiod
až podo-1
ntica[:do]
n-tica z prvkov od začiatku až po prvok s indexomdo-1
ntica[od:]
n-tica z prvkov s indexmiod
až po koniec n-ticentica[od:do:krok]
n-tica z prvkov s indexmiod
až podo-1
, pričom berieme každýkrok
prvok
Niekoľko príkladov:
>>> prvo = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29)
>>> prvo[2]
5
>>> prvo[2:5]
(5, 7, 11)
>>> prvo[4:5]
(11,)
>>> prvo[:5]
(2, 3, 5, 7, 11)
>>> prvo[5:]
(13, 17, 19, 23, 29)
>>> prvo[::2]
(2, 5, 11, 17, 23)
>>> prvo[::-1]
(29, 23, 19, 17, 13, 11, 7, 5, 3, 2)
Vidíme, že s n-ticami pracujeme veľmi podobne ako sme pracovali so znakovými reťazcami a so zoznamami. Keď sme ale do znakového reťazca chceli pridať jeden znak (alebo aj viac), museli sme to robiť rozoberaním a potom skladaním:
>>> prvo = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29)
>>> prvo = prvo[:5] + ('fuj',) + prvo[5:]
>>> prvo
(2, 3, 5, 7, 11, 'fuj', 13, 17, 19, 23, 29)
Pred 5-ty prvok vloží nejaký znakový reťazec.
Rovnako nemôžeme zmeniť ani hodnotu nejakého znaku reťazca obyčajným priradením:
>>> ret = 'Python'
>>> ret[2] = 'X'
...
TypeError: 'str' object does not support item assignment
>>> ret = ret[:2] + 'X' + ret[3:]
>>> ret
'PyXhon'
>>> ntica = (2, 3, 5, 7, 11, 13)
>>> ntica[2] = 'haha'
...
TypeError: 'tuple' object does not support item assignment
>>> ntica = ntica[:2] + ('haha',) + ntica[3:]
>>> ntica
(2, 3, 'haha', 7, 11, 13)
Všimnite si, že Python vyhlásil rovnakú chybu pre tuple
ako pre str
. Hovoríme, že ani reťazce ani n-tice nie sú meniteľné (teda sú immutable).
Viacnásobné priradenie¶
Najprv pripomeňme, ako funguje viacnásobné priradenie: ak je pred znakom priradenia =
viac premenných, ktoré sú oddelené čiarkami, tak za znakom priradenia musí byť iterovateľný objekt, ktorý má presne toľko hodnôt, ako počet premenných. Iterovateľným objektom môže byť zoznam (list
), n-tica (tuple
), znakový reťazec (str
), generovaná postupnosť čísel (range()
) ale aj otvorený textový súbor (open()
), ktorý má presne toľko riadkov, koľko je premenných v priradení.
Ak do jednej premennej priraďujeme viac hodnôt oddelených čiarkou, Python to chápe ako priradenie n-tice. Pozrite nasledovné priradenia.
Priradíme n-ticu:
>>> a1, a2, a3, a4 = 3.14, 'joj', len, (1, 3, 5)
>>> print(a1, a2, a3, a4)
3.14 joj <built-in function len> (1, 3, 5)
>>> a, b, c, d, e, f = 3 * (5, 7)
>>> print(a, b, c, d, e, f)
5 7 5 7 5 7
Priradíme vygenerovanú postupnosť 4 čísel:
>>> a, b, c, d = range(2, 6)
>>> print(a, b, c, d)
2 3 4 5
Priradíme znakový reťazec:
>>> d, e, f, g, h, i = 'Python'
>>> print(d, e, f, g, h, i)
P y t h o n
Priradíme riadky textového súboru:
>>> with open('dva.txt', 'w') as f:
f.write('first\nsecond\n')
>>> with open('dva.txt') as subor:
prvy, druhy = subor
>>> prvy
'first\n'
>>> druhy
'second\n'
Vieme zapísať aj takto:
>>> prvy, druhy = open('dva.txt')
Tento posledný príklad je veľmi umelý a v praxi sa asi priamo do premenných takto čítať nebude.
Viacnásobné priradenie používame napríklad aj na výmenu obsahu dvoch (aj viac) premenných:
>>> x, y, z = y, z, x
Aj v tomto príklade je na pravej strane priradenia (za =
) n-tica: (y, z, x)
.
Ďalšie funkcie a metódy¶
S n-ticami vedia pracovať nasledovné štandardné funkcie:
len(ntica)
- vráti počet prvkov n-ticesum(ntica)
- vypočíta súčet prvkov n-tice (všetky musia byť čísla)min(ntica)
- zistí najmenší prvok n-tice (prvky sa musia dať navzájom porovnať, nemôžeme tu miešať rôzne typy)max(ntica)
- zistí najväčší prvok n-tice (ako primin()
ani tu sa nemôžu typy prvkov miešať)
Na rozdiel od zoznamov a znakových reťazcov, ktoré majú veľké množstvo metód, n-tice majú len dve:
ntica.count(hodnota)
- zistí počet výskytov nejakej hodnoty v n-ticintica.index(hodnota)
- vráti index (poradie) v n-tici prvého (najľavejšieho) výskytu danej hodnoty, ak sa hodnota v n-tici nenachádza, metóda spôsobí spadnutie na chybe (ValueError: tuple.index(x): x not in tuple
)
Ukážme tieto funkcie na malom príklade. V n-tici uložíme niekoľko nameraných teplôt a potom vypíšeme priemernú, minimálnu aj maximálnu teplotu:
>>> teploty = (14, 22, 19.5, 17.1, 20, 20.4, 18)
>>> print('počet nameraných teplôt: ', len(teploty))
počet nameraných teplôt: 7
>>> print('minimálna teplota: ', min(teploty))
minimálna teplota: 14
>>> print('maximálna teplota: ', max(teploty))
maximálna teplota: 22
>>> print('priemerná teplota: ', round(sum(teploty) / len(teploty), 2))
priemerná teplota: 18.71
Ďalej môžeme zistiť, kedy bola nameraná konkrétna hodnota:
>>> teploty.index(20)
4
>>> teploty.index(20.1)
...
ValueError: tuple.index(x): x not in tuple
Môžeme zistiť, koľko-krát sa nejaká konkrétna teplota vyskytla v našich meraniach:
>>> teploty.count(20)
1
>>> teploty.count(20.1)
0
n-tice a grafika¶
Nasledovný príklad predvedie použitie n-tíc v grafickom režime. Zadefinujeme niekoľko bodov v rovine a potom pomocou nich kreslíme nejaké farebné polygóny. Začnime takto:
a = (70, 150)
b = (200, 200)
c = (150, 250)
d = (120, 70)
e = (50, 220)
canvas = tkinter.Canvas()
canvas.pack()
canvas.create_polygon(a, b, c, d, fill='red')
Ak by sme chceli jedným priradením priradiť dva body do premenných a
aj b
, zapíšeme:
a, b = (100, 150), (180, 200)
čo je vlastne:
a, b = ((100, 150), (180, 200))
Polygónov môžeme nakresliť aj viac (zrejme väčšinou záleží na poradí ich kreslenia):
canvas.create_polygon(e, a, c, fill='green')
canvas.create_polygon(e, d, b, fill='yellow')
canvas.create_polygon(a, b, c, d, fill='red')
canvas.create_polygon(a, c, d, b, fill='blue')
Vidíme, že niektoré postupnosti bodov tvoria jednotlivé útvary, preto zapíšme:
utvar1 = e, a, c
utvar2 = e, d, b
utvar3 = a, b, c, d
utvar4 = a, c, d, b
canvas.create_polygon(utvar1, fill='green')
canvas.create_polygon(utvar2, fill='yellow')
canvas.create_polygon(utvar3, fill='red')
canvas.create_polygon(utvar4, fill='blue')
Volanie funkcie canvas.create_polygon()
sa tu vyskytuje 4-krát, ale s rôznymi parametrami. Prepíšme to do for-cyklu:
utvar1 = e, a, c
utvar2 = e, d, b
utvar3 = a, b, c, d
utvar4 = a, c, d, b
for param in (utvar1, 'green'), (utvar2, 'yellow'), (utvar3, 'red'), (utvar4, 'blue'):
utvar, farba = param
canvas.create_polygon(utvar, fill=farba)
Dostávame to isté. Vo for-cykle sa najprv do premennej param
priradí dvojica s dvoma prvkami: útvar a farba, a v tele cyklu sa táto premenná s dvojicou priradí do dvoch premenných utvar
a farba
. Potom sa zavolá funkcia canvas.create_polygon()
s týmito parametrami.
Už sme videli aj predtým, že pre for-cyklus existuje vylepšenie: ak sa do premennej cyklu postupne priraďujú nejaké dvojice hodnôt a tieto by sa na začiatku tela rozdelili do dvoch premenných, môžeme priamo tieto dve premenné použiť ako premenné cyklu (ako keby viacnásobné priradenie). Podobnú ideu sme mohli vidieť pri použití enumerate()
. Predchádzajúci príklad prepíšeme:
utvar1 = e, a, c
utvar2 = e, d, b
utvar3 = a, b, c, d
utvar4 = a, c, d, b
for utvar, farba in (utvar1, 'green'), (utvar2, 'yellow'), (utvar3, 'red'),(utvar4, 'blue'):
canvas.create_polygon(utvar, fill=farba)
Pozrime sa na n-ticu, ktorá sa prechádza týmto for-cyklom:
>>> cyklus = (utvar1, 'green'), (utvar2, 'yellow'), (utvar3, 'red'), (utvar4, 'blue')
>>> cyklus
((((50, 220), (70, 150), (150, 250)), 'green') (((50, 220), (120, 70),
(200, 200)), 'yellow') (((70, 150), (200, 200), (150, 250), (120, 70)),
'red') (((70, 150), (150, 250), (120, 70), (200, 200)), 'blue'))
Vidíme, že n-tica v takomto tvare je dosť ťažko čitateľná, ale for-cyklus jej normálne rozumie. Zrejme by sme teraz mohli zapísať:
for utvar, farba in cyklus:
canvas.create_polygon(utvar, fill=farba)
Zoznamy a grafika¶
Už vieme, že väčšina grafických príkazov, napríklad create_line()
, create_polygon()
, … akceptujú ako parametre nielen čísla, ale aj n-tice alebo aj zoznamy čísel, resp. zoznamy/dvojice čísel, napríklad:
import tkinter
canvas = tkinter.Canvas()
canvas.pack()
utvar = ((100, 50), (200, 120))
canvas.create_rectangle(utvar, fill='blue')
canvas.create_oval(utvar, fill='yellow')
utvar2 = list(utvar) # z n-tice sa vyrobí zoznam
utvar2.append((170, 20))
canvas.create_polygon(utvar2, fill='red')
tkinter.mainloop()
alebo môžeme generovať náhodnú krivku:
import tkinter
import random
canvas = tkinter.Canvas(bg='white')
canvas.pack()
krivka = []
for i in range(30):
krivka.append((random.randrange(350), random.randrange(250)))
canvas.create_line(krivka)
tkinter.mainloop()
Po spustení dostaneme spojených 30 náhodných bodov v rovine:

Ak by sme chceli využiť grafickú funkciu coords()
, ktorá modifikuje súradnice nakreslenej krivky, nemôžeme jej poslať zoznam súradníc (dvojíc čísel x a y), ale táto vyžaduje plochý zoznam (alebo n-ticu) čísel. Predchádzajúci príklad mierne zmeníme:
import tkinter
import random
canvas = tkinter.Canvas(bg='white')
canvas.pack()
poly = canvas.create_polygon(0, 0, 0, 0, fill='yellow', outline='blue')
krivka = []
for i in range(100):
bod = [random.randrange(350), random.randrange(250)]
krivka.extend(bod) # to isté ako krivka += bod
canvas.coords(poly, krivka)
canvas.update()
canvas.after(300)
tkinter.mainloop()
Použili sme tu dvojicu nových príkazov pre grafickú plochu canvas
:
canvas.update()
canvas.after(300)
Po spustení sa postupne vygeneruje 100 náhodných bodov, ktoré budú tvoriť obrys polygónu:

Tieto dva príkazy označujú, že sa grafická plocha prekreslí (aktualizuje) pomocou metódy update()
a potom sa na 300 milisekúnd (0.3 sekundy) pozdrží výpočet pomocou metódy after()
. Vďaka tejto dvojici príkazov budeme vidieť postupné pridávanie náhodných bodov vytváranej krivky.
Okrem toho sme tu využili novú metódu extend()
, ktorá k existujúcemu zoznamu prilepí na koniec nový zoznam. Napríklad:
>>> a = [1, 2, 3, 4]
>>> b = ['xx', 'yy']
>>> a.extend(b)
>>> a
[1, 2, 3, 4, 'xx', 'yy']
Zrejme to isté by sme dosiahli aj takto:
>>> a = [1, 2, 3, 4]
>>> b = ['xx', 'yy']
>>> a += b
>>> a
[1, 2, 3, 4, 'xx', 'yy']
Cvičenia¶
Napíš funkciu
posun(zoznam)
, ktorá posunie prvky v danom zozname tak, že prvý sa presťahuje na koniec. Funkcia nič nevracia, len zmení obsah pôvodného zoznamu. Napríklad:>>> a = [2, 3, '5', 7, 11] >>> posun(a) >>> a [3, '5', 7, 11, 2] >>> zoz = 'kto druhemu jamu kope'.split() >>> for i in range(5): print(zoz) posun(zoz) ['kto', 'druhemu', 'jamu', 'kope'] ['druhemu', 'jamu', 'kope', 'kto'] ['jamu', 'kope', 'kto', 'druhemu'] ['kope', 'kto', 'druhemu', 'jamu'] ['kto', 'druhemu', 'jamu', 'kope']
Napíš funkciu
vyhod_none(ntica)
, ktorá z danej n-tice vyhodí všetky výskytyNone
. Funkcia vráti (return
) túto novú n-ticu (nič nevypisuje). Napríklad:>>> ntica = vyhod_none((None, 1, None, None)) >>> ntica (1,)
Napíš funkciu
dve_kocky(pocet)
, ktorá vráti 13-prvkový zoznam celých čísel. Tento sa skonštruuje takto: zadanýpocet
-krát hodí dvoma kockami (dve nádodné čísla od 1 do 6), pre každý takýto hod urobí ich súčet a v 13-prvkovom zozname si eviduje počet výskytov každého súčtu, napríkladzoznam[5]
bude označovať, koľko krát pri našej simulácii padol súčet 5; zrejme na začiatku budú v zozname samé 0 a potom pri každom hode sa číslo na príslušnom indexe zvýši o 1. Funkcia nič nevypisuje, len vráti vytvorený 13-prvkový zoznam celých čísel. Mohol by si dostať napríklad, takýto zoznam:>>> dve_kocky(1000) [0, 0, 29, 36, 90, 105, 137, 181, 125, 126, 93, 50, 28]
Napíš funkciu
osmickova(cislo)
, ktorá vráti (return
) zoznam cifier daného čísla v osmičkovej sústave. Využi funkcieoct
aint
. Napríklad:>>> osmickova(11213) [2, 5, 7, 1, 5]
Napíš funkciu
dvojkova(cislo)
, ktorá vráti (return
) zoznam cifier daného čísla v dvojkovej sústave. Využif'{cislo:b}'
. Napríklad:>>> dvojkova(11213) [1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1]
Napíš funkciu
z_dvojkovej(zoznam)
, ktorá dostane zoznam cifier dvojkového zápisu čísla v tvare z predchádzajúcej úlohy. Funkcia vráti celé číslo (return
), ktorého cifry v dvojkovej sústave zodpovedajú zadanému zoznamu. Napríklad:>>> z_dvojkovej([1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1]) 11213 >>> z = [1] + [0] * 20 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] >>> z_dvojkovej(z) 1048576 >>> 2 ** 20 1048576
Využi funkciu
int(reťazec, 2)
, pomocou ktorej sa zo znakového reťazca s dvojkovým zápisom čísla vyrobí celé číslo.
Napíš funkciu
nahodne_body(pocet)
, ktorá vráti zadaný počet náhodných bodov v grafickej ploche (dvojíc čísel z 380x260). Funkcia vráti zoznam, ktorý bude obsahovať dvojprvkové n-tice celých čísel. Napríklad:>>> nahodne_body(5) [(118, 103), (299, 27), (247, 118), (166, 237), (269, 225)]
Ak by si celú postupnosť 100 náhodných bodov z predchádzajúcej úlohy vykreslil pomocou jediného
create_line
, dostal by si nejakú čmáranicu (vyskúšaj). Ďalej otestuj, ako sa vykreslí táto postupnosť, keď sa najprv usporiada pomocou funkciesorted
. Napríklad, náhodná postupnosť 100 bodov:a po usporiadaní pomocou
sorted
:
Napíš funkciu
sort_y(zoznam)
, kdezoznam
obsahuje dvojice (typtuple
) celých čísel. Tieto reprezentujú súradnice(x, y)
nejakých bodov v rovine. Tentozoznam
treba usporiadať od najmenšieho po najväčší, lenže podľa druhých prvkov dvojíc (y
-ových súradníc). Uvedom si, že volaniezoznam.sort()
by usporiadalo zoznam podľa prvých prvkov dvojíc (x
-ových súradníc). Napríklad:>>> xy = [(100, 30), (200, 10), (300, 20)] >>> sort_y(xy) >>> xy [(200, 10), (300, 20), (100, 30)]
Triediť môžeš takto: najprv v zozname v každej dvojici vymeníš
x
ay
, potom normálne utriediš (napríklad pomocou metódysort
) a nakoniec v takto utriedenom zozname vrátiš všetky dvojice do pôvodného stavu (vymeníšx
ay
).Podobne ako v predchádzajúcej úlohe vykresli takto usporiadanú postupnosť vrcholov pomocou
create_line
:
Napíš funkciu
prerob(cislo)
, ktorá z daného celého čísla vyrobí reťazec, ale tak, že cifry zoskupí do trojíc (sprava) a oddelí podčiarkovníkom. Využi funkciujoin
, preto z čísla najprv vyrob zoznam trojznakových reťazcov. Funkcia nič nevypisuje, ale vráti (return
) výsledný reťazec. Napríklad:>>> prerob(12345678) '12_345_678'
Je zaujímavé, že Python aj takto zadané celé čísla považuje za korektné, napríklad:
>>> 12_345_678 12345678
Výsledok svojej funkcie
prerob
môžeš skontrolovať pomocouf'{cislo:_}'
.
Napíš funkciu
sipka(xy1, xy2)
, ktorá do grafickej plochy nakreslí šípku z boduxy1
do boduxy2
. Oba tieto parametre sú dvojice čísel (tuple
), t.j. súradnice bodov. Šípku kresli pomocoucreate_line
, v ktorej využiješ ďalší pomenovaný parameterarrow='last'
(podobné šípky sme kreslili v 15. úlohe z 5.cvičenia). Teraz nakresli štyri šípky, ktoré nakreslia obrys takéhoto štvorca:import tkinter def sipka(xy1, xy2): ... canvas = tkinter.Canvas() canvas.pack() canvas.create_rectangle(150, 50, 250, 150, fill='gold') sipka(...) sipka(...) sipka(...) sipka(...) tkinter.mainloop()
Mal by si dostať takýto obrázok:
Napíš funkciu
vektor(xy, dlzka, uhol)
, ktorá nakreslí vektor (teda šípku) z boduxy
(dvojprvkovýtuple
celých čísel) s danou dĺžkou a s daným uhlom (v stupňoch). Uvedom si, že koncové body takéhoto vektora ležia na kružnici s polomeromdlzka
a stredomxy
. Na kreslenie šípky využi volanie funkciesipka
z predchádzajúcej úlohy. Funkciavektor
vráti (return
) súradnicu koncového bodu vektora ako dvojicu (tuple
) celých čísel. Napríklad:import tkinter from math import sin, cos, radians def sipka(xy1, xy2): ... def vektor(xy, dlzka, uhol): ... return ... canvas = tkinter.Canvas() canvas.pack() poz = (200, 120) for uhol in range(0, 720, 144): poz = vektor(poz, 100, uhol) tkinter.mainloop()
nakreslí:
Napíš funkciu
ntica_cisel(retazec)
, ktorá z daného reťazca vyrobí n-ticu celých čísel - použi metódusplit
. Napríklad:>>> a = ntica_cisel('12 345 6 -78 9000') >>> a (12, 345, 6, -78, 9000)
Napíš funkciu
retazec(ntica)
, ktorá z ntice čísel vyrobí reťazec - použi metódujoin
. Napríklad:>>> retazec((12, 3.45, 6, -78, 9000)) '12 3.45 6 -78 9000'
Napíš funkciu
zadaj(pocet)
, ktorá vráti prečítanú n-ticu čísel zo vstupu (input
). Funkcia si vypýta od používateľa, aby zadal príslušný počet čísel (napríkladinput(f'zadaj {pocet} čísla: ')
) a ak ich používateľ nezadá požadovaný počet, bude si tentoinput
pýtať znovu a znovu. Funkcia vráti (return
) n-ticu celých čísel a nie n-ticu reťazcov. Napríklad:>>> tri = zadaj(3) zadaj 3 čísla: 12 3 zadaj 3 čísla: 12 3 456 >>> tri (12, 3, 456)
Napíš funkciu
zisti(slovo1, slovo2)
, ktorá zistí (vrátiTrue
aleboFalse
), či sú dve zadané slová zložené presne z tých istých písmen - možno v inom poradí. Napríklad:>>> zisti('Skola', 'Lasko') True >>> zisti('poobede', 'bopeodo') False
Pomôcka: použi funkciu
sorted
Napíš funkciu
vsetky_rozne(zoznam)
, ktorá zistí (vrátiTrue
aleboFalse
), či sú všetky prvky zoznamu rôzne. Najprv si vyrob utriedený pomocný zoznam (nepokaz pôvodný) a v ňom zisťuj, či sa nenachádzajú dve rovnaké hodnoty za sebou. Napríklad:>>> vsetky_rozne([3, 8, 7, 9, 4, 1, 6, 10, 5, 2]) True >>> zoz = [3, 8, 7, 9, 4, 1, 6, 3, 10, 5, 2] >>> vsetky_rozne(zoz) False >>> zoz [3, 8, 7, 9, 4, 1, 6, 3, 10, 5, 2]
Napíš funkciu
enum(postupnost)
, ktorá vráti (return
) n-ticu dvojíc. V tejto n-tici je prvý prvok poradové číslo (od0
do počet prvkov postupnosti minus 1) a druhým je prvok z danej postupnosti. Malo by to dať rovnaký výsledok akotuple(enumerate(postupnost))
ale bez použitiaenumerate
. Napríklad:>>> enum([12, 'dva', 3.14]) ((0, 12), (1, 'dva'), (2, 3.14))
Python ponúka ešte jednu štandardnú funkciu
zip
. Táto funkcia, keď dostane nejaké dve postupnosti (napríklad zoznam, n-ticu, reťazec,range
, …), vytvorí z nich jednu novú postupnosť dvojíc (tuple
): v každej takejto dvojici je jeden prvok z prvej a jeden z druhej postupnosti. Môžeš vyskúšať, napríklad:>>> list(zip('python', [2, 3, 5, 7])) [('p', 2), ('y', 3), ('t', 5), ('h', 7)]
Zrejme, ak je jedna z týchto postupností kratšia, výsledok sa nastaví podľa nej. Napíš funkciu
moj_zip(post1, post2)
, ktorá z dvoch postupností (iterovateľných objektov možno rôznej dĺžky) vytvorí jeden zoznam dvojíc. Nepouži štandardnú funkciuzip()
.
Prepíš funkciu
enum
z (18) úlohy tak, aby neobsahovala cyklus a využila tvoju funkciumoj_zip
. Teda:def enum(postupnost): return ... moj_zip ...
Napíš funkciu
od_zip(zoznam)
, ktorá bude fungovať ako opak funkciemoj_zip
. Funkcia dostáva zoznam dvojíc a vráti dva zoznamy prvých a druhých prvkov dvojíc. Napríklad:>>> z1, z2 = od_zip([(2, 'a'), ('h', 3), (5, 'o'), ('j', 7)]) >>> z1 [2, 'h', 5, 'j'] >>> z2 ['a', 3, 'o', 7]
Napíš funkciu
do_dvojic(zoznam)
, ktorá daný zoznam (alebo n-ticu) párnej dĺžky „rozseká“ na zoznam dvojíc (list
s prvkamituple
), dvojice postupne budú (prvý, druhý), (tretí, štvrtý), … Napríklad:>>> x = do_dvojic(('11', 22, '3', 4)) [('11', 22), ('3', 4)]
Rieš najprv bez použitia funkcie
moj_zip()
z predchádzajúcich úloh (teda pomocou for-cyklu) a potom pomocou tejto funkcie (bez cyklu).
Napíš funkciu
pomiesaj(zoznam)
, ktorá náhodne pomieša poradie prvkov v pôvodnom zozname. Funkcia nič nevypisuje ani nevracia, len zmení obsah zoznamu. Funkcia by pren
-prvkový zoznam mala pracovať takto:najprv zvolí náhodné číslo
x
od 0 don-1
v zozname vymení
x
-tý a posledný prvokpotom zvolí náhodné číslo
x
od 0 don-2
v zozname vymení
x
-tý a predposledný prvok (t.j.zoznam[-2]
)potom zvolí náhodné číslo
x
od 0 don-3
v zozname vymení
x
-tý a a tretí od koncatakto to opakuje, kým sa dá
Napríklad:
for i in range(4): p = list(range(1, 11)) pomiesaj(p) print(p)
[2, 9, 6, 1, 7, 8, 10, 3, 5, 4] [7, 2, 10, 9, 6, 8, 4, 1, 3, 5] [3, 8, 7, 9, 4, 1, 6, 10, 5, 2] [2, 9, 4, 1, 8, 3, 5, 7, 6, 10]