Nauč se Python > Kurzy > Týmový začátečnický kurz Pythonu > Chyby a moduly > Cyklické importy

Cyklické importy

V domácích úkolech budeš rozdělovat piškvorkový projekt na několik modulů. Tento text si doporučuju číst až když narazíš na příslušný úkol, abys věděl/a o čem tu je řeč.

Po rozdělení bude projekt vypadat třeba nějak takhle: (Šipky mezi moduly znázorňují importování.)

┌──────────────────╮  ┌───────────────╮  ┌──────────────────╮ 
│      ai.py       │  │ piskvorky.py  │  │    hra.py        │
├──────────────────┤  ├───────────────┤  ├──────────────────┤
│                  │◀-│ import ai     │◀-│ import piskvorky │
├──────────────────┤  ├───────────────┤  ├──────────────────┤
│ def tah_pocitace │  │ def vyhodnot  │  │                  │
│                  │  │ def tah       │  │                  │
└──────────────────┘  │ def tah_hrace │  └──────────────────┘
                      │               │
                      └───────────────┘

Jenže funkce tah_pocitace většinou potřebuje volat funkci tah. Co s tím? Můžeš importovat aipiskvorky a zároveň piskvorkyai?

┌──────────────────╮  ┌───────────────╮
│      ai.py       │  │ piskvorky.py  │
├──────────────────┤  ├───────────────┤
│                  │◀-│ import ai     │
│ import piskvorky │-▶│               │
│                  │  │               │
│ def tah_pocitace │  │ def vyhodnot  │
│                  │  │ def tah       │
└──────────────────┘  │ def tah_hrace │
                      │               │
                      └───────────────┘

Můžeš se na to podívat z pohledu Pythonu, který příkazy v souborech vykonává. Když má importovat soubor piskvorky.py, začne ho zpracovávat řádek po řádku, když tu (docela brzo) narazí na příkaz import ai. Otevře tedy soubor ai.py a začne ho zpracovávat řádek po řádku. Brzy narazí na příkaz import piskvorky. Co teď?

Aby nenastala situace podobná nekonečné smyčce – jeden soubor by importoval druhý, druhý zase první, a tak stále dokola – udělá Python takový malý „podvod“: když zjistí, že soubor piskvorky.py už importuje, zpřístupní v modulu ai modul piskvorky tak, jak ho má: nekompletní, bez většiny funkcí co v něm mají být nadefinované. A až potom, co dokončí import ai.py, se vrátí k souboru piskvorky.py a pokračuje v provádění příkazů def které v něm jsou. Takový nekompletní modul může být občas užitečný, ale ve většině případů se chová skoro nepředvídatelně a tudíž nebezpečně.

Jinými slovy: když se dva moduly importují navzájem, nemusí to fungovat podle očekávání.

Téhle situaci se budeš chtít vyvarovat.

Jak na to? Máš dvě možnosti.

Organizace modulů podle závislostí

První možnost je importovat funkci tah v modulu ai a používat ji odtamtud. To je jednoduché, ale nerespektuje účel modulu ai, který má obsahovat jenom logiku vybírání tahu počítače, a ne pomocné funkce, které můžou být potřeba i jinde.

┌──────────────────╮  ┌───────────────╮
│      ai.py       │  │ piskvorky.py  │
├──────────────────┤  ├───────────────┤
│                  │◀-│ import ai     │
│                  │  │               │
│ def tah_pocitace │  │ def vyhodnot  │
│ def tah          │  │ def tah_hrace │
│                  │  │               │
└──────────────────┘  └───────────────┘

Pomocný modul

Druhá možnost je definovat nový, sdílený modul, který se použije jak v piskvorky.py tak v ai.py.

Takový modul se často se pojmenovává util.py (z angl. utility, pomůcka, nástroj).

              ┌──────────────────╮
              │ util.py          │
              ├──────────────────┤
              │ def tah          │
              └──────────────────┘
                      ▲  ▲
                      │  │
┌──────────────────╮  │  │  ┌───────────────╮
│      ai.py       │  │  │  │ piskvorky.py  │
├──────────────────┤  │  │  ├───────────────┤
│ import util      │──┘  └──│ import util   │
│                  │◀───────│ import ai     │
│                  │        │               │
│ def tah_pocitace │        │ def vyhodnot  │
│                  │        │ def tah_hrace │
│                  │        │               │
└──────────────────┘        └───────────────┘

Nevýhoda pomocného modulu je ta, že se z něj může stát neudržované „odkladiště“ všeho kódu, který byl jednou potřeba na dvou nebo více místech.

Pro kterou z možností se rozhodnout, záleží na situaci. Programování není vždycky jen exaktní věda!


Toto je stránka lekce z kurzu, který probíhá nebo proběhl naživo s instruktorem.