Python模块依赖性

时间:2020-03-06 14:58:55  来源:igfitidea点击:

好的,我有两个模块,每个模块包含一个类,问题是它们的类相互引用。

假设我有一个房间模块和一个包含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]

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)

解决方案

我们实际上需要在类定义时引用类吗? IE。

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

或者(更有可能),我们只需要在类的方法中使用CPerson(反之亦然)。例如:

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

如果是第二个,就没有问题,因为在调用方法而不是定义方法时,模块将被导入。我们唯一的问题是如何引用它。我们可能正在执行以下操作:

from CRoom import CPerson # or even import *

对于循环引用模块,我们无法执行此操作,因为一个模块导入另一个模块时,原始模块主体将无法完成执行,因此名称空间将不完整。而是使用合格的引用。 IE:

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

在这里,在方法真正被调用之前,python不需要在命名空间上查找属性,到那时两个模块都应该完成它们的初始化。

我们可以将第二个作为别名。

import CRoom

CPerson = CRoom.CPerson

无需导入CRoom

我们不要在person.py中使用CRoom,因此不要导入它。由于动态绑定,Python不需要"在编译时查看所有类定义"。

如果我们确实在person.py中使用了CRoom,则将从房间导入CRoom更改为导入房间,并使用模块限定格式room.CRoom。有关详细信息,请参见Effbot的通函导入。

旁注:" Self.NextId + = 1"行中可能存在错误。它增加实例的" NextId",而不是类的" NextId"。要增加类的计数器,请使用CRoom.NextId + = 1或者Self .__ class __。NextId + = 1

首先,用大写字母命名论点会造成混淆。由于Python没有形式化的静态类型检查,因此我们使用UpperCase来表示一个类,而使用lowerCase来表示一个参数。

其次,我们不必理会CRoom和CPerson。大写字母足以表明它是一类。不使用字母C。房间。

第三,我们通常不会将内容放在"每个文件一个类"的格式中。文件是Python模块,我们通常会导入包含所有类和函数的整个模块。

[我知道这些是习惯-我们今天不需要破坏它们,但是它们确实使人难以阅读。]

Python不使用像C ++这样的静态定义的类型。定义方法函数时,不会正式定义该函数的参数的数据类型。我们只列出了一些变量名。希望客户端类将提供正确类型的参数。

在运行时,当我们发出方法请求时,Python必须确保该对象具有该方法。笔记。 Python不会检查对象是否为正确的类型-没关系。它只会检查它是否具有正确的方法。

" room.Room"和" person.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。

在运行时评估Person(...)表达式之前,不必知道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

@ S.Lott
如果我未将任何内容导入到room模块中,则会收到未定义的错误(我将其导入到主模块中,如我们所示)

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()