如何在Python中处理来自不同模块的相关对象之间的循环引用?
为了提高我(初学者)的Python技能,我开始了一个pet项目,现在我遇到了循环导入问题 宠物项目是一个小口袋妖怪式的游戏,它的特点之一是一组动物带着武器。 关系链:团队->动物->武器(一个团队由几只动物组成,每只动物使用一件武器)。 为了避免过大的类,我决定将非常不同的动物和武器类分布在两个文件上,并使用import相互访问。 来自Java,我喜欢强类型变量、参数和参数 所以稍微简化一下,我的类武器.py和动物.py如下所示:如何在Python中处理来自不同模块的相关对象之间的循环引用?,python,oop,circular-dependency,circular-reference,strong-typing,Python,Oop,Circular Dependency,Circular Reference,Strong Typing,为了提高我(初学者)的Python技能,我开始了一个pet项目,现在我遇到了循环导入问题 宠物项目是一个小口袋妖怪式的游戏,它的特点之一是一组动物带着武器。 关系链:团队->动物->武器(一个团队由几只动物组成,每只动物使用一件武器)。 为了避免过大的类,我决定将非常不同的动物和武器类分布在两个文件上,并使用import相互访问。 来自Java,我喜欢强类型变量、参数和参数 所以稍微简化一下,我的类武器.py和动物.py如下所示: import weapons class Animal():
import weapons
class Animal():
def __init__(self, name: str, level: int):
self.name: str = name
self.level: int = int
self.weapon: Weapon or None = None
def equip(self, weapon: Weapon) -> None:
self.weapon = weapon
所以,当我举例说明动物时,我不希望他们立即挥舞武器,也不希望武器立即拥有主人。但是,虽然在游戏中,动物->武器的关系相当直接,但我也希望有一种方法可以将武器指向拥有它的动物
上述代码导致循环导入问题。当面对一个不同但相关的问题时,我发现了一个有趣的\uuuuuuuuuuuuu未来
模块。添加来自未来导入注释的”解决了我的问题
但是,虽然我对自己的工作代码感到高兴,但我不知道是否可以以更优雅的方式解决这个问题。这是不是很臭的代码。是否有一个不同的解决方案仍然允许我使用打字。我很高兴有任何建议可以改进我的Python编码风格(以及我对循环导入的理解)以了解如何从组合、聚合和关联的角度构建代码
不过还是有几种可能性,你需要决定哪一种是最重要的(拥有者有武器,武器拥有者有武器)
假设每件武器一次只有一个拥有者,你想如何访问该武器
所有者。武器
->那么你就知道所有者了
或者您可以保留对所有者的引用作为武器的属性:
武器。拥有者
->可能在这里使用id
而不是对实际类的引用,这就是您当前的问题所在,对吗
武器存在时没有主人吗?然后看作文:
组合意味着子对象不能独立于父对象而存在的关系
组合示例:
房子(父母)和房间(孩子)。没有房子就没有房间
非合成的示例:
汽车和轮胎。没有汽车就没有轮胎
关于为什么要更好地避免循环引用的一般思路:
您也可以尝试考虑<强>依赖反转(注入原理)< /强>
(见或
).
我想你已经在你的第一个方法中尝试过了(将武器实例传递给动物)。这个想法很好,但也许你需要在中间再加一层
另一件事,来自Java,您习惯于getter和setter。就是
在Python中不太流行(但你可以做到)
你的做法:
class Weapon(ABC):
def set_wielder(wielder: Animal) -> None:
self.wielder = wielder
更具Pythonic的是,使用属性(“描述符”):
你可以阅读关于描述符的内容,
还有一点理论。要了解如何构造代码,可以从组合、聚合和关联的角度进行思考
不过还是有几种可能性,你需要决定哪一种是最重要的(拥有者有武器,武器拥有者有武器)
假设每件武器一次只有一个拥有者,你想如何访问该武器
所有者。武器
->那么你就知道所有者了
或者您可以保留对所有者的引用作为武器的属性:
武器。拥有者
->可能在这里使用id
而不是对实际类的引用,这就是您当前的问题所在,对吗
武器存在时没有主人吗?然后看作文:
组合意味着子对象不能独立于父对象而存在的关系
组合示例:
房子(父母)和房间(孩子)。没有房子就没有房间
非合成的示例:
汽车和轮胎。没有汽车就没有轮胎
关于为什么要更好地避免循环引用的一般思路:
您也可以尝试考虑<强>依赖反转(注入原理)< /强>
(见或
).
我想你已经在你的第一个方法中尝试过了(将武器实例传递给动物)。这个想法很好,但也许你需要在中间再加一层
另一件事,来自Java,您习惯于getter和setter。就是
在Python中不太流行(但你可以做到)
你的做法:
class Weapon(ABC):
def set_wielder(wielder: Animal) -> None:
self.wielder = wielder
更具Pythonic的是,使用属性(“描述符”):
你可以阅读关于描述符的内容,
还有一点理论。谢谢你的链接,我已经研究过了。由于武器确实可以在没有主人的情况下存在(可以交给其他动物,也可以简单地躺着),我更倾向于这种关系。(团队似乎更复杂,因为动物可以没有团队,但团队总是需要一组动物)。“这就是你目前的问题所在,对吗?”-没错。我希望能够以一种有效的方式(O(1))从武器到其所有者。我不知道如何通过id引用,因为这样我就需要引用武器中的动物词典->同一个问题,或者不是?词典现在还可以。可能有一本包含所有武器实例的字典。关键是一个唯一的武器id。并且有一个包含所有动物实例的字典,有一个唯一的动物id(或玩家id)。然后您可以将武器id分配给animal类的实例:animal.has_-wearm=51
。您还可以维护武器字典:wearm.used\u by=43
。那你就可以和我们在一起了
class Weapon(ABC):
def __init__(self):
# notice the underscore, it indicates "treat as non-public"
# but in Python there is no such thing
self._wielder = None
@property #this makes it work like a getter
def wielder(self) -> Animal: # not sure about the annotation syntax
return self._wielder
@wielder.setter
def wielder(wielder: Animal) -> None:
self._wielder = wielder