python -m a podobné legrácky
V příspěvku o setup.py jsme používali volání python -m jméno.modulu. Jak jste asi pochopili, tenhle parametr zavolá modul. Tím bych mohl skončit.
Ale přece, pár drobností.
Moduly
Python hledá moduly na cestě. Cesta je někde definovaná. Zkuste:
Python 3.6.1 (default, Apr 23 2017, 15:03:36)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/local/lib/python36.zip', '/usr/local/lib/python3.6', '/usr/local/lib/python3.6/lib-dynload',
'/home/petr/.local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/site-packages']
Teď si to zkuste s jiným pythonem a pak ještě ve virtualenv. Všimněte si, že ty cesty jsou pokaždé jiné. Když nainstalujete balíček, nainstaluje se do site-packages. Když pak spustíte python -m jméno.modulu, hledá se jméno.modulu na cestě, a pokud se najde, tak se modul spustí.
Všimněte si toho '' na první pozici. To znamená, že moduly se hledají i v aktuálním adresáři. Takže jestli v něm máte nějaký modul, můžete ho zkusit spustit: python -m modul
Tohle využívá i mnoho standardních modulů. A protože máme dobrou konvenci, že pokud má modul samostatně fungovat, obsahuje na konci něco jako:
if __name__ == "__main__":
# udělej nějakou práci
main()
tak můžeme snadno najít moduly, které se dají přes python -m spustit:
cd /usr/local/lib/python3.6
grep __main__ *.py
Namátkou:
python -m calendar
python -m http.server
python -m pydoc -b
python -m smtplib
python -m unittest
python -m webbrowser -n http://petr.blahos.com/
python -m zipfile -c zipfile.zip src_directory
__main__.py
Vrátíme se k balíčku semprini, který jsme si vytvořili v díle o setup.py. Jak si možná vzpomínáte, spouštěli jsme tam python -m semprini.main. Lepší by bylo spouštět jen python -m semprini. Co to udělá:
$ python -m semprini
/home/petr/work/SEMP/bin/python: No module named semprini.__main__; 'semprini' is a package and cannot be directly executed
Tak tady to máte. Musíme si vytvořit modul semprini/__main__.py, a je to:
if "__main__" == __name__:
from semprini import main
print (main.main_func())
Proč if __name__ == "__main__"?
Python nerozlišuje mezi moduly, které slouží k naimportování a moduly, které slouží ke spuštění. Tak si představte, že máte modul, který definuje funkce na rekurzivní mazání souborů. Když ho naimportujete, prostě Vám nadefinuje nějaké ty mazací funkce. Když ho spustíte, smaže disk. Takové moduly každý píše naprosto běžně, že ano?
Kdybyste prostě na konci modulu napsali:
rm_rf("/")
tak by se při spuštění modulu zavolala funkce rm_rf z toho modulu, a pokusila se smazat disk. To při spuštění modulu chceme. Jenže totéž by se stalo i při importu. Proto upravíme:
if __name__ == "__main__":
rm_rf("/")
V běžícím programu v pythonu jsou vždy nějaké globální proměnné. Jedna z nich je __name__ - jméno aktuálního modulu. No a ten modul, který byl spuštěn v ní bude mít __main__. Importovaný modul v ní bude mít své jméno, např. semprini.main. Takže pokud modul spustíte, bude se jmenovat __main__, pokud jej importujete, nebude se jmenovat __main__.
Schválně, přečtěte si můj příspěvek o rozdílu mezi interpretovaným a kompilovaným jazykem.
Závěr
Když už jsme si dali tu práci a vytvořili balíček, který něco dělá, měli bychom dát možnost ho nějak smysluplně spustit. python -m ... je rozhodně krok, který někam vede, ale ještě to není úplně ono. Proto se někdy příště podíváme na skripty.
Komentáře byly zrušeny
V EU teď máme složitou situaci s Cookies. Na komentáře jsem používal jistou službu třetí strany. Ta však používá Cookies poměrně, ehm, benevolentně. Tak jsem se rozhodl komentáře zrušit. Pokud chcete, můžete mi napsat přímo