Python中的循环依赖

94 投票
4 回答
115947 浏览
提问于 2025-04-15 11:45

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

到目前为止,Path 的定义中引用了 Node 对象,所以我在 path.py 文件中做了如下设置:

from node.py import *

但是,今天我为 Node 创建了一个新方法,这个方法中又引用了 Path 对象。

当我尝试导入 path.py 时遇到了问题:我试着运行程序,结果在调用使用 NodePath 方法时,出现了一个错误,提示 Node 没有定义。

我该怎么办呢?

4 个回答

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

node.py 文件中,你可能不需要导入 Path,这样 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,可以添加类型提示。从 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())

我发现了一个很棒的博客文章,教我如何解决 Python 中的循环导入问题,这篇文章对我帮助很大。

33

另一种方法是在你需要用到的函数里面只导入这两个模块中的一个。这样做最有效的情况是你只在一个或少数几个函数中需要这个模块:

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

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

撰写回答