pre up next title end end

7. Soubory a moduly

  1. Soubory
  2. Datový typ bytes, bytearray, memoryview
    1. Převod objektu na bytes
    2. Převod bytes na původní objekt
    3. Bytearray
    4. Memoryview
  3. Práce s textovými soubory
  4. Práce s binárními soubory
  5. Vytváření a import modulů
    1. Import modulu
    2. Cesta k modulu
    3. Import modulu z paketu
  6. Modul sys a proměnná argv
  7. Modul Numpy, Array, Matplotlib
    1. Modul Numpy
    2. Modul Array
    3. Modul Matplotlib
  8. Glosář
  9. Cvičení

7.1 Soubory

Všechny soubory, které máme uloženy v paměti na disku, jsou uloženy v binárním formátu. Při otevírání souboru v nějaké aplikaci (například v textovém editoru či v Průzkumníku souborů) je binární formát automaticky převeden do formátu, který lze číst nebo prohlížet. V prostředí Pythonu nám práci s binárním formátem umožňuje existence datového typu bytes.
Názvy souborů by neměly být stejné jako jména vestavěných objektů (built-ins).

Při práci s textovým i binárním souborem musíme znát dvě věci - kde je soubor uložen a v jakém kódování (UTF-8, ASCII, ...) byl textový soubor uložen, neboli převeden do binárního formátu.
Před vlastní manipulací s obsahem souboru musíme soubor otevřít funkcí open(~), po ukončení úprav musíme soubor zavřít funkcí close().


7.2 Bytes, bytearray, memoryview

Pro zvídavé

Objekt typu bytes je neměnitelná sekvence bitů. Tato binární serializace je nutná pro uložení dat do paměti počítače nebo pro jejich transport po síti.
Mnohá data (obrázky, zvuk, text) lze serializovat (kódovat - encode) na objekt typu bytes či deserializovat (dekódovat - decode) z typu bytes s použitím vhodného protokolu, jako je PNG, WAW, JSON nebo UTF-8, ASCII, cp1250 aj.

7.2.1   Převod objektu na bytes

Prezentaci objektu ve formátu bytes lze provést dvojím způsobem a to úpravou literálu nebo s použitím příslušných funkcí či metod.

Literálový přepis objektu na typ bytes vytvoříme předznamenáním literálu písmenem b. Vhodným typem literálu je řetězec (string), obsahující pouze znaky ze sady ASCII.
Řetězec se znaky UTF-8 lze převést funkcí bytes().

>>> asc = "Za horami, za lesy"         # konformní s ASCii 
>>> utf = "Bílá růže"                  # konformní s UTF-8

Literálová forma pro bytes:
>>> lba = b'Za horami, za lesy'; lba  
b'Za horami, za lesy'                  
>>> lbu = b'Bílá růže'; lbu            # bude to chtít funkci  
SyntaxError: bytes can only contain ASCII characters.  # vida

Převod funkcí bytes a encode

Převod na formát bytes lze provést pro všeliké kódování funkcí bytes, přijímající tři nepovinné parametry:

bytes([source[, encoding[, errors]]])
>>> asc = "Za horami, za lesy"
>>> utf = "Bílá růže"

>>> bytes(asc, "utf-8")         
b'Za horami, za lesy'          
>>> bytes(utf, "utf-8")
b'B\xc3\xadl\xc3\xa1r\xc5\xaf\xc5\xbe e'
       í        á	 ů       ž

Znaky, které nejsou součástí ASCII, jsou vyjádřeny hexadecimálními čísly za zpětnými lomítky (escape sekvence). Na příkladě vidíme, že znaky ze sady UTF-8 (í, á, ů, ž) jsou vyjádřeny dvěma kódovými čísly.

Převod na formát bytes metodou .encode() - pouze pro typ 'string':

string.encode([encoding[, errors]])

Údaj o kódování (encoding) lze vypustit, pokud souhlasíme s implicitně nastaveným utf-8. Pokud chceme použít jiné kódování, musíme jej uvést:

>>> bytes("píšeš", "utf-8")      # kódování je povinné
b'p\xc3\xad\xc5\xa1e\xc5\xa1'
>>> "píšeš".encode()             # pro utf-8 je nepovinné
b'p\xc3\xad\xc5\xa1e\xc5\xa1'
>>> "píšeš".encode('utf-16')     # pro jiné kód. je povinné
b'\xff\xfep\x00\xed\x00a\x01e\x00a\x01'

7.2.2   Převod bytes na původní objekt

Při deserializaci (decoding) objektu typu bytes na původní objekt musíme vědět, jaké kódování bylo při serializaci použito. To není vždy spolehlivě zjistitelné.

Pro převod použijeme metodu zdroj.decode('coding')

>>> by = bytes("píšež", "utf-8"); by   # kódování je povinné   
b'p\xc3\xad\xc5\xa1e\xc5\xa1'          # objekt typu bytes
>>> by.decode("utf-8")                 # kódování je nepovinné
'píšeš' 

Lze také použít funkci str(bytes-obj, 'coding'):

>>> str(by, "utf-8")                   # kódování je povinné
'píšež' 

7.2.3   Bytearray

Typ bytearray je měnitelná verze typu bytes.

