Python中的循环依赖


71

我有两个文件node.pypath.py,分别定义了两个类NodePath

直到今天,用于Path引用该Node对象的定义,因此我已经做了

from node.py import *

path.py文件中。

但是,到目前为止,我已经为Node引用该Path对象的对象创建了一个新方法。

尝试导入时遇到了问题path.py:我尝试了一下,当程序运行并调用了using的Path方法时Node,出现了一个Node未定义的异常。

我该怎么办?



3
您是否要每个文件一个类?这就是为什么很少能奏效的原因。
S.Lott

4
同意S.Lott。Python不是Java。每个文件不需要一个类。
丹尼尔·罗斯曼

43
几个人说过“每个文件不需要一个类”,并带有“不要尝试成为Java”的意思。好的-但这不是重点。类定义会变得非常大,并将它们捆绑到同一个文件中可能会导致非常大的不可读文件。在一个我正在处理的8个相互依赖的类的程序中,每个类的长度为几百行,将它们保存在同一文件中并没有任何好处,而将它们分开也没有多大好处。
sfkleach '16

1
同样作为参考,似乎在python 3.5(可能还有更高版本)上允许循环导入,但在3.4(可能是波纹管)上不允许。
查理·帕克

Answers:


114

导入Python模块是一篇很棒的文章,解释了Python中的循环导入。

解决此问题的最简单方法是将路径导入移动到节点模块的末尾。


好的,但事实是,我还有另外两个模块,tree.py并且block.py在该软件包中,它们需要node.py和所必需path.py。那我应该将它们全部放在一个文件中吗?我喜欢每节课有一个模块。
拉姆(Ram Rachum),2009年

2
你尝试过我的建议吗?可能会起作用。只需将导入移动到文件末尾即可。我建议您阅读这篇文章,以了解为什么会发生这种情况。
娜迪亚·阿拉姆利

12
顺便说一句,除了“喜欢”它之外,还有其他原因需要每个模块一个类吗?我几次看到这种偏好,是因为它类似于Java。
tzot

4
导入Python模块的链接已断开。
Ben2209 '12

26

另一种方法是仅在您需要的另一个函数中导入两个模块之一。当然,如果您只需要一个或少数几个功能,则效果最好:

# in node.py 
from path import Path
class Node 
    ...

# in path.py
class Path
  def method_needs_node(): 
    from node import Node
    n = Node()
    ...

3

我更喜欢通过在另一个依赖类的构造函数中声明一个依赖来打破循环依赖。在我看来,这可以使代码保持整洁,并可以轻松访问需要依赖项的所有方法。

因此,就我而言,我有一个相互依赖的CustomerService和UserService。我按如下方式打破循环依赖关系:

class UserService:

    def __init__(self):
        # Declared in constructor to avoid circular dependency
        from server.portal.services.admin.customer_service import CustomerService
        self.customer_service = CustomerService()

    def create_user(self, customer_id: int) -> User:
        # Now easy to access the dependency from any method
        customer = self.customer_service.get_by_id(customer_id)

2

您可能不需要进口Pathnode.py,以便PathNode利用彼此的。

# in __init__.py  (The order of imports should not matter.)
from .node import Node
from .path import Path

# in path.py 
from . import Node
class Path
  ...

  def return_something_pathy(self): 
    ...

# in node.py
class Node
  def __init__(self, path): 
    self.path = path
    ...

  def a_node_method():
    print(self.path.return_something_pathy())

为了明确说明Node正在使用Path,请添加类型提示。从PPE 563开始,从Python 3.7开始有可用的功能来支持类型注释中的前向引用。

# in node.py  (Now with type hinting.)
from __future__ import annotations

class Node
  def __init__(self, path: Path): 
    self.path = path
    ...

  def a_node_method():
    print(self.path.return_something_pathy())

我遇到了一个另外的解决方案,它可以使您摆脱Python的圆形导入孔,这是一篇很棒的博客文章,它教会了我这一点。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.