Python中的循环依赖

Ram*_*hum 61 python circular-dependency

我有两个文件,node.py并且path.py,它定义了两个类,NodePath分别.

到目前为止,Path引用该Node对象的定义,因此我已经完成了

from node.py import *
Run Code Online (Sandbox Code Playgroud)

path.py文件中.

但是,截至今天,我创建了一个Node引用该Path对象的新方法.

我在尝试导入时遇到了问题path.py:我尝试过,当程序运行并调用使用的Path方法时Node,一个异常上升,Node因为没有定义.

我该怎么办?

Nad*_*mli 104

导入Python模块是一篇很棒的文章,用于解释Python中的循环导入.

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

  • 顺便说一句,除了你"喜欢"它之外还有一些理由你想要每个模块一个课吗?我几次看到这种偏好,这是因为它像Java一样. (10认同)
  • 导入 Python 模块的链接已损坏。 (4认同)
  • 你试过我的建议了吗?它可能会奏效.只需将导入移动到文件末尾即可.我建议你阅读这篇文章,了解为什么会这样. (2认同)

mir*_*ngu 22

另一种方法是仅在您需要的功能中导入两个模块中的一个.当然,如果您只需要一个或少量功能,这种方法效果最好:

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

# in path.py
class Path
  def method_needs_node(): 
    from node import Node
    n = Node()
    ...
Run Code Online (Sandbox Code Playgroud)

  • 它会起作用,但我没有看到这种通过可读性代码审查 (3认同)

Bry*_*ach 6

您可能不需要为了互相使用而Path导入。node.pyPathNode

# 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())
Run Code Online (Sandbox Code Playgroud)

为了清楚地表明Node正在使用Path,请添加类型提示。从 Python 3.7 开始,有一个功能可以支持类型注释中的前向引用,如PEP 563中所述。

# 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())
Run Code Online (Sandbox Code Playgroud)

我遇到了另一个解决方案来将你从 Python 中的循环导入洞中挖掘出来,这是一篇很棒的博客文章,它教会了我这一点。


小智 5

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

因此,就我而言,我有一个相互依赖的 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)
Run Code Online (Sandbox Code Playgroud)