pre up next title end end

7. Soubory a moduly

  1. Soubory
  2. Datový typ bytes, bytearray, memoryview
    1. Převod řetězce na bytes
    2. Převod bytes na řetězce
    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. Modul pydoc
  9. Glosář
  10. 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 (bytearray) je neměnitelná (mě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 objektu typu bytes s použitím vhodného protokolu, jako je PNG, WAW, JSON nebo UTF-8, ASCii, cp1250 aj.
Prezentaci objektu ve formátu bytes, bytearray lze provést dvojím způsobem a to literálovou formou nebo s použitím příslušných funkcí či metod.

Literálový zápis objektu typu 'bytes' vytvoříme předznamenáním literálu řetězce písmenem b:

>>> asc = "Za horami, za lesy"    # lze kódovat v ASCii
>>> utf = "Až na severní pól"     # lze kódovat v UTF-8

Literálová forma pro bytes:
>>> lba = b'Za horami, za lesy'; lba
b'Za horami, za lesy'                  
>>> lbu = b'Až na severní pól'; lbu  
SyntaxError: bytes can only contain ASCii characters.
>>> lb = b'(1, 2, 237)'; lb
b'(1, 2, 237)'
>>> lbn = b'range(12)'; lbn; type(lbn)
b'range(12)' 
<class 'bytes'>

Literálová forma pro bytearray:
>>> bal = bytearray(b'Za horami, za lesy'); bal
bytearray(b'Za horami, za lesy')

Co k tomu dodat? Serializaci stringu literálovou formou lze provést jen tehdy když se formátovaný řetězec skládá pouze ze znaků, obsažených v kódování ASCii.

7.2.1   Převod řetězce na bytes

Převod na bytes lze provést pro všechny myslitelné znaky, ovšem patřičně ošetřené s použitím takzvané escape sekvence. Tu za nás při tvorbě objektu provede funkce bytes či bytearray, přijímající tři nepovinné parametry:

bytes([source[, encoding[, errors]]])
>>> bytes(asc, "utf-8")         
b'Za horami, za lesy'          
>>> bytes(utf, "utf-8")
b'A\xc5\xbe na severn\xc3\xad p\xc3\xb3l'  
                  # kombinace s 'escape sekvencí' 

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

Vedle funkce bytes(~) existuje také metoda encode(string, "coding"). Údaj o kódování lze vypustit, pokud souhlasíme s implicitně nastaveným utf-8. Pokud chceme použít jiné kódování, musíme jej uvést:

>>> "píšež".encode()           # kódování utf-8 je implicitní
b'p\xc3\xad\xc5\xa1e\xc5\xbe'             
>>> "píšež".encode('utf-16')
b'\xff\xfep\x00\xed\x00a\x01e\x00~\x01'   

7.2.2   Převod bytes na řetězce

Při deserializaci (decoding) objektu typu bytes na řetězec musíme vědět, jaké kódování bylo při serializaci použito. To není vždy spolehlivě zjistitelné. Jeden způsob je popsán zde.
Pro převod použijeme metodu bytes.decode("coding"):

>>> bczstr = bytes("píšež", "utf-8")    # objekt typu bytes     
>>> bczstr.decode("utf-8")              # kódování je povinné
'píšež' 

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

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

7.2.3   Bytearray

Jediná odlišnost typu bytearray od typu bytes spočívá v tom, že bytearray podporuje měnitelnost.

>>> bs = bytes('souznění', 'utf-8'); bs        # objekt typu bytes
b'souzn\xc4\x9bn\xc3\xad'                      # nejde změnit
>>> ba = bytearray('souznění', 'utf-8'); ba       
bytearray(b'souzn\xc4\x9bn\xc3\xad')           # objekt typu bytearray
>>> ba[0] = 76                          # změna znaku "s" ( ord("L") = 76)
>>> aba = bytearray("b", "utf-8") + ba; aba    # předsazení znaku "b" k ba  
bytearray(b'bLouzn\xc4\x9bn\xc3\xad')
>>> str(aba, "utf-8")                          # převod na řetězec
'blouznění'

Jak vidno, objekt typu bytearray je vlastně objekt typu bytes, dekorovaný slovem bytearray.

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.
Sekvence memoryview vytvořená z objektu bytes je neměnitelná, sekvence vytvořená z bytearray je měnitelná.

>>> obj = bytearray('Python','utf-8')    výchozí objekt
>>> mba = memoryview(obj)                objekt memoryview
>>> mba[0] = 74; obj                     změna výchozího objektu
bytearray(b'Jython')
>>> bajts = bytes(mu[0:4]); bajts        výsek (slice) typu bytes
b'Jyto'

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


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. 4.2, 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")
>>> 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. Používáte IDLE Pythonu.

Na objekt typu file (soubor) lze rovněž aplikovat metodu .split() (viz 6.4.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".


7.5 Vytváření a import modulů

Moduly jsou soubory s příponou ~.py, určené k opakovanému používání.

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

K vytvoření vlastního modulu nám stačí textový soubor s příponou .py. Název souboru nesmí být rozdělen pomlčkou, přípustné je podtržítko.

mojevoje.py

def mocnina(m, n=3):            # deklarace funkce           
    print(m**n)
	
print("Quo vadis?")             # přímo proveditelný kód

Tento skript můžeme realizovat přímo, voláním ze systémové konzoly (nebo přes F5 v IDLE):

F:\Codetest\HowTo\ch-07> python mojevoje.py
Quo vadis?             

Ve spuštěném souboru se ihned provede přímo proveditelný text. Bohužel, k této aktivitě dochází i při importu modulu.

Máme-li soubor, který obsahuje import dalšího souboru:

tvojevoje.py
import mojevoje

můžeme jej aktivovat z konzoly:

F:\Codetest\HowTo\ch-07> python tvojevoje.py
Quo vadis?        # výstup realizovaného textu z importu

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?").

Samostatně proveditelné příkazy jsou vlastně svého druhu problém. Eliminovat jej lze tím, že ze souborů, kde se tyto příkazy vyskytují, nebudeme nic neadresně importovat nebo tyto příkazy umístíme za karanténní bariéru:

mojevoje_alt.py

def mocnina(m, n=3):               # Jen deklarace funkce           
    print(m**n)
	
if __name__ == "__main__":         # idiom Pythonu
    print("Quo vadis?")            # Přímo proveditelný příkaz

Pokud tento soubor spustíme přímo (__name__ == "__main__"), potom se print("Quo vadis?") samo aktivuje. Pokud tento soubor importujeme do okna konzoly (__name__ !== "__main__"), potom se print("Quo vadis?") neaktivuje - je za "ochrannou bariérou".

7.5.2   Cesta k modulu

Importujeme-li 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. 12)
    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řen 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 array nutné vytvořit importovanou funkcí array().

Tuto funkci získáme importem z vestavěného modulu array nebo z instalovaného (pip install numpy) modulu Numpy.

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

>>> import numpy as np
>>> arrnp = np.array(["numbers", 3.6, 6.9, 12])
>>> print(arrnp)
['numbers' '3.6' '6.9' '12']
>>> type(arrnp)
<class 'numpy.ndarray'>

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. 9.4 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 Modul pydoc

Modul pydoc použijeme k prohledávání knihoven Pythonu, instalovaných na počítači. Na příkazový řádek napíšeme:

F:\HowTo> python -m pydoc -b
Server ready at http://localhost:52142/
Server commands: [b]rowser, [q]uit
server> 

Příkaz spustí libovolný nepoužitý port v počítači a otevře stránku ve webovém počítači. Seanci ukončíme zavřením stránky a zápisem q za poslední port v konzole.

Je to výčet všech knihoven Pythonu na vašem počítači. Klikem na jméno modulu otevřeme novou stránku s dokumentací o vybraném modulu. Například, klik na slovu keyword otevře následující stánku:

Dokumentace pro většinu modulů obsahuje tři barevně označené sektory:

Modul keyword obsahuje jedinou funkci iskeyword, která - jak její jméno naznačuje - je booleovskou funkcí, vracející True je-li zadaný řetězec klíčovým slovem:

>>> from keyword import *
>>> iskeyword('for')
True
>>> iskeyword('all')
False

Datový prvek kwlist obsahuje seznam všech současných klíčovych slov Pythonu:

>>> from keyword import *
>>> print(kwlist)
['and', 'as', 'assert', 'break', 'class', 'continue', 'def',
'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from',
'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not',
'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield',
'False', 'None', 'True']

Doporučujeme časté používání služby pydoc ke zkoumání rozsáhlých knihoven Pythonu. Mnoho pokladů čeká na své objevení!


7.9 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.
příkaz k importu (import statement)
Příkaz, který zpřístupní objekty ze zadaného souboru - např. mymod.py. Jsou tři formy tohoto příkazu:
import mymod
importuje celý modul mymod,
from mymod import *
importuje vše z modulu mymod,
from mymod import f1, v1
importuje z modulu mymod jen objekt f1 a v1.
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. Použítím
import string
# a posléze s použitím tečkové notace
string.method_name() 
místo
from string import *
zabráníme jmenné kolizi.
atribut (aclr-ttribute)
Proměnná či funkce, která je definovaná uvnitř modulu (nebo třídy či instance, jak uvidíme později). Atributy modulů jsou přistupné s použitím tečkového operátoru (.).
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()
'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.
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).
argv
Zkratka pro argument vector a proměnná modulu sys, do které se uloží argumenty příkazového řádku, použité později při běhu programu.

7.10 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