2008-10-01 256 views
16

好吧我有兩個模塊,每個模塊包含一個類,問題是它們的類相互引用。Python模塊依賴關係

比方說,我有一個房間模塊和一個包含CRoom和CPerson的人模塊。

CRoom類包含有關房間的信息和房間中每個人的CPerson列表。

但是,CPerson類有時需要使用CRoom類才能找到房間,例如找到房門,或者看看房間裏還有誰。

問題是與兩個模塊導入互相我只是得到它曾經是被導入第二:(

在C++中我可以只包括頭解決這一進口誤差,因爲在這兩種情況下,類只是指向其他類,向前宣言將足以爲標題,例如:

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

反正有沒有做到這一點在Python,不是將兩個類在同一個模塊或類似的東西在其他?

編輯:增加了Python示例使用上述類

顯示問題

錯誤:

Traceback (most recent call last):
File "C:\Projects\python\test\main.py", line 1, in
from room import CRoom
File "C:\Projects\python\test\room.py", line 1, in
from person import CPerson
File "C:\Projects\python\test\person.py", line 1, in
from room import CRoom
ImportError: cannot import name 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) 
+0

您可以發佈再現您的錯誤一個小的測試案例?我試圖創建兩個模塊,它們互相引用並沒有問題,所以我假設我有一些微妙的缺失點。 – 2008-10-01 15:50:15

+2

[offtop]請閱讀Python風格指南http://www.python.org/dev/peps/pep-0008/。特別是,從類名中刪除第一個'C',在你的例子中的所有其他名稱應該是小寫。要回答你的問題:只要`進口房間',並在人的方法使用`room.Room(...)`。 – jfs 2008-10-01 17:46:10

+0

提及你正在使用的是哪個版本的python可能是有用的。我不認爲這是一些版本的Python 3(我認爲3.5但不是3.4)的問題。 – 2017-02-08 15:13:50

回答

18

不需要輸入克魯姆

你不person.py使用CRoom,所以不要將其導入。由於動態綁定,Python不需要「在編譯時查看所有的類定義」。

如果你真的使用CRoomperson.py,然後更改from room import CRoomimport room和使用模塊合格的形式room.CRoom。詳情請參閱Effbot's Circular Imports

旁註:您可能在Self.NextId += 1行有錯誤。它增加了NextId的實例,而不是NextId的類。增加班級的計數器使用CRoom.NextId += 1Self.__class__.NextId += 1

7

你確實有必要在類定義時引用的類?即。

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

或(更可能),你只需要在你的類(反之亦然)的方法來使用CPerson。例如:

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

如果第二,沒有任何問題 - 如通過該方法得到稱爲,而不是定義,模塊將被導入的時間。你唯一的問題是如何參考它。可能你正在做的事情,如:

from CRoom import CPerson # or even import * 

以圓形參考模塊,你不能這樣做,因爲在點一個模塊導入另一個,原來模塊身體不會有執行完畢,所以命名空間將不完整。相反,請使用合格的參考。即:

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

這裏,蟒並不需要查找的命名空間中的屬性,直到方法實際上被調用,而此時這兩個模塊應該已經完成​​了他們的初始化。

1

你可以只是第二個別名。

import CRoom 

CPerson = CRoom.CPerson 
+0

這不起作用,就像在模塊中完成一樣,CRoom.CPerson可能還不存在。你可以做到的唯一方法就是將你的名字從其他模塊(比如import croom; croom.CPerson = CPerson)插入到其他模塊名稱空間中,這很冒險。最好使用完全限定名稱。 – Brian 2008-10-01 16:13:53

2

首先,用大寫字母命名你的參數是令人困惑的。由於Python沒有正式的靜態類型檢查,我們使用UpperCase來表示一個類,lowerCase來表示一個參數。

其次,我們不打擾CRoom和CPerson。大寫足以表示它是一個班級。字母C未被使用。 RoomPerson

三,我們通常不會把東西放在每類文件格式。一個文件是一個Python模塊,我們更經常導入包含所有類和函數的整個模塊。

[我知道這些都是習慣 - 你今天不需要打破他們,但他們並使其難以閱讀。]

Python不使用靜態定義的類型,如C++。當你定義一個方法函數時,你不會正式定義該函數參數的數據類型。您只需列出一些變量名稱。希望客戶端類將提供正確類型的參數。

在運行時,當您發出方法請求時,Python必須確保該對象具有該方法。注意。 Python不檢查對象是否是正確的類型 - 這並不重要。它只檢查是否有正確的方法。

room.Roomperson.Person之間的循環是一個問題。定義另一個時,不需要包含一個。

導入整個模塊是最安全的。

這裏的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 

工作正常,只要人在哪裏,這是執行命名空間最終確定。在定義課程時不需要知道人員。

在運行時不需要知道人員,然後評估Person(...)表達式。

這裏的person.py

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

main.py看起來像這樣

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

@美國洛特 如果我不輸入任何東西進了房間模塊我得到一個未定義的錯誤,而不是(我進口它就像你展示的主要模塊一樣)

Traceback (most recent call last):
File "C:\Projects\python\test\main.py", line 6, in
Ben = Room.AddPerson('Ben', 'Blacker', 'Male')
File "C:\Projects\python\test\room.py", line 12, in AddPerson
Person = CPerson(FirstName,SecondName,Gender,Id)
NameError: global name 'CPerson' is not defined

另外,有不同模塊的原因是我遇到的問題是從容器類(例如房間)開始已經有好幾百條線,所以我希望它中的項目(例如人)在一個單獨的文件中。

編輯: 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()