2008-10-01 169 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()