Pro bytearray použijeme funkci  bytearray(bytes):
>>> ba = bytearray(b'Za horami, za lesy'); ba
bytearray(b'Za horami, za lesy')
>>> by = bytes('Souznění', 'utf-8'); by   # objekt typu bytes
b'Souzn\xc4\x9bn\xc3\xad'                 # nejde změnit
>>> ba = bytearray(by); ba
bytearray(b'Souzn\xc4\x9bn\xc3\xad')
# případně:  
>>> ba = bytearray('Souznění', 'utf-8'); ba
bytearray(b'Souzn\xc4\x9bn\xc3\xad')
# Úprava iteráblu s konkatenací:
>>> ba[0] = 108           # změna znaku "S": (ord("l")=108)
>>> aba = bytearray("B", "utf-8") + ba; aba 
bytearray(b'Blouzn\xc4\x9bn\xc3\xad')
>>> str(aba, "utf-8")                     # převod na řetězec
'Blouznění'

7.2.4   Memoryview

Interní data objektu, uložená ve vyrovnávací paměti (buffer) jsou přístupná prostřednictvím procedury, zvané buffer protocol.

Tento protokol používá sekvenční objekt memoryview, vytvořený funkcí memoryview(obj). Objekt memoryview umožňuje přímý přístup (bez kopírování) k interním datům objektů typu bytes a bytearray.

Význam objektu memoryview spočívá v tom, že šetří paměť a urychluje výpočet zejména mnohokrát opakovaných operací.

# Vytvoření objektu
>>> ba = bytearray('Python','utf-8')    objekt bytearray
>>> mvba = memoryview(ba); mvba         objekt memoryview
<memory at 0x0000020ED8FD53C0>          místo v paměti
>>> tmvba = tuple(mvba); tmvba          mvba jako tuple  
(80, 121, 116, 104, 111, 110)         
cm_mvba = [chr(i) for i in tmvba]; cm_mvba  převod komprehencí
['P', 'y', 't', 'h', 'o', 'n']              viz kap. 3.5 

# Změna objektu 'ba' prostřednictvím 'mvba'
>>> mvba[0] = 74; ba                    chr(74) = J              
bytearray(b'Jython')

# Výsek z objektu 'ba' prostřednictvím 'mvba'
>>> slba = tuple(mvba[0:4]); slba
(74, 121, 116, 104)
>>> cm_slba = [chr(i) for i in slba]; cm_slba
['J', 'y', 't', 'h']

# Výsek pro bytes/memoryview/bytearray    
>>> bymv = bytes(mvba[0:4]); bymv       
b'Jyth'
>>> bymv.decode('utf-8')                   
'Jyth'

# Výsek pro bytearray/memoryview/bytearray
>>> bamv = bytearray(mvba[0:4]); bamv
bytearray(b'Jyth')
>>> bamv.decode('utf-8')
'Jyth'

Sekvence memoryview vytvořená z objektu bytes je neměnitelná, sekvence vytvořená z bytearray je měnitelná. Ovšem (jak vidno), sekvence bytes/memoryview/bytearray je rovněž měnitelná - zřejmě proto, že argumentem 'bymv' je objekt 'mvba', vytvořený z objektu 'ba' (bytarray).

Příložený soubor by_ba_mv.py obsahuje obšírný přehled vzájemných kombinací mezi typy bytes, bytearray a memoryview.


7.3 Práce s textovými soubory

Otevření souboru funkcí open(~) vytváří souborový objekt (file_object), označovaný také jako stream:

file_obj = open('file', mode='r', buffering=-1, encoding=None,
      errors=None, newline=None, closefd=True, opener=None)
file: název textového či bajtového souboru včetně přípony
      a případné cesty
mode: přístupový režim pro manipulaci se souborem
coding: žádané kódování např. coding="utf-8" či "cp1250" (nebo "ASCii")
buffering: nastavení velikosti vyrovnávací paměti - nebudeme používat

Přístupové režimy

Přístupový režim (mód) určuje, jakou manipulaci lze s otevřeným souborem provádět. Není-li režim zadán, je implicitně nastaven režim read. Zároveň určuje polohu interního 'ukazovátka', označujícího počáteční místo pro případnou manipulaci.

'r', 'rt' (read, read text)  pouze pro čtení; ukazovátko
      na začátku souboru
'w', 'wt' (write, write text) pouze pro psaní; ukazovátko
      na začátku souboru; přepisuje  existující  soubor,       neexistující vytvoří
'x'   vytvoří nový soubor a otevře jej pro psaní 
'a'   (append) pro připojení textu; ukazovátko na konci existujícího souboru; neexistující soubor vytvoří
'rb', 'wb', 'ab'  totéž co 'r', 'w', 'a' ale pro binární soubor
'r+', 'rb+' pro čtení i psaní - pozor, přepisuje existující soubor
Těmto režimům je lépe se vyhnout:
'w+', 'wb+' pro psaní i čtení; přepisuje existující soubor,
       neexistující vytvoří
'a+', 'ab+' pro připojení textu i čtení; neexistující soubor vytvoří  

Manipulaci se souborovým objektem (streamem) si ukážeme na několika příkladech.

>>> myfile = open('test.dat', 'w')       # zde vytváříme nový stream
>>> print(myfile)
<_io.TextIOWrapper name='test.dat' mode='w' encoding='cp1250'>

Příkaz print() nám vrátil typ objektu, jméno souboru, použitý mód a kódování souboru.

