2009-06-25 14 views
6

Ho due classi che si riferiscono l'una all'altra, ma ovviamente il compilatore si lamenta. C'è un modo per aggirare questo?classi python che si riferiscono l'una all'altra

EDIT

In realtà il mio codice è un po 'diverso da quello che utilizza Hank Gay. Quindi python può sicuramente gestire alcuni tipi di riferimenti circolari, ma lancia un errore nella seguente situazione. Qui di seguito è quello che ho e ottengo un 'nome di Y non definito errore'

class X(models.Model): 

     creator = Registry() 
     creator.register(Y) 

class Y(models.Model): 
    a = models.ForeignKey(X) 
    b = models.CharField(max_length=200) 

Spero che questo aiuta a chiarire. Eventuali suggerimenti.

+4

Cos'è "ovvio"? Dove si lamenta? Mostra il codice? I riferimenti circolari non sono un problema per Python, il problema sta altrove. –

+0

Che aspetto ha il codice? –

+0

wow ... * rolleyes * – Robbie

risposta

15

In python, il codice in una classe viene eseguito quando la classe viene caricata.

Ora, che diavolo significa? ;-)

Si consideri il seguente codice:

class x: 
    print "hello" 
    def __init__(self): print "hello again" 

Quando si carica il modulo che contiene il codice, Python stamperà hello. Ogni volta che si crea un x, python stamperà hello again.

Si può pensare a def __init__(self): ... come equivalente a __init__ = lambda self: ..., tranne che non si applicano le restrizioni su lambda python. Cioè, def è un compito, che potrebbe spiegare perché viene eseguito il codice al di fuori dei metodi ma non all'interno dei metodi.

Quando il codice dice

class X(models.Model): 
    creator = Registry() 
    creator.register(Y) 

si fa riferimento a Y quando viene caricato il modulo, prima di Y ha un valore. Si può pensare di class X come un incarico (ma non riesco a ricordare la sintassi per la creazione di classi anonime fuori mano, forse è un'invocazione di type?)

Che cosa si può desiderare di fare è questo:

class X(models.Model): 
    pass 
class Y(models.Model): 
    foo = something_that_uses_(X) 
X.bar = something_which_uses(Y) 

Cioè, creare gli attributi della classe di X quale riferimento Y dopo la creazione Y. O viceversa: creare prima Y, quindi X, quindi gli attributi di Y che dipendono da X, se è più semplice.

speranza che questo aiuti :)

2

AGGIORNAMENTO: Ha cambiato la domanda dopo la mia risposta. La soluzione attualmente accettata è migliore alla luce della nuova domanda.

Cosa stai dicendo è il problema?

class A(object): 
    def __init__(self): 
     super(A, self).__init__() 


    def b(self): 
     return B() 


class B(object): 
    def __init__(self): 
     super(B, self).__init__() 


    def a(self): 
     return A() 

Compilano e funzionano correttamente.

+0

Alcune informazioni aggiuntive: Funziona, sì. Ma ha un prezzo: funziona solo se metti tutte le classi in un singolo file. Questo è abbastanza scomodo: potrebbe essere molto pitonico, non lo so, ma so che rompe con una buona pratica OOP di usare un proprio file per ogni classe (pubblica). –

2

Finché si lavora con un metodo è possibile accedere all'oggetto classe.

Pertanto, l'esempio precedente non presenta problemi se creator.register(Y) viene spostato all'interno di __init__. Tuttavia, non puoi avere riferimenti circolari a classi al di fuori dei metodi.

+1

Questa risposta non spiega nulla. Fornisce una "soluzione alternativa" senza comprendere o spiegare il vero problema, che è spiegato nelle risposte di Jonas e John Machin. –

2

L'errore è che l'esecuzione di creator.register(Y) viene tentata durante la (eseguibile) definizione della classe X, e in tale fase, classe Y non è definito. Capire questo: class e def sono dichiarazioni che vengono eseguite (in genere al momento dell'importazione); non sono "dichiarazioni".

Suggerimento: dicci cosa stai cercando di ottenere, forse come una nuova domanda.

-2

Il problema molto probabilmente non è Python. Penserei che sia un problema SQL. Le classi sono tramite un livello di astrazione convertito in una query SQL per creare una tabella. Stai provando a fare riferimento da una tabella a un'altra che al momento non esiste ancora.

In SQL si risolverebbe questo creando al tavolo prima senza i riferimenti e dopo che modificano loro di fare tali riferimenti,

Tuttavia non sono sicuro circa la mia risposta, in modo da prendere con un sacco di condimento, I sarebbe in effetti abbastanza sorpreso se il livello di astrazione del database di Django non trattasse bene i riferimenti incrociati.

Problemi correlati