Naimportujete-li modul (nebo vynutíte-li si jeho překlad jiným způsobem), bude v podadresáři __pycache__
(ve dvojkovém Python'u přímo ve stejném adresáři) vytvořena jeho předkompilovaná (spíše tzv. pseudozkompilovaná) verze s příponou pyc (vlevo zdrojový py-soubor, vpravo pyc-soubor):
Navzdory populárním představám ale tento soubor neobsahuje binární kód pro příslušnou platformu (Python není kompilovaný jazyk), ale „pouze“ jistým způsobem „zabalený“ bajtkód interpretru Python'u. Tudíž pyc-soubory jsou přenositelné mezi platformami a spustitelné, pokud cílová platforma má k dispozici stejný interpretr Python'u.
V dalším se podíváme souborům *.pyc na zoubek.
První čtyři bajty představují magické číslo souboru:
Pro Python se první dva bajty mění s verzí použité maršalizace a druhé dva jsou vtipně b'\r\n'
, tedy konce řádků, díky kterým je občas možné poznat, že soubory byly zpracovány nikoli jako binární ale textové.
Další čtveřice bajtů je časová značka souboru:
Interpretr díky ní pozná, zda se případný zdrojový soubor od poslední předkompilace nezměnil a zda ho tedy nemá znovu zpracovat.
Všechny zbývající bajty v souboru představují zamaršalovaný bajtkód interpretru:
Uvedený binární řetězec je zamaršalovaný výstup zdrojového bajtkódu pomocí modulu marshal, jehož prakticky jedinou úlohou je právě převod bajtkódu do a z pyc-souborů. Z těchto důvodů není jeho formát ani nijak oficiálně dokumentovaný, aby někdo neměl tendenci používat ho místo modulů pickle, respektive shelve.
Za pomoci modulu marshal se můžeme do tohoto kódu podívat. Příkaz marshal.loads(b'…')
na uvedený binární řetězec vyprodukuje na výstupu odpovídající bajtkódový objekt <code object <module> at 0x00C04DE0, file "pyc.py", line 1>
, jehož „vnitřnosti“ můžeme prozkoumat například metodou dis.dis()..
..a metodou dis.show_code():
python soubor.py
skutečně zavolá zdrojový soubor soubor.py a ne jeho případnou předkompilovanou verzi soubor.pyc.