Neexistuje-li soubor se jménem test.dat, bude vytvořen v aktuálním adresáři. Jestliže takový soubor v režimu "w" již existuje, bude jeho text nahrazen textem, který případně zapíšeme.

Pro vkládání dat do souboru použijeme metodu souborového objektu write. Pokud proceduru 'write' provádíme v jedné seanci opakovaně, k přepisu stávajícího textu nedojde. K přepisu dojde u nově aktivovaného souborového objektu.

>>> myfile.write("Nyní je čas")            # 11 znaků
>>> myfile.write(" zavřít soubor.")        # 15 znaků

Zavření souboru říká systému, že jsme skončili zapisování a soubor je možné zavřít:

>>> myfile.close()

Nyní můžeme soubor opět otevřít, tentokrát pro čtení a načíst jeho obsah do řetězce v našem programu.

>>> myfile = open('test.dat', 'r')

Pokusíme-li se otevřít soubor, který neexistuje, dostaneme chybové hlášení:

>>> myfile = open('test.cat', 'r')
FileNotFoundError: [Errno 2] No such file or directory: 'test.cat'

Pokusíme-li se otevřít soubor s českým textem, můžeme dostat toto chybové hlášení:

>>> ovoce = open("cz_fruits.txt")
>>> next(ovoce)
...
UnicodeDecodeError: 'charmap' codec can't decode 
byte 0x88 in position 27: character maps to <undefined>
... Kodek 'charmap' neumí dekódovat bajt 0x88 (136) na pozici 27

Náprava spočívá v tom, že zadáme rovněž parametr 'encoding':

>>> ovoce = open("cz_fruits.txt", encoding="utf-8")
>>> next(ovoce)
'pomeranč\n'

Metoda read() bez argumentů načte celý obsah do jediného řetězce:

>>> print(myfile.read())
Nyní je čas zavřít soubor.
>>> myfile.close()

Metoda read() může také přijmout argument, který říká kolik znaků má být čteno:

>>> myfile = open('test.dat')       # nutno znovu "naládovat"
>>> print(myfile.read(7))
Nyní je

Zadáme-li číslo větší než je počet znaků v souboru, vrátí read() jen zbývající znaky. Došlo-li se na konec souboru, vrátí read() prázdný řetězec:

>>> print(myfile.read(726))
 čas zavřít soubor.
>>> print(myfile.read())
                                 # nemáme "naládováno"

Podivné chování metody read() je důsledkem toho, že souborový objekt je také iterátorem a když opět nahlédneme do kap. 3.1, tak si připomeneme, že iterátorový objekt vlastní funkci next(), která posouvá interní index objektu a jejíž použití si nyní opět ukážeme.
Otevřeme si soubor unsorted_fruits.txt a jeho obsah vložíme do souboru "fruits.txt", který vložíme do složky, v níž následně aktivujeme konzolu interpreta Pythonu. Ze souboru vytvoříme souborový objekt (neboli iterátor):

>>> fru = open("fruits.txt")  # fce 'open' vytvoří iterátor
>>> next(fru)
'papaya\n'                    # \n označuje konec řádku
>>> next(fru)
'kiwifruit\n'
...
>>> next(fru)
StopIteration                 # vyčerpali jsme celý seznam
>>> fru.read()            
''                            # potvrzeno, vrabci vyklobali

Potřebujeme-li z objektu znovu číst, musíme přesunout jeho ukazovátko (pointer) na začátek - a to nejlépe metodou seek(offset[, from]):

>>> fru.seek(0, 0)          # jsme opět na začátku!
>>> print(fru.readline())   # vrátí obsah aktuálního řádku
papaya
>>> print(fru.readlines())  # vrátí seznam řetězců, obsahujících zbývající řádky
papaya
>>> print(fru.tell())       # sdělí pozici ukazovátka
8
>>> fru.close()             # zavřít objekt se vřele doporučuje 

Metoda readline() přečte všechny znaky z prvního řádku včetně znaku newline:

Metoda readlines() vrátí všechny zbyvající řádky jako seznam řetězců:

Automatické zavření objektu nám zajistí použití idiomu with :

with open("week.txt", "w") as dny:
   dny.write("pondělí\núterý\nstředa\nčtvrtek\npátek\nsobota\nneděle\n")

# Soubor je zavřen, pro novou manipulaci jej musíme opět otevřít

with open("week.txt") as ven:
   for line in ven.readlines():
      print(line, end='') 

Skript vytvořil v aktuálním adresáři soubor 'week.txt' (pokud již neexistoval) a vložil do něho dny týdnu. Při dalším otevření souboru (implicitně v režimu 'read') jsme předepsali jejich postupný výtisk v konzole. Po ukončení práce se soubor sám zavřel.
Ověřte si to v IDLE nebo v Thonny.

Následující funkce kopíruje textový soubor tak, že přečte a zapíše nejvíce 50 znaků najednou. První argument je jméno původního souboru, druhý argument je jméno nového souboru:

copy_file.py
                        # názvy souborů v uvozovkách
def copy_file('oldfile', 'newfile'):   
    infile = open(oldfile, 'r')
    outfile = open(newfile, 'w')
    while True:
        text = infile.read(50)
        if text == "":
            break
        outfile.write(text)
    infile.close()
    outfile.close()
    return

Tato funkce cyklicky čte 50 znaků z infile a zapisuje je do outfile až je dosaženo konce a text je prázdný řetězec, čímž se vyvolá provedení příkazu break.
Soubor copy_file.py uložte do složky, kde máte soubor oldfile.

