Python-Modul-Abhängigkeit
-
03-07-2019 - |
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)
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()