Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Python中处理来自不同模块的相关对象之间的循环引用?_Python_Oop_Circular Dependency_Circular Reference_Strong Typing - Fatal编程技术网

如何在Python中处理来自不同模块的相关对象之间的循环引用?

如何在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():

为了提高我(初学者)的Python技能,我开始了一个pet项目,现在我遇到了循环导入问题

宠物项目是一个小口袋妖怪式的游戏,它的特点之一是一组动物带着武器。 关系链:团队->动物->武器(一个团队由几只动物组成,每只动物使用一件武器)。 为了避免过大的类,我决定将非常不同的动物和武器类分布在两个文件上,并使用import相互访问。 来自Java,我喜欢强类型变量、参数和参数

所以稍微简化一下,我的类武器.py和动物.py如下所示:

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