Frage

Ok Ich habe zwei Module, die jeweils eine Klasse enthält, das Problem ist, ihre Klassen aufeinander verweisen.

Hier kann zum Beispiel sagen, ich hatte ein Raummodul und eine Person Modul enthält Croom und CPerson.

Die Croom-Klasse enthält Informationen zum Thema Raum und eine CPerson Liste eines jeden im Raum.

Die Klasse CPerson aber manchmal braucht die Croom Klasse für das Zimmer seiner in verwenden, zum Beispiel die Tür zu finden oder zu sehen, wer sonst noch im Raum ist.

Das Problem ist mit den beiden Modulen sie importieren ich einen Importfehler nur bekommen, auf der jemals zweite importiert wird: (

In c ++ Ich könnte dieses Problem lösen, indem nur die Header einschließlich, und da in beiden Fällen nur die Klassen Zeiger auf die andere Klasse, eine Vorwärtsdeklaration würde für den Header zB genügen:

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

Gibt es trotzdem, dies in Python zu tun, außer beiden Klassen im gleichen Modul oder etwas wie das Platzieren?

edit: hinzugefügt Python Beispiel zeigt Problem obigen Klassen mit

Fehler:

  

Traceback (jüngste Aufforderung zuletzt):
   Die Datei "C: \ Projects \ Python \ test \ main.py" Linie 1 in
     von Raum Import Croom
   Die Datei "C: \ Projects \ Python \ test \ room.py" Linie 1 in
     von Person Import CPerson
   Die Datei "C: \ Projects \ Python \ test \ person.py" Linie 1 in
     von Raum Import Croom
  Import: kann nicht Namen importieren 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)
War es hilfreich?

Lösung

Keine Notwendigkeit Croom

importieren

Sie haben nicht CRoom in person.py verwenden, so dass es nicht importieren. Aufgrund der dynamischen Bindung braucht Python nicht auf „alle Klassendefinitionen bei der Kompilierung sehen“.

Wenn Sie eigentlich tun Verwendung CRoom in person.py, dann from room import CRoom ändern und Modul qualifizierte Form import room verwenden, um room.CRoom. Siehe Effbot Circular Import .

Nebenbei bemerkt: Sie wahrscheinlich einen Fehler in Self.NextId += 1 Linie haben. Es erhöht NextId der Instanz, nicht NextId der Klasse. Zu erhöhen Klasse Zähler Verwendung CRoom.NextId += 1 oder Self.__class__.NextId += 1.

Andere Tipps

Haben Sie eigentlich die Klassen in Klassendefinition Zeit verweisen müssen? dh.

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

oder (wahrscheinlicher), tun Sie müssen nur CPerson in den Methoden der Klasse (und umgekehrt) verwenden. zB:

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

Wenn das zweite, gibt es kein Problem - wie sie in der Zeit der Methode wird aufgerufen und nicht definiert ist, wird das Modul importiert. Ihr einziges Problem ist, wie man es verweisen. Wahrscheinlich Sie tun so etwas wie:

from CRoom import CPerson # or even import *

Mit zirkular Referenzierung Modulen können Sie dies nicht tun, wie an dem Punkt eines Modul importiert eine andere, der ursprüngliche Module Körper Ausführung nicht beendet haben, so wird der Namensraum unvollständig sein. Stattdessen qualifizierte Referenzen verwenden. dh:

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

Hier Python muss nicht auf den Namespace das Attribut zum Nachschlagen, bis die Methode tatsächlich aufgerufen wird, in welcher Zeit beide Module ihre Initialisierung abgeschlossen haben sollten.

Zuerst Ihre Argumente mit Großbuchstaben Namensgebung ist verwirrend. Da Python nicht über formale, statische Typprüfung, verwenden wir die UpperCase eine Klasse und lowerCase bedeuten ein Argument zu verstehen.

Zweitens haben wir nicht mit Croom und CPerson stören. Das obere Gehäuse ist ausreichend, um anzuzeigen, dass es eine Klasse ist. Der Buchstabe C wird nicht verwendet. Room. Person.

Drittens, wir haben in der Regel nicht die Dinge in eine Klasse pro Datei Format. Eine Datei ist ein Python-Modul, und wir importieren oft ein ganzes Modul mit allen Klassen und Funktionen.

[Ich bin mir bewusst, diese Gewohnheiten sind -. Sie müssen nicht sie heute brechen, aber sie machen es schwer zu lesen]

Python verwendet nicht statisch definierten Typen wie C ++. Wenn Sie eine Methode Funktion definieren, müssen Sie nicht formal den Datentyp der Argumente für diese Funktion definieren. Sie müssen lediglich einige Variablennamen auflisten. Wir hoffen, dass die Client-Klasse Argumente des richtigen Typs liefern.

Zur Laufzeit, wenn Sie eine Methode Antrag stellen, dann hat Python sicher sein das Objekt die Methode hat. HINWEIS. Python prüft nicht, ob das Objekt die richtige Art ist - das spielt keine Rolle. Es prüft nur, ob es die richtige Methode hat.

Die Schleife zwischen room.Room und person.Person ist ein Problem. Sie brauchen nicht ein zu schließen, wenn die andere definieren.

Es ist am sichersten, das gesamte Modul zu importieren.

Hier ist 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 

Adaequat solange Person schließlich im Namensraum definiert ist, wo diese ausgeführt werden. Person muss nicht bekannt sein, wenn Sie die Klasse zu definieren.

Person muss nicht erst zur Laufzeit bekannt sein, wenn dann Person (...) Ausdruck ausgewertet wird.

Hier ist person.py

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

Ihre main.py wie folgt aussieht

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

Sie konnte nur alias die zweite.

import CRoom

CPerson = CRoom.CPerson

@ S.Lott wenn ich mir einen undefinierten Fehler nicht bekommen, etwas in das Raummodul importieren, anstatt (I importierte sie in das Hauptmodul, wie Sie zeigte)

  

Traceback (jüngste Aufforderung zuletzt):
   Die Datei "C: \ Projects \ Python \ test \ main.py", Zeile 6, in
     Ben = Room.AddPerson ( 'Ben', 'Blacker', 'männlich')
   Die Datei "C: \ Projects \ Python \ test \ room.py", Zeile 12, in addPerson
     Person = CPerson (Vorname, SecondName, Geschlecht, Id)
  Nameerror: global name 'CPerson' ist nicht definiert

Auch der Grund, es diffrent Module ist, wo ich das Problem, mit der Container-Klasse (IEG den Raum) zu beginnen, sind bereits mehrere hundert Zeilen, also wollte ich die Elemente darin (zB Menschen) in einer separaten Datei.

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()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top