Domanda

Ok ho due moduli, ognuno contenente una classe, il problema è che le loro classi si fanno riferimento l'un l'altro.

Diciamo ad esempio che avevo un modulo room e un modulo persona contenenti CRoom e CPerson.

La classe CRoom contiene informazioni sulla stanza e un elenco CPerson di ognuno nella stanza.

La classe CPerson tuttavia a volte ha bisogno di usare la classe CRoom per la stanza in cui si trova, ad esempio per trovare la porta o anche vedere chi altro è nella stanza.

Il problema è che i due moduli si importano a vicenda. Ho appena ricevuto un errore di importazione sul quale viene mai importato secondo :(

In c ++ ho potuto risolvere questo problema includendo solo le intestazioni e poiché in entrambi i casi le classi hanno solo puntatori all'altra classe, una dichiarazione in avanti sarebbe sufficiente per l'intestazione, ad esempio:

class CPerson;//forward declare
class CRoom
{
    std::set<CPerson*> People;
    ...

Esiste un modo per farlo in Python, oltre a mettere entrambe le classi nello stesso modulo o qualcosa del genere?

modifica: aggiunto esempio di pitone che mostra un problema usando le classi precedenti

errore:

  

Traceback (ultima chiamata più recente):
   File " C: \ Projects \ python \ test \ main.py " ;, riga 1, in
     da room import CRoom
   File " C: \ Projects \ python \ test \ room.py " ;, riga 1, in
     da persona importazione CPerson
   File " C: \ Projects \ python \ test \ person.py " ;, riga 1, in
     da room import CRoom
  ImportError: impossibile importare il nome CRoom
  room.py

from person import CPerson

class CRoom:
    def __init__(Self):
        Self.People = {}
        Self.NextId = 0

    def AddPerson(Self, FirstName, SecondName, Gender):
        Id = Self.NextId
        Self.NextId += 1#

        Person = CPerson(FirstName,SecondName,Gender,Id)
        Self.People[Id] = Person
        return Person

    def FindDoorAndLeave(Self, PersonId):
        del Self.People[PeopleId]

person.py

from room import CRoom

class CPerson:
    def __init__(Self, Room, FirstName, SecondName, Gender, Id):
        Self.Room = Room
        Self.FirstName = FirstName
        Self.SecondName = SecondName
        Self.Gender = Gender
        Self.Id = Id

    def Leave(Self):
        Self.Room.FindDoorAndLeave(Self.Id)
È stato utile?

Soluzione

Non è necessario importare CRoom

Non usi CRoom in person.py , quindi non importarlo. A causa dell'associazione dinamica, Python non ha bisogno di " vedere tutte le definizioni di classe al momento della compilazione " ;.

Se in realtà fai usi CRoom in person.py , quindi cambia da CRoom di importazione delle stanze in < codice> import room e utilizza il modulo qualificato room.CRoom . Vedi Importazioni circolari di Effbot per dettagli.

Sidenote: probabilmente hai un errore nella riga Self.NextId + = 1 . Incrementa NextId dell'istanza, non NextId della classe. Per incrementare il contatore della classe usa CRoom.NextId + = 1 o Self .__ class __. NextId + = 1 .

Altri suggerimenti

In realtà devi fare riferimento alle classi al momento della definizione della classe? vale a dire.

 class CRoom(object):
     person = CPerson("a person")

O (più probabilmente), devi solo usare CPerson nei metodi della tua classe (e viceversa). ad esempio:

class CRoom(object):
    def getPerson(self): return CPerson("someone")

Se il secondo non presenta alcun problema, poiché quando il metodo viene chiamato anziché definito, il modulo verrà importato. Il tuo unico problema è come fare riferimento ad esso. Probabilmente stai facendo qualcosa del tipo:

from CRoom import CPerson # or even import *

Con i moduli a riferimento circolare, non puoi farlo, poiché nel momento in cui un modulo ne importa un altro, il corpo dei moduli originali non avrà terminato l'esecuzione, quindi lo spazio dei nomi sarà incompleto. Utilizzare invece riferimenti qualificati. vale a dire:

#croom.py
import cperson
class CRoom(object):
    def getPerson(self): return cperson.CPerson("someone")

Qui, python non ha bisogno di cercare l'attributo nello spazio dei nomi fino a quando il metodo non viene effettivamente chiamato, quando entrambi i moduli dovrebbero aver completato la loro inizializzazione.

Innanzitutto, dare un nome ai tuoi argomenti con lettere maiuscole è fonte di confusione. Poiché Python non ha un controllo formale e statico del tipo, usiamo UpperCase per indicare una classe e lowerCase per indicare un argomento.

In secondo luogo, non ci preoccupiamo di CRoom e CPerson. Le maiuscole sono sufficienti per indicare che è una classe. La lettera C non è usata. Camera . persona .

Terzo, di solito non inseriamo le cose nel formato Una classe per file . Un file è un modulo Python e più spesso importiamo un intero modulo con tutte le classi e funzioni.

[Sono consapevole che quelle sono abitudini - non è necessario romperle oggi, ma rendono difficile la lettura.]

Python non usa tipi definiti staticamente come C ++. Quando si definisce una funzione del metodo, non si definisce formalmente il tipo di dati degli argomenti per quella funzione. Elencate semplicemente alcuni nomi di variabili. Eventualmente, la classe client fornirà argomenti del tipo corretto.

In fase di esecuzione, quando si effettua una richiesta di metodo, Python deve assicurarsi che l'oggetto abbia il metodo. NOTA. Python non controlla se l'oggetto è del tipo giusto, non importa. Controlla solo se ha il metodo giusto.

Il loop tra room.Room e person.Person è un problema. Non è necessario includerne uno quando si definisce l'altro.

È più sicuro importare l'intero modulo.

Ecco room.py

import person
class Room( object ):
    def __init__( self ):
        self.nextId= 0
        self.people= {}
    def addPerson(self, firstName, secondName, gender):
        id= self.NextId
        self.nextId += 1

        thePerson = person.Person(firstName,secondName,gender,id)
        self.people[id] = thePerson
        return thePerson 

Funziona bene fintanto che Person viene definito nello spazio dei nomi in cui è in esecuzione. La persona non deve essere conosciuta quando si definisce la classe.

La persona non deve essere conosciuta fino al runtime quando viene valutata l'espressione Persona (...).

Ecco person.py

import room
class Person( object ):
    def something( self, x, y ):
        aRoom= room.Room( )
        aRoom.addPerson( self.firstName, self.lastName, self.gender )

Il tuo main.py è simile a questo

import room
import person
r = room.Room( ... )
r.addPerson( "some", "name", "M" )
print r

Potresti semplicemente alias il secondo.

import CRoom

CPerson = CRoom.CPerson

@ S. Lott se non importare nulla nel modulo della stanza, invece, viene visualizzato un errore indefinito (l'ho importato nel modulo principale come mostrato)

  

Traceback (ultima chiamata più recente):
   File " C: \ Projects \ python \ test \ main.py " ;, riga 6, in
     Ben = Room.AddPerson ('Ben', 'Blacker', 'Male')
   File " C: \ Projects \ python \ test \ room.py " ;, riga 12, in AddPerson
     Person = CPerson (FirstName, SecondName, Gender, Id)
  NameError: il nome globale "CPerson" non è definito

Inoltre, la ragione per cui i diversi moduli è dove ho riscontrato il problema per iniziare con la classe container (ieg the room) sono già diverse centinaia di righe, quindi volevo che gli elementi in essa contenuti (ad esempio le persone) in un file separato.

EDIT: main.py

from room import CRoom
from person import CPerson

Room = CRoom()

Ben = Room.AddPerson('Ben', 'Blacker', 'Male')
Tom = Room.AddPerson('Tom', 'Smith',   'Male')

Ben.Leave()
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top