2015-11-13 12 views
6

Python è un linguaggio estremamente elegante. Bene, tranne ... eccetto le importazioni. Non riesco ancora a farlo funzionare come mi sembra naturale.Importazioni circolari inferno

Ho una classe MyObjectA che si trova nel file mypackage/myobjecta.py. Questo oggetto utilizza alcune funzioni di utilità che si trovano in mypackage/utils.py. Così nelle mie prime righe di myobjecta.py scrivo:

from mypackage.utils import util_func1, util_func2 

Ma alcune delle funzioni di utilità creare e restituire nuove istanze di MyObjectA. Quindi ho bisogno di scrivere in utils.py:

from mypackage.myobjecta import MyObjectA 

Beh, no non posso. Questa è un'importazione circolare e Python si rifiuterà di farlo.

Ci sono molte domande riguardo questo problema, ma nessuna sembra dare una risposta soddisfacente. Da quello che posso leggere in tutte le risposte:

  1. Riorganizzare i moduli, lo stai facendo male! Ma non so come meglio organizzare i miei moduli anche in un caso così semplice come ho presentato .
  2. provare solo import ... piuttosto che from ... import ... (personalmente io odio di scrivere e potenzialmente refactoring tutti i pieni qualificazioni nome, mi piace vedere esattamente di cosa sto importazione in modulo dal mondo esterno). Questo sarebbe d'aiuto? Non sono sicuro, ancora ci sono le importazioni circolari.
  3. Gli hacker come importano qualcosa nello scope interno di un corpo di una funzione solo una riga prima di utilizzare qualcosa da un altro modulo.

Sto ancora sperando che ci sia la soluzione numero 4) che sarebbe Pythonic nel senso di essere funzionale ed elegante, semplice e funzionante. O non c'è?

Nota: Io sono principalmente un programmatore C++, l'esempio sopra è così facilmente risolvibile includendo intestazioni corrispondenti che non posso credere che non sia possibile in Python.

+0

Da quello che dici, ho messo MyObjectA in utils.py perché alcune funzioni di utilità lo restituiscono, oppure inserisco le funzioni di utilità che restituiscono MyObjectA in myobjecta.py. Ma questa è la risposta 1) – DainDwarf

+0

Ho cercato le importazioni circolari di python e ho trovato diverse domande. Hai cercato? –

+0

@ Dain: Sì, certamente potrebbe farlo se le funzioni di utilità restituiscono solo MyObjectA. Ma cosa succede se possono anche restituire MyObjectB o MyObjectC ecc. –

risposta

0

Non c'è niente di hacker sull'importazione qualcosa nel corpo di una funzione, si tratta di un modello assolutamente valida:

def some_function(): 
    import logging 
    do_some_logging() 

solito ImportError s sono allevati solo a causa del modo in cui import() valuta le dichiarazioni di alto livello di tutto il file quando viene chiamato .

Nel caso in cui non hanno una logica dipendenza circolare ... , nulla è impossibile in pitone ...

C'è un modo intorno ad esso se si vuole positivamente vostre importazioni sopra:

Da David Beazleys ottimo intervento Modules and Packages: Live and Let Die! - PyCon 2015, 1:54:00, ecco un modo per trattare con le importazioni circolari in pitone:

try: 
    from images.serializers import SimplifiedImageSerializer 
except ImportError: 
    import sys 
    SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer'] 

Questo tenta di importare SimplifiedImageSerializer e se viene sollevato ImportError, poiché è già stato importato, verrà estratto dall'importcache.

PS: Devi leggere tutto questo post nella voce di David Beazley.

+1

Grazie, mi prenderò sicuramente il tempo di vedere quel discorso. Tuttavia, importare la funzione interna non è una soluzione così bella per qualificarlo come medaglia "molto pitone". Nasconde la dipendenza del modulo e lo nasconde nel codice. Perché allora non fare tutte le importazioni nel codice? Mi manca la logica in esso ... Ma sì, funziona la maggior parte del tempo. E usare try/catch solo per aggirare il concetto imperfetto (IMHO) dell'importazione in Python è ... decisamente un hack. –

0

Non importare mypackage.utils nel modulo principale, esiste già in mypackage.myobjecta. Dopo aver importato mypackage.myobjecta il codice da quel modulo è in esecuzione e non è necessario importare nulla nel modulo corrente, perché mypackage.myobjecta è già completo.

+0

Questa è una buona soluzione? Cosa succede se voglio usare le funzioni di utilità anche dal modulo 'main'. Quindi oscurerei questa dipendenza non importando 'utils' in' main'. Anche dal punto di vista di 'myobjecta.py', l'uso di' utils.py' è solo un dettaglio di implementazione. Introduce un potenziale caos di refactoring quando in seguito deciderò di modificare questo dettaglio di implementazione ... E come si interrompe l'importazione circolare tra 'myobjecta.py' e' utils.py'? Ma forse ho frainteso il punto. –

+0

puoi importarli in questo modo: 'da mypackage.myobjecta importa util_func1, util_func2' dato che sono già in quel pacchetto – Nhor

+0

Ma come ho detto, usare' utils' da 'myobjecta' è solo un dettaglio di implementazione. Che cosa succede se lo cambio più tardi. Quindi dovrei riscrivere tutto ciò che usa 'utils' e' myobjecta' allo stesso tempo. Personalmente ritengo che questo sia un trucco perché costringe l'utente a conoscere i dettagli di implementazione. Questo non è un buon progetto. E btw. non infrange l'importazione circolare tra 'myobjecta' e' utils'. O è? Non capisco –

0

Il modo in cui l'ho ottenuto nel mio (primo) progetto era semplicemente copiare e incollare l'intero modulo nel corpo dell'altro e utilizzare solo un'importazione. Duplicazione del codice, inelegante, ma mi ha permesso di andare avanti.

+0

Ho problemi simili. Non sono un'esportazione Ptyhon, ma suona orribile. Che cosa hai fatto nel tuo (secondo) progetto? – smerlung

+0

Non è mai arrivato di nuovo, per fortuna, ma il modo in cui lo farei ora è creare un altro modulo e importarne gli altri due. – postoronnim