Na objekt typu file (soubor) lze rovněž aplikovat metodu .split() (viz 6.2.4), jíž je možné roztrhnout soubor na jednotlivé řádky, věty či slova. Pro soubor "unsorted_fruits.txt" to provedeme takto:

file=open("unsorted_fruits.txt").read() 

řádky = file.split("\n")        # separátorem je konec řádku
věty = file.split(".")          # separátorem je tečka
slova = file.split()            # separátorem je mezera

Pokud se zadaný separátor v textu nevyskytuje, k roztržení souboru nedojde.


7.4 Práce s binárními soubory

Soubory, které obsahují fotografie, obrázky, videa, zvukový záznam, zipové a spustitelné soubory - se nazývají binární soubory. Tyto soubory nejsou organizovány do řádků a nelze je (užitečně) otevřít normálním textovým editorem.

V Pythonu tyto soubory regulerně otevřeme již popsanou funkcí open v režimu rb (read binary) a wb (write binary). V následující ukázce vytvoříme binární kopii velikonočního pozdravu:

copy-easter.py

f = open("easter_328kb.jpg", "rb")   # existující kopírovaný soubor
g = open("easter_copy.jpg", "wb")    # nový (prázdný) soubor tamtéž

while True:
    buff = f.read(3300)              # pomocný objekt 3300 bitů
    if len(buff) == 0:
         break
    g.write(buff)

f.close(); g.close()	

Soubor easter_328kb.jpg si prohlédnete zde , otevřený obrázek si v otevřeném kontextovém menu uložíte volbou "Save image as...". Pro potěšení si posléze ve svém adresáři otevřete také easter_copy.jpg

V následující ukázce si vytvoříme nový soubor a vložíme do něho text v kódování utf-8. Následně si tento soubor otevřeme jako objekt typu bytes:

with-open.py

with open("cat.txt", "w", encoding="utf-8") as cat:
    cat.write("Kočička")

with open("cat.txt", "rb") as cat:
    data = cat.read()
>>> data
b'Ko\xc4\x8di\xc4\x8dka'

Ve výstupu vidíme, že písmeno "č" se v utf-8 vyjádří pomocí dvou bajtů, což se v zápisu binárního řetězce (který je implicitně kódován v ASCII) projeví aplikací "escape sekvence", neboli použitím 'zpětného lomítka'.


7.5 Vytváření a import modulů

Soubor s příponou ~.py může být spuštěn jako skript přímou invokací (python file_name.py) z příkazového řádku systémové konzoly (CMD či Terminál) nebo být načten jako modul do jiného souboru příkazem import v jeho záhlaví.

Vestavěné (built-in) moduly jsou psány v jazyce C a jsou součástí standardní knihovny Pythonu - viz Python Module Index. Příkladem vestavěných modulů jsou moduly math, string, random, sys,   se kterými se postupně seznámíme.

Jako vlastní modul můžeme použít vhodný textový soubor s příponou .py. Název souboru nesmí být rozdělen pomlčkou, přípustné je podtržítko.

# file_1.py                        # zamýšlený modul    

def mocnina(m, n=3):               # příklad funkce
    print(" {}**{} = {} " .format(m, n, m**n))
	
print("Zpráva ze souboru file_1.py")              # příkaz
print("Hodnota proměnné __name__ je ", __name__)  # příkaz
print(__name__)                                   # příkaz

Po přímé invokaci tohoto souboru v konzole (--> vyhledat nadřazenou složku v Průzkumníku -> po pravém kliku zvolit "Otevřít v aplikaci Terminál" -> zadat příkaz python  -i  file_1.py) dostaneme tento výstup:

Zpráva ze souboru file_1.py
Hodnota proměnné __name__ je __main__      # vida!
__main__                                   # vida!
>>>                           # jsme v konzole Pythonu                         
>>> mocnina(5)                # funkci musíme volat
 5**3 = 125                   # formátovaný výstup fce 'print'
>>> __name__                  # bez příkazu 'print' chodí jen v konzole
'__main__'                    # interní jméno skriptu

V následující ukázce si předvedeme vliv příkazu 'import' a použití idiomu if __name__ == '__main__':

# file_2.py

import file_1

print("Nazdárek Kašpárek")
print("Hodnota proměnné __name__ je ", __name__)

if __name__ == "__main__":
    print("Soubor file_2.py byl invokován přímo.")
    file_1.mocnina(5)
else:
    print("Soubor file_2.py byl invokován nepřímo.")

Po přímé invokaci tohoto souboru dostaneme tento na první pohled podivně řazený výstup - jeho první tři řádky jsou výstupem z importovaného souboru, zbývající čtyři řádky jsou výstupem ze souboru 'file_2.py'.
Znak >>> je svědectvím toho, že provoz interpreta přešel z realizace skriptu 'file_2.py' do prostředí konzoly (REPL) Pythonu:

Zpráva ze souboru file_1.py             # výstup z modulu
Hodnota proměnné __name__ je  file_1    # výstup z modulu                       
file_1                                  # výstup z modulu
Nazdárek Kašpárek                       # výstup ze skriptu
Hodnota proměnné __name__ je  __main__  # výstup ze skriptu
Soubor file_2.py byl invokován přímo.   # výstup ze skriptu
 5**3 = 125                             # výstup ze skriptu
>>>                                     # přechod do konzoly
>>> file_1.mocnina(5,4)                 # invokace z konzoly
 5**4 = 625

Co k tomu dodat? V importovaném modulu by se neměly vyskytovat přímo proveditelné příkazy

7.5.1   Import modulu

Import modulu lze provést různým způsobem.

a) Importujeme celý modul a jeho objekty evokujeme tečkovou notací:

>>> import mojevoje
Quo vadis?                     # samostatně provedený text
>>> mojevoje.mocnina(4)        # evokace tečkovou notací
64

Případně importujeme celý modul pod jiným jménem
>>> import mojevoje as mv
Quo vadis?                     # samostatně provedený text
>>> mv.mocnina(4)              # evokace tečkovou notací
64

b) Importujeme všechny objekty z modulu:

>>> from mojevoje import *
Quo vadis?                     # samostatně provedený text
>>> mojevoje.mocnina(4)        # evokace tečkovou notací
64
# Tento způsob se nedoporučuje, neboť může dojít ke
  kolizi jmen.

c) Importujeme jen určitý objekt modulu

>>> from math import pi, factorial as fact
>>> pi, fact(8)
(3.141592653589793, 40320)

Importem dochází ke spuštění importovaného souboru a nic se neděje, pokud importovaný soubor neobsahuje samostatně proveditelný příkaz, jako je například příkaz print("Quo vadis?").

7.5.2   Cesta k modulu

Importujeme-li vlastní modul, musíme mít k němu zajištěnou cestu tím, že:

  1. Modulový soubor se nachází ve stejném adresáři jako zdrojový soubor - tento způsob jsme dosud používali.
  2. V záhlaví zdrojového souboru uvedeme cestu k modulovému souboru (například 'mojevoje.py') ve složce F/Codetest/Howto/ch-07/. Je-li IDLE otevřen ve složce F/Codetest/Howto/, doplníme zbytek cesty pomocí tečkové notace:
    F:/Codetest/Howto> python
    
    >>> import sys
    >>> sys.path.append("ch-07/")     # doplnění cesty
    
    >>> import mojevoje
    Quo vadis?             # importovaný soubor se v možném 
                             rozsahu ihned realizuje
    
  3. Máme-li soubor, který můžeme často používat jako modul, můžeme jej vložit do instalační složky Pythonu ../Lib/site-packages; umístění této složky zjistíme (z jiného místa) dotazem:
    >>> import sys
    >>> print(sys.path)
    
    Takto uložený soubor můžeme importovat odkudkoli.
    Poznámka: Stejného účinku dosáhneme, jestliže máme v Console2 nastaveno aby se konzola Python spouštěla v téže složce, kde odkládáme své modulové soubory.

7.5.3   Import modulu z paketu

Paket (package) je adresář, který spolu s potřebnými soubory (moduly) ~ .py obsahuje také soubor (třeba prázdný) __init__.py. Tento konstrukt využívá inherentní souborovou strukturu operačního systému.

Mějme například složku (paket) package/ se soubory __init__.py a foo.py.

ch-07/package/foo.py

class Foo:                  # deklarace třídy (viz kap. 10)
    def ukul(self):         # metoda (funkce) třídy           
        print("Ukulele")

Ukulele si můžeme vytisknout v konzole, otevřené ve složce ch-07:

F:/Codetest/Howto/ch-07> python

>>> import package.foo          #1 deklarace cesty k modulu
>>> inst = package.foo.Foo()    #2 vytvoření instance třídy
>>> inst.ukul()                 #3 volání metody třídy
Ukulele

Alternativně lze provést import modulu foo s přejmenováním:

F:/Codetest/Howto/ch-07> python

>>> import package.foo as foe   #1 deklarace s přejmenováním
>>> inst = foe.Foo()            #2 vytvoření instance třídy
>>> inst.ukul()                 #3 volání metody třídy
Ukulele

Jak vidno, program Pythonu umožňuje přístup k podřízeným položkám pomocí tečkové notace.
V prvním případě nahrazuje tečka lomítko v deklaraci cesty. Ve druhém a třetím případě působí tečky při vytvoření instance třídy a při volání metody třídy.


7.6 Modul sys a proměnná argv

Modul sys obsahuje funkce a proměnné, které poskytují přístup k prostředí operačního systému, ve kterém běží překladač Pythonu. Následující příklad ukazuje výstupní hodnoty několika příkazů, zadaných na některém z našich počítačů:

>>> import sys
>>> sys.platform
'win32'

>>> sys.path
['', 'D:\\Python\\Lib\\idlelib', 'D:\\Python\\python310.zip', 'D:\\Python\\DLLs', 'D:\\Python\\lib', 'D:\\Python', 'D:\\Python\\lib\\site-packages']

>>> sys.version
'3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)]'

Úplný obsah modulu sys nám vrátí funkce:

>>> dir(sys)                         

Interní seznam sys.argv obsahuje výpis argumentů, zadaných při spouštění Pythonu i souboru ~.py současně z příkazového řádku systémové konzoly.

Vytvořme skript demo_argv.py

F:/codetest/howto/ch-07/demo_argv.py

import sys

print(sys.argv)
print(len(sys.argv)))            

Spustíme jej z příkazového řádku zároveň s argumenty (viz) a obdržíme:

F:\Codetest\HowTo\ch-07 > python demo_argv.py Zdrávi došli 315
['demo_argv.py', 'Zdrávi', 'došli', '315']
4

Argumenty, mezi něž patří i název skriptu, jsou odděleny pouze mezerou. Chceme-li zadat argumenty s uskupením, použijeme uvozovky:

F:\Codetest\HowTo\ch-07 > python demo_argv.py "Zdrávi došli"  "31" 5
['demo_argv.py', 'Zdrávi došli', '31', '5']
4

Pomocí argv můžeme psát užitečné programy, které přijímají vstupy přímo z příkazového řádku. Zde je například program, který určí součet zadané řady čísel:

sum.py

from sys import argv

nums = argv[1:]     # index '0' je vyhrazen pro název souboru

# Funkce enumerate(~) vytváří z objektu 'nums' iterátor - viz 4.9.
for index, value in enumerate(nums):
    nums[index] = float(value)

print(sum(nums))

V tomto programu používáme způsob importu from <module> import <attribute>, při kterém je pouze proměnná argv přenesena do jmenného prostoru aktuálního modulu.

Nyní můžeme spouštět program z příkazové řádky takto:

F:\Codetest\HowTo\ch-07 > python sum.py 3.5 5 11 100
119.5

7.7 Modul Numpy, Array a Matplotlib

Pouze pro zvídavé

7.7.1   Modul Numpy

Aplikaci Numpy je nutné nejprve instalovat. Ve Windows s instalovaným programem Python s aplikací pip to je jednoduché:

C:\> pip install numpy                # velikost cca 15 MB

Knihovnu Numpy je nutné importovat do aktuálního pracovního prostředí Pythonu:

>>> import numpy as np               

Numpy používá vlastní formát kolektoru, zvaný array neboli pole. Prvky tohoto kolektoru musí být homogenní - to jest, musí být stejného typu.
Datový typ pole může být jedno- (1D, vektor), dvou- (2D, matice), tři- (3D, tenzor) i více (nD) dimenzionální.
Dimenzím se v Numpy říká osy (axes). Velikost pole je vyjádřena atributem shape (tvar), což je entice celých čísel, která vyjadřují délky jednotivých os (dimenzí).

Array v Numpy vytvoříme ze seznamu příkazem np.array() :

>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
>>> a[1][2]
7
>>> a.shape
(2,4)                   # počet os = počtu prvků v entici

Uvedené pole má dvě osy (je to tedy matice) o délkách 2 a 4 položky. Pro přístup k vybranému prvku matice lze použít indexy (počínající nulou).

Součin dvou matic je v Numpy líbezně prostý:
>>> a = np.array([[1,2,3], [4,5,6]])
>>> b = np.array([[7,8], [9,1], [2,3]])
>>> c = np.matmul(a, b)
>>> c.shape
(2, 2)
>>> print(c)
[[31, 19],
 [85, 55]]

Protože solidnější popis práce s modulem Numpy přesahuje rámec tohoto tutoriálu, odkazuji případné zájemce na tuto webovou stránku.

7.7.2   Modul Array

Array je kolektor, podobně jako seznam. Na rozdíl od seznamu, který je vestavěným objektem Pythonu, je nutné objekt array vytvořit importovanou funkcí array() z modulu array nebo z instalovaného modulu (pip install numpy) numpy:

# Import z modulu array: 
>>> from array import array as arr     import funkce z modulu
>>> arrpy = arr("i", [3, 6, 9, 12])    její aplikace

>>> import array as arr                import celého modulu
>>> arrpy = arr.array("i", [3, 6, 9, 12])
>>> print(arrpy)
array('i', [3, 6, 9, 12])
>>> type(arrpy)
<class 'array.array'>

# Import z modulu numpy:
>>> import numpy as np                 import celého modulu
>>> arrnp = np.array(["numbers", 3.6, 6.9, 12])
>>> print(arrnp)
['numbers' '3.6' '6.9' '12']
>>> type(arrnp)
<class 'numpy.ndarray'>

Deklarace kolektoru array má skladbu:

array_name = invokace_fce_array('type_code', [seznam_hodnot])

Údajem 'type_code' zadáváme typ a velikost jednotlivých elementů v bajtech:

signed integer: 'b'(1), 'i'(2)
float :         'f'(4), 'd'(8)
unicode char:   'u'(2)               # aktuálně 'deprecated' 

Modul array obsahuje také řadu metod

>>> ar_ray = arr('i', [1, 2, 3, 4]); ar_ray
 array('i', [1, 2, 3, 4])
insert
>>> ar_ray.insert(3,9); ar_ray
 array('i', [1, 2, 3, 9, 4])
remove
>>> ar_ray.remove(1); ar_ray
 array('i', [2, 3, 9, 4])
pop
>>> ar_ray.pop(2); ar_ray
 array('i', [2, 3, 4]) 

Kolektory array s výhodou použijeme při rozsáhlejších matematických výpočtech, neboť jsou rychlejší než standardní seznamy (lists).

7.7.3   Modul Matplotlib

V Kap. 8.11.2 je popisováno, jak lze rozdělit pole náhodných čísel [0,1) na intervaly (bucketWidth) a určit počet výskytů náhodných čísel v daném intervalu(výskyty).

Tento soubor čísel (frekvenční tabulku) je možné graficky znázornit histogramem, vytvořeným pomocí knihovny Matplotlib.

