簡體   English   中英

Python 中的循環依賴

[英]Circular dependency in Python

我有兩個文件, node.pypath.py ,它們分別定義了兩個類, NodePath

直到今天, Path的定義引用了Node對象,因此我已經完成了

from node.py import *

path.py文件中。

但是,截至今天,我為Node創建了一個引用Path對象的新方法。

我在嘗試導入path.py時遇到了問題:我試過了,當程序運行並調用使用NodePath方法時,出現了一個關於Node未定義的異常。

我該怎么辦?

Importing Python Modules是一篇很好的文章,它解釋了 Python 中的循環導入。

解決此問題的最簡單方法是將路徑導入移動到節點模塊的末尾。

另一種方法是僅在另一個需要它的函數中導入兩個模塊之一。 當然,如果您只需要在一個或少數幾個功能中使用它,則效果最佳:

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

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

我更喜歡通過在另一個依賴類的構造函數中聲明一個依賴來打破循環依賴。 在我看來,這使代碼更整潔,並且可以輕松訪問需要依賴項的所有方法。

所以在我的情況下,我有一個 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)

您可能不需要在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 中的圓形導入漏洞中挖掘出來,這是一篇很棒的博客文章,它教會了我這一點。

另一種方法是在同一個模塊中定義它們,並延遲定義類型。 有點像這樣:

class Node:
   _path_type: type = None
   
   def method_needs_path(self):
       p = self._path_type()
       ...


class Path:
    def method_needs_node(self):
       n = Node()

Node._path_type = Path

對此保持對稱可能會更好:

class Node:
   _path_type: type = None
   
   def method_needs_path(self):
       p = self._path_type()
       ...


class Path:
    _node_type: type = None

    def method_needs_node(self):
       n = Node()

Node._path_type = Path
Path._node_type = Node

這也可以在多個模塊中完成:

# in node.py
class Node:
   _path_type: type = None
   
   def method_needs_path(self):
       p = self._path_type()
       ...

# in path.py
from .node import Node

class Path:
    _node_type: type = None

    def method_needs_node(self):
       n = self._node_type()

Node._path_type = Path
Path._node_type = Node

# in __init__.py (note that order is important now)
from .node import Node
from .path import Path

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM