Moduly
Co jsou to moduly
Pokud budete psát nějaký větší program, jistě nebudete chtít
„naplácat“ všechny funkce a třídy do jednoho velkého souboru.
Moduly jsou obdobou knihoven v jazyce C (include) nebo Pascal
(USES). Jsou to textové soubory s příponou .py
(nebo zkompilované soubory s příponou .pyc
). Mohou obsahovat
funkce, třídy, objekty atd. Existuje mnoho standardních modulů, další
si můžete vytvořit.
Volání funkcí a modulů
Moduly se do programu načtou příkazem
import jmeno_modulu
.
Jméno modulu se za příkazem import
uvádí bez přípony.
V příkladu se načítá standardní modul sys
a používá jeho funkce exit()
. Tato funkce ukončí program
kdekoliv ji zavoláte.
>>> sys.exit()
petr: $
Po zavolání příkazu sys.exit()
se program ukončí. V případě,
že pracujete v interaktivním módu, ukončí se
interpret Python a vrátíte se do příkazové řádky.
Importovaný modul můžete přejmenovat pomocí slovíčka as
:
>>> s.exit()
petr: $
Chcete-li načíst více modulů najednou, napište je všechny za
příkazem import
oddělené čárkou.
Nechcete-li volat funkce
složitě přes jmeno_modulu.jmeno_fce
, můžete
načíst funkci přímo:
>>> exit()
petr: $
Chcete-li takto načíst více funkcí z modulu, napište je za
import
a oddělte je čárkou. Chcete-li takto načíst všechny
funkce z modulu, napište místo jmena_funkce hvězdičku.
Použití hvězdičky na vestavěné moduly se silně nedoporučuje, protože při importování několika modulů tímto způsobem by se mohly přepsat globální proměnné z vašeho jmenného prostoru, které by měly stejné jméno jako v modulech. Nebo by si mohly moduly navzájem přepsat jména funkcí, tříd atp. Konec konců, moduly jsou tu právě proto, abyste mohli používat jména bez obav, že je použil už někdo jiný. Vyčleněním jmen do modulů se stávají jména unikátní.
Na dalším příkladě ukáži práci s proměnnou ps1 a
ps2 z modulu sys
. Tyto proměnné určují vzhled promptu
v interaktivním režimu. Spusťte Python v interaktivním režimu:
Python 2.1.3 (#1, Apr 20 2002, 10:14:34)
[GCC 2.95.4 20011002 (Debian prerelease)] on linux2
Type "copyright", "credits" or "license" for more information.
>>> from sys import ps1, ps2, exit # from sys import *
>>> ps1
'>>> '
>>> ps2
'... '
>>> ps1=":-) "
>>> import sys
>>> sys.ps1=":-) "
:-) exit()
petr: $
Funkce exit()
pracovala tak jak má. Proč ale přiřazení
ps1=":-) "
nefungovalo a přiřazení sys.ps1=":-) "
ano? Odpověď je jednoduchá. Python se při vypisování promptu obrací
na standardní modul sys
. Příkazem from sys import ps1, ps2
se
zkopírovaly proměnné ps1 a ps2 do našeho
jmenného prostoru a změna „našich proměnných“ neměla na modul
sys
pražádný vliv. Druhé
přiřazení již s modulem sys
pracuje, a tak se dostavil kýžený
výsledek. Život (Python?) je holt pes a na takové věci je třeba dávat pozor.
Vytváření vlastních modulů
Vytvořte textový soubor pokus.py s tímto obsahem:
#
# modul pokus.py
#
x = 'Hello World'
def pozdrav(pocet):
try:
for i in range(pocet):
print(x)
except TypeError:
print('Argumentem funkce pozdrav musi byt cele cislo')
return
except:
print('Neocekavana chyba')
raise
.py
je pro moduly povinná.
Tím jste vytvořili modul pokus a můžete jej používat:
>>> pokus.pozdrav(2)
Hello World
Hello World
>>> pokus.x = 'Ahoj'
>>> pokus.pozdrav(1)
Ahoj
>>> sys.exit()
Porovnejte to s následujícím příkladem. Všiměte si, že každý modul má
svůj vlastní jmenný prostor. Ke globálním proměnným v modulu přistupujete
přes tečkovou notaci. Pomocí konstrukce from ... import ...
je zkopírujete do svého jmenného prostoru, ale funkce stále pracují s proměnnými
z jmenného prostoru modulu. To je super, protože se tak nemusíte bát,
že vám imporotvané funkce budou dělat bordel ve vašem jmenném prostoru.
>>> print(x)
Hello World
>>> pozdrav(1)
Hello World
>>> x = 'Ahoj'
>>> pozdrav(1)
Hello World
>>> pokus.x = 'Ahoj'
>>> pozdrav(1)
Ahoj
V aktuálním adresáři vznikl soubor pokus.pyc.
To je zkompilovaný modul pokus.py. Python jej vytváří
a aktualizuje automaticky, aby se tím urychlilo načítání modulů. Při druhém
načtení modulu pokus se načte pokus.pyc, což je výrazně
rychlejší.
V případě, že soubor pokus.py upravíte ,Python si toho
všimne sám od sebe a modul znovu skompiluje.
import
načte soubor během běhu interpretu jen jednou.
Druhé zavolání importu už soubor znovu nečte, takže, pokud soubor změníte,
import
si toho nevšimne. Nezbývá, než po úpravě modulu
interpret ukončit a znovu spustit …
Spouštění modulů jako skriptů
Všechno, co do modulu napíšete, se během importu vykonává. V modulu může být nějaký kód, kterým chcete modul inicializovat, ale většinou v něm budete mít jen definice funkcí a tříd.
Pokud spouštíte nějaký skript Pythonu, nastaví se speciální globální proměnná __name__ na hodnotu "__main__", což se dá s výhodou použít pro rozlišení, zda je soubor spouštěn jako skript, nebo je importován.
Do modulů se takto často umísťují testy, které ověřují jeho funkčnost.
#
# modul pokus.py
#
x = 'Hello World'
def pozdrav(pocet):
try:
for i in range(pocet):
print(x)
except TypeError:
print('Argumentem funkce pozdrav musi byt cele cislo')
raise
# vykonej nejakou inicializaci
print(x)
# pokud je modul spusten jako skript, vykonej testy
if __name__ == "__main__":
err = False
try:
pozdrav('1')
except TypeError:
err = True
finally:
if not err:
print('Error: Byla ocekavana vyjimka TypeError')
else:
print('Test prosel OK')
Hello World
Argumentem funkce pozdrav musi byt cele cislo
Test prosel OK
Standardní moduly Pythonu
Python obsahuje mnoho standardních modulů, které byste měli znát. Některé popíši v části Standardní knihovna. Dva moduly, které stojí za zvláštní pozornost, popíši tady.
Modul sys
Modul sys
obsahuje užitečné proměnné a metody.
Některé jsem už ukazoval (ps1, ps2, exit()).
Další důležitou proměnnou je sys.path
.
To je seznam adresářů, kde se hledají moduly.
>>> print (sys.path)
['', 'C:\\Program Files\\python3.3\\Lib\\idlelib',
'C:\\Windows\\system32\\python33.zip', 'C:\\Program Files\\python3.3\\DLLs',
'C:\\Program Files\\python3.3\\lib', 'C:\\Program Files\\python3.3',
'C:\\Program Files\\python3.3\\lib\\site-packages']
Další zajímavé proměnné jsou sys.stdin
(standardní vstup),
sys.stdout
(standardí výstup) a sys.stderr
(standardní chybový výstup). Chyby byste měli vypisovat na standardní
chybový výstup. Pomocí funkce print
toho docílíte takto:
print >> sys.stderr, 'spam' # Python 2.7
V sys.argv
najdete argumenty příkazové řádky.
Modul copy
Při povídání o jmenném prostoru
byla zmíněna problematika vytváření objektů v Pythonu. Přiřazením
a = b
nevznikne nový objekt, ale jen se v prostou jmen
přiřadí stávajícímu objektu nové jméno. Nový objekt může vzniknout
těmito způsoby:
1. vytvořením nového objektu
>>> a is b
True
>>> b = 3
>>> a is b
False
>>> a = [5]; b = a
>>> b += [4]
>>> a is b
True
>>> b = b[:]
>>> a is b
False
>>> seznam1 = [a, b]
>>> seznam2 = seznam1[:]
>>> seznam1 is seznam2
False
>>> seznam1[0] is seznam2[0]
True
Všimněte si, že je potřeba skutečně vytvořit nový objekt (například
použitím slice viz. b = b[:]
) a nestačí jen změnit hodnotu objektu
(viz. b += [4]
). Taky si všiměte, že vytvořením kopie seznamu se nevytvoří
kopie jeho obsahu, takže seznam2[0]
stále ukazuje na ten samý objekt, jako
seznam1[0]
.
2. použitím funkcí modulu copy
Použití slice v předházejícím příkladu je sice efektivní, ale když
je potřeba vytvořit kopii např. třídy,
pak pomůže jen modul copy
.
Obsahuje dvě funkce:
copy(arg) |
Vytvoří kopii objektu arg, objekty v arg se budou odkazovat na tytéž objekty, jako v původním objektu. Jde o tzv. mělkou kopii. |
---|---|
deepcopy(arg) |
Vytvoří kopii objektu arg a z objektů v arg budou vytvořeny také kopie (rekurzivně se vytvářejí kopie všech objektů v nalezených objektech …). Jde o tzv. hlubokou (deep) kopii. |
Funkce těchto funkcí ukazuje následující příklad.
cislo1 = [1] # třídní proměnná
def __init__(self):
self.cislo2 = [1] # proměnná objektu
>>> x = trida()
>>> y = x
>>> x is y
True
>>> x.cislo2 is y.cislo2
True
>>> import copy
>>> y = copy.copy(x)
>>> x is y
False
>>> x.cislo2 is y.cislo2
True
>>> y = copy.deepcopy(x)
>>> x is y
False
>>> x.cislo2 is y.cislo2 # atributy objektu jsou zkopírovány
False
>>> x.cislo1 is y.cislo1 # třídní proměnná zůstává stejná
True
Proč je x.cislo1 stejný objekt jako y.cislo1? Protože je součástí objektu, který deklaruje třídu trida, nikoliv objektu x (ani y), které jsou instancemi této třídy.
trida
.