python -m pip install -U matplotlib          # velikost cca 12 MB

Podrobný popis práce s tímto nástrojem lze nalézt například zde.


7.8 Glosář

modul (module)
Soubor obsahující definice a příkazy Pythonu určené pro použití v jiných pythonovských programech. Obsah modulu je zpřístupněn použitím příkazu import .
standardní knihovna (standard library)
Knihovna je kolekce programů, používaných jako nástroje při vytváření jiných programů. Knihovny jsou nedílnou součástí programovacích jazyků. Python má bohatou standardní knihovnu.
pydoc
Generátor dokumentace, který je součástí standardní knihovny Pythonu.
jmenný prostor (namespace)
Syntaktický kontejner, který umožňuje aby totéž jméno mohlo být součástí různých jmenných prostor bez víceznačností. Jmenné prostory v Pythonu se tvoří pro moduly, třídy, funkce a metody.
jmenná kolize (naming collision)
Situace, při které nelze od sebe rozlišit dvě nebo více jmen v daném jmenném prostoru. zabráníme jmenné kolizi.
metoda (method)
Funkce, definovaná uvnitř třídy. Metody se pro objekt evokují s použitím tečkového operátoru, například:
>>> s = "this is a string"
>>> s.upper()                     # upper() je metoda                
'THIS IS A STRING'

Říkáme, že metoda upper je volána pro řetězec s.

nestálá paměť (volatile memory)
Paměť, která k zachování stavu potřebuje stálý příkon elektrické energie. Hlavní paměť počítače, neboli RAM je nestálá. Informace, uložená v paměti RAM se ztratí při vypnutí počítače.
trvalá paměť (non-volatile memory)
Paměť, která svůj stav udržuje bez elektrické energie. Pevné disky, měnitelné disky a přepisovatelné kompaktní disky (CD-RW) jsou příklady nosičů s trvalou pamětí.
mód (mode)
Určitý způsob operace v počítačovém programu. Soubory v Pythonu mohou být otevřeny v jednom ze tří módů: číst~read ('r'), psát~write ('w'), připojit~append ('a').
textový soubor (text file)
Soubor, který obsahuje tisknutelné znaky uspořádané do řádků oddělených znaky newline.
binární soubor (binary file)
Soubor, který obsahuje pouze nuly a jedničky (strojový kód).
adresář či složka (directory or folder)
Pojmenovaná kolekce souborů či dalších adresářů. Adresáře uvnitř adresářů jsou označovány jako podadresáře (subdirectories).

