Python 模块依赖
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/158268/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python module dependency
提问by Fire Lancer
Ok I have two modules, each containing a class, the problem is their classes reference each other.
好的,我有两个模块,每个模块都包含一个类,问题是它们的类相互引用。
Lets say for example I had a room module and a person module containing CRoom and CPerson.
比如说,我有一个房间模块和一个包含 Croom 和 CPerson 的人员模块。
The CRoom class contains infomation about the room, and a CPerson list of every one in the room.
Croom 类包含有关房间的信息,以及房间中每个人的 CPerson 列表。
The CPerson class however sometimes needs to use the CRoom class for the room its in, for example to find the door, or too see who else is in the room.
然而,CPerson 类有时需要为它所在的房间使用 Croom 类,例如找到门,或者看看房间里还有谁。
The problem is with the two modules importing each other I just get an import error on which ever is being imported second :(
问题在于两个模块相互导入,我只是在导入第二个模块时遇到导入错误:(
In c++ I could solve this by only including the headers, and since in both cases the classes just have pointers to the other class, a forward declaration would suffice for the header eg:
在 C++ 中,我可以通过只包含头文件来解决这个问题,因为在这两种情况下,类都只有指向另一个类的指针,所以前向声明对于头文件就足够了,例如:
class CPerson;//forward declare
class CRoom
{
std::set<CPerson*> People;
...
Is there anyway to do this in python, other than placing both classes in the same module or something like that?
除了将两个类放在同一个模块或类似的东西中之外,还有什么办法可以在 python 中做到这一点吗?
edit: added python example showing problem using above classes
编辑:添加了使用上述类显示问题的 python 示例
error:
错误:
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
回溯(最近一次调用):
文件“C:\Projects\python\test\main.py”,第 1 行,
从房间导入 Croom
文件“C:\Projects\python\test\room.py”,第 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
人.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)
回答by Constantin
No need to import CRoom
无需导入 Croom
You don't use CRoom
in person.py
, so don't import it. Due to dynamic binding, Python doesn't need to "see all class definitions at compile time".
你不使用CRoom
in person.py
,所以不要导入它。由于动态绑定,Python 不需要“在编译时查看所有类定义”。
If you actually douse CRoom
in person.py
, then change from room import CRoom
to import room
and use module-qualified form room.CRoom
. See Effbot's Circular Importsfor details.
如果你确实做使用CRoom
中person.py
,然后换from room import CRoom
到import room
和使用模块合格形式room.CRoom
。有关详细信息,请参阅Effbot 的循环导入。
Sidenote:you probably have an error in Self.NextId += 1
line. It increments NextId
of instance, not NextId
of class. To increment class's counter use CRoom.NextId += 1
or Self.__class__.NextId += 1
.
旁注:你可能有一个错误Self.NextId += 1
。它增加NextId
了实例,而不是NextId
类。要增加类的计数器,请使用CRoom.NextId += 1
或Self.__class__.NextId += 1
。
回答by Brian
Do you actually need to reference the classes at class definition time? ie.
你真的需要在类定义时引用类吗?IE。
class CRoom(object):
person = CPerson("a person")
Or (more likely), do you just need to use CPerson in the methods of your class (and vice versa). eg:
或者(更有可能),您是否只需要在类的方法中使用 CPerson(反之亦然)。例如:
class CRoom(object):
def getPerson(self): return CPerson("someone")
If the second, there's no problem - as by the time the method gets calledrather than defined, the module will be imported. Your sole problem is how to refer to it. Likely you're doing something like:
如果是第二个,则没有问题 - 因为当方法被调用而不是定义时,模块将被导入。您唯一的问题是如何引用它。可能你正在做这样的事情:
from CRoom import CPerson # or even import *
With circularly referencing modules, you can't do this, as at the point one module imports another, the original modules body won't have finished executing, so the namespace will be incomplete. Instead, use qualified references. ie:
对于循环引用模块,您不能这样做,因为在一个模块导入另一个模块时,原始模块主体不会执行完毕,因此命名空间将不完整。相反,使用限定的引用。IE:
#croom.py
import cperson
class CRoom(object):
def getPerson(self): return cperson.CPerson("someone")
Here, python doesn't need to lookup the attribute on the namespace until the method actually gets called, by which time both modules should have completed their initialisation.
在这里,python 不需要在名称空间上查找属性,直到方法实际被调用,此时两个模块都应该完成初始化。
回答by S.Lott
First, naming your arguments with uppercase letters is confusing. Since Python does not have formal, static type checking, we use the UpperCase
to mean a class and lowerCase
to mean an argument.
首先,用大写字母命名你的参数是令人困惑的。由于 Python 没有正式的静态类型检查,我们使用 theUpperCase
来表示一个类和lowerCase
一个参数。
Second, we don't bother with CRoom and CPerson. Upper case is sufficient to indicate it's a class. The letter C isn't used. Room
. Person
.
其次,我们不打扰 Croom 和 CPerson。大写足以表明它是一个类。不使用字母 C。 Room
. Person
.
Third, we don't usually put things in One Class Per Fileformat. A file is a Python module, and we more often import an entire module with all the classes and functions.
第三,我们通常不会把东西放在一个类每个文件的格式中。文件是一个 Python 模块,我们更经常地导入包含所有类和函数的整个模块。
[I'm aware those are habits -- you don't need to break them today, but they do make it hard to read.]
[我知道这些都是习惯——你今天不需要打破它们,但它们确实让阅读变得困难。]
Python doesn't use statically defined types like C++. When you define a method function, you don't formally define the data type of the arguments to that function. You merely list some variable names. Hopefully, the client class will provide arguments of the correct type.
Python 不使用静态定义的类型,如 C++。当您定义方法函数时,您并没有正式定义该函数的参数的数据类型。您只需列出一些变量名称。希望客户端类将提供正确类型的参数。
At run time, when you make a method request, then Python has to be sure the object has the method. NOTE. Python doesn't check to see if the object is the right type -- that doesn't matter. It only checks to see if it has the right method.
在运行时,当您发出方法请求时,Python 必须确保对象具有该方法。笔记。Python 不会检查对象是否是正确的类型——这无关紧要。它只检查它是否有正确的方法。
The loop between room.Room
and person.Person
is a problem. You don't need to include one when defining the other.
room.Room
和之间的循环person.Person
是一个问题。在定义另一个时,您不需要包含一个。
It's safest to import the entire module.
导入整个模块是最安全的。
Here's room.py
这是 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
Works fine as long as Person is eventually defined in the namespace where this is executing. Person does not have to be known when you define the class.
只要 Person 最终在执行它的命名空间中定义,就可以正常工作。定义类时不必知道人员。
Person does not have to be known until runtime when then Person(...) expression is evaluated.
直到运行时才知道 Person ,然后计算 Person(...) 表达式。
Here's person.py
这是 person.py
import room
class Person( object ):
def something( self, x, y ):
aRoom= room.Room( )
aRoom.addPerson( self.firstName, self.lastName, self.gender )
Your main.py
looks like this
你的main.py
样子
import room
import person
r = room.Room( ... )
r.addPerson( "some", "name", "M" )
print r
回答by S.Lott
You could just alias the second one.
你可以只是别名第二个。
import CRoom
CPerson = CRoom.CPerson
回答by Fire Lancer
@S.Lott if i don't import anything into the room module I get an undefined error instead (I imported it into the main module like you showed)
@S.Lott 如果我没有将任何东西导入到房间模块中,我会得到一个未定义的错误(我像你展示的那样将它导入到主模块中)
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
回溯(最近一次调用):
文件“C:\Projects\python\test\main.py”,第 6 行,在
Ben = Room.AddPerson('Ben', 'Blacker', 'Male')
文件“C: \Projects\python\test\room.py",第 12 行,在 AddPerson
Person = CPerson(FirstName,SecondName,Gender,Id)
NameError: global name 'CPerson' is not defined
Also, the reason there diffrent modules is where I encountered the problem to start with the container class (ieg the room) is already several hundred lines, so I wanted the items in it (eg the people) in a seperate file.
此外,存在不同模块的原因是我遇到问题的地方,从容器类(例如房间)开始已经有几百行了,所以我希望其中的项目(例如人)在一个单独的文件中。
EDIT: main.py
编辑: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()