2012-12-13 13 views
7

Un modo è usare import x, senza usare la parola chiave "from". Quindi ti riferisci alle cose con il loro spazio dei nomi ovunque.Evitare importazioni circolari (cicliche) in Python?

C'è qualche altro modo? come fare qualcosa come in C++ ifnotdef __b__ def __b__ tipo di cosa?

+2

Non avere dipendenze circolari, creare z combinando le dipendenze di x in ye dipendenze di y in x – Esailija

+0

Questo post è un duplicato: http://stackoverflow.com/questions/744373/circular-or-cyclic -imports-in-python – alinsoar

+1

@alinsoar Non è un duplicato esatto - quella domanda chiedeva cosa succede quando si hanno importazioni circolari; e questa domanda richiede tecniche per evitarli. –

risposta

10

Unisci qualsiasi coppia di moduli che dipendono l'uno dall'altro in un singolo modulo. Quindi introdurre moduli aggiuntivi per riavere i vecchi nomi.

esempio

# a.py 
from b import B 

class A: whatever 

# b.py 
from a import A 

class B: whatever 

diventa

# common.py 
class A: whatever 
class B: whatever 

# a.py 
from common import A 

# b.py 
from common import B 
+0

Penso che intendevi fare "dall'importazione comune A" e "dall'importazione comune B"? – jdi

+0

@jdi: si. Grazie, risolto. –

+21

Questo impone di iniziare a dichiarare tutto in 'common.py' piuttosto che' a.py' e 'b.py'. Non una buona soluzione IMHO. – Nick

5

importazioni circolari sono un "codice odore," e spesso (ma non sempre) indicano che alcuni refactoring sarebbe opportuno. Ad esempio, se A.x utilizza B.y e B.y utilizza A.z, quindi potresti prendere in considerazione lo spostamento di A.z nel proprio modulo.

Se pensi di aver bisogno importazioni circolari, poi mi raccomando generalmente importando il modulo e facendo riferimento agli oggetti con nomi completi (cioè, import A e utilizzare A.x piuttosto che from A import x).

+1

Cosa succede se si sta facendo un controllo di tipo esplicito? Sto cercando di farlo in questo momento in modo da poter fornire un messaggio di errore molto dettagliato, piuttosto che un traceback offuscato che i miei clienti non capiscono. – Nick

0

Se stai cercando di fare from A import *, la risposta è molto semplice: non farlo. Solitamente, è supposto fare import A e fare riferimento ai nomi qualificati.

Per gli script rapidi & e le sessioni interattive, è una cosa assolutamente ragionevole da fare, ma in questi casi non si imbatteranno in importazioni circolari.

Ci sono alcuni casi in cui ha senso fare import * in codice reale. Ad esempio, se si desidera nascondere una struttura di modulo complessa o generata dinamicamente o che cambia frequentemente tra una versione e l'altra oppure se si esegue il wrapping del pacchetto di qualcun altro troppo nidificato, import * può avere senso da un "wrapper" modulo "o un modulo pacchetto di livello superiore. Ma in quel caso, nulla che importi ti importerebbe.

In effetti, ho difficoltà a immaginare qualsiasi caso in cui sia garantito lo standard import * e le dipendenze circolari siano addirittura possibili.

Se stai facendo from A import foo, ci sono dei modi per aggirare questo problema (ad es., import A quindi foo = A.foo). Ma probabilmente non vuoi farlo. Ancora una volta, considera se hai davvero bisogno di portare lo foo nel tuo spazio dei nomi: i nomi qualificati sono una caratteristica, non un problema da risolvere.

Se stai facendo il from A import foo solo per convenienza nella realizzazione le funzioni, perché A è in realtà long_package_name.really_long_module_name e il codice è illeggibile a causa di tutte quelle chiamate a long_package_name.really_long_module_name.long_class_name.class_method_that_puts_me_over_80_characters, ricordate che potete sempre import long_package_name.really_long_module_name as P e quindi utilizzare P per voi qualificati chiamate.

(Inoltre, ricorda che con qualsiasi from fatto per convenienza implementazione, probabilmente si vuole fare in modo di specificare un __all__ per assicurarsi che i nomi importati non sembrano far parte dello spazio dei nomi, se qualcuno fa un import * su di voi da una sessione interattiva.)

Inoltre, come altri hanno sottolineato, la maggior parte, ma non tutti, i casi di dipendenze circolari, sono un sintomo di una cattiva progettazione e il refactoring dei moduli in modo ragionevole lo risolverà. E nei rari casi in cui hai davvero bisogno di portare i nomi nel tuo spazio dei nomi, e un insieme circolare di moduli è in realtà il miglior design, alcuni refactoring artificiale possono ancora essere una scelta migliore di foo = A.foo.