7.9 Cvičení

  1. Napište program mean.py, který na příkazovém řádku konzoly přijme číselné pořadí a vrátí jeho střední hodnotu. Nejde o doctesty.
    >>> python mean.py 3 4
    3.5
    >>> python mean.py 3 4 5
    4.0
    >>> python mean.py 11 15 94.5 22
    35.625
    
    Vztah mezi vstupy a výstupy u vašeho programu by měl být stejný jako v uvedené ukázce.
    Při řešení použijete vestavěnou funkci sum:
    sum(iterable[, start])            
    
    iterable je sekvence číselných hodnot - viz kap. 4.1
    [, start] je nepovinná hodnota, která se přičte k součtu
    
  2. Napište program median.py který na příkazovém řádku přijme číselné pořadí a vrátí jeho prostřední hodnotu. Řešení bude mít nejspíš větev 'if' a 'else'. Budete mít otevřený textový editor a systémovou konzolu, kde budete ověřovat program v souboru plus konzolu Pythonu, kde si budete ověřovat krátká dílčí řešení. Console2 vám ušetří místo na monitoru.
    >>> python median.py 3 7 11
    7
    >>> python median.py 19 85 121
    85
    >>> python median.py 11 15 16 22
    15.5
    
  3. Proveďte následující:
    • Spusťte server pydoc příkazem & pydoc -b případně > python -m pydoc -b z příkazového řádku.
    • Vyberte modul calendar.
    • Ze sektoru Funkctions vyberte a vyzkoušejte:
      >>> import calendar
      >>> year = calendar.calendar(2020)
      >>> print(year)  
      
    • Experimentujte s funkcí calendar.isleap(~). Co očekává jako argument? Co vrací jako výsledek? O jaký druh funkce se jedná?
    Zapište si poznatky, získané z tohoto cvičení.
  4. Alternativně se lze k webové stránce s nápovědou Pydoc dostat příkazem:

    >>> python -m pydoc -p 7464
    

    To aktivuje webový server pydoc na portu 7464. Jeho stránku ve vašem webovém prohlížeči aktivuje příkaz:

    >>> [b]rowser
    
    Spuštěný server deaktivuje příkaz:
    > [q]uit
    

    Použijte tento postup ke spuštění pydoc a vyhledejte modul math.

    1. Kolik funkcí je v modulu math?
    2. Co dělá math.ceil? A co dělá math.floor? (Nápověda: jak floor tak ceil očekávají argument v desetinném formátu.)
    3. Popište, jak jsme počítali odmocninu vlastní funkcí sqrt bez použití modulu math.
    4. Jaké jsou datové konstanty v modulu math?

    Dělejte si podrobné poznámky o svém zkoumání v tomto cvičení.

  5. Vytvořte modul mymodule1.py. Přidejte atribut myage se zadaným vlastním věkem a year se zadaným současným letopočtem. Vytvořte další modul mymodule2.py. Přidejte atribut myage s nastavenou nulou a year s rokem svého narození.

    Nyní vytvořte soubor namespace.py. Importujte oba výše uvedené moduly a napište následující příkaz:
    print((mymodule1.myage - mymodule2.myage) == (mymodule1.year - mymodule2.year))
    

    Spustíte-li namespace.py, dostanete jako výstup buď True nebo False podle toho, zda jste letos již narozeniny měl nebo neměl.

  6. V prostředí interpretační konzoly si vykoušejte následující:
    >>> import this
    
    Co říká Tim Peter o jmenných prostorech?
  7. Použijte pydoc k vyhledání a vyzkoušení dalších funkcí z modulu string. Porovnejte se seznamem, evokovaným příkazy:
    >>> import string
    >>> dir(string)
    
  8. Použijte dir(str) a dir(list) k nalezení nejméně tří metod na řetězci a seznamu, které nebyly dosud uvedeny. Prozatím ignorujte všechno, co začíná dvojitým odtržítkem (__). Pečlivě si zapisujte své poznatky včetně jmen nových metod a příkladů jejich použití.
    Nápověda: Vytiskněte si dokumentační řetězec funkce, kteru chcete zkoumat. Například, abychom zjistili, jak pracuje str.join, zadáme příkaz print(str.join.__doc__)

  9. V prostředí konzoly vyvolávejte odezvy k následujícím příkazům:
    1. >>> s = "If we took the bones out, \
               it wouldn't be crunchy, would it?"
      >>> s.split()
      
    2. >>> type(s.split())
      
    3. >>> s.split('o')
      
    4. >>> s.split('i')
      
    5. >>> '0'.join(s.split('o'))
      
    Je důležité, abyste každému výsledku porozuměl.
  10. Získané poznatky použijte při doplnění následující funkce s použitím metod split a join na objektech str:
    def myreplace(old, new, s):
        """
        Nahraď všechny argumenty 'old' argumenty 'new'
        v řetězci 's'.
        """
    
        >>> myreplace(',', ';', 'this, that, and, some, other, thing')
        'this; that; and; some; other; thing'
    
        >>> myreplace(' ', '**', 'Words will now be separated by stars.')
        'Words**will**now**be**separated**by**stars.'
        
    
    Vaše řešení má projít oběma doctesty. Tutéž úlohu řešte také přímo s použitím metody replace.
  11. Vytvořte modul wordtools.py s následujcím ukončením:
    if __name__ == '__main__':
        import doctest
        doctest.testmod()
    
    Vysvětlete jak tento příkaz usnadňuje užití a testování vytvořeného modulu. Jaká bude hodnota __name__ při importu wordtools.py z jiného modulu? A jaká bude při spuštění wordtools.py jako hlavního programu? Ve kterém případě budou aktivovány doctesty?
  12. Nyní do tohoto souboru postupně přidejte těla ke každé z následujících funkcí tak, aby bylo vyhověno doctestům:
    def cleanword(word):
        """
        >>> cleanword('what?')
        'what'
        >>> cleanword('"now!"')
        'now'
        >>> cleanword('?+="word!,@$()"')
        'word'
        """
    
    def has_dashdash(s):
        """
        >>> has_dashdash('distance--but')
        True
        >>> has_dashdash('several')
        False
        >>> has_dashdash('critters')
        False
        >>> has_dashdash('spoke--fancy')
        True
        >>> has_dashdash('yo-yo')
        False
        """
    
    def extract_words(s): """ >>> extract_words('Now is the time!"Now", is the time? Yes, now.') ['now', 'is', 'the', 'time', 'now', 'is', 'the', 'time', 'yes', 'now'] >>> extract_words('she tried to curtsey as she spoke--fancy') ['she', 'tried', 'to', 'curtsey', 'as', 'she', 'spoke', 'fancy']i """
    def wordcount(word, wordlist): """ >>> wordcount('now', ['now', 'is', 'time', 'is', 'now', 'is', 'is']) ['now', 2] >>> wordcount('is', ['now', 'is', 'time', 'is', 'now', 'is', 'the', 'is']) ['is', 4] >>> wordcount('time', ['now', 'is', 'time', 'is', 'now', 'is', 'is']) ['time', 1] >>> wordcount('frog', ['now', 'is', 'time', 'is', 'now', 'is', 'is']) ['frog', 0] """
    def wordset(wordlist): """ >>> wordset(['now', 'is', 'time', 'is', 'now', 'is', 'is']) ['is', 'now', 'time'] >>> wordset(['I', 'a', 'a', 'is', 'a', 'is', 'I', 'am']) ['I', 'a', 'am', 'is'] >>> wordset(['or', 'a', 'am', 'is', 'are', 'be', 'but', 'am']) ['a', 'am', 'are', 'be', 'but', 'is', 'or'] """
    def longestword (wordset): """ >>> longestword(['a', 'apple', 'pear', 'grape']) 5 >>> longestword(['a', 'am', 'I', 'be']) 2 >>> longestword(['this', 'that', 'supercalifragilisticexpialidocious']) 34 """
    Modul si uložte pro použití jeho procedur v jiných programech.
  13. Upravte program countLetters_acc.py ze cvičení 6.20.2 tak aby jméno souboru a potřebné argumenty mohly být přijaty z příkazového řádku. Řešení si uložte do souboru ountLetters_cli.py.

pre up next title end end