在Python中管理相互引用的类之间的循环依赖和类型提示

huangapple go评论72阅读模式
英文:

Managing Circular Dependencies and Type Hints Between Mutually Referencing Classes in Python

问题

我有一个场景,我正在处理两个类A和B,它们位于分别位于a.py和b.py模块中。类A在类型提示中使用了类B,而类B在其功能中使用了类A(关联关系)。目前,我的代码实现了这个功能,但我希望能够改进或简化实现方式,以解决循环依赖和可维护性的问题。在仍然有效使用类型提示的情况下,我应该如何以更清晰和更有组织的方式设计类A和类B之间的交互?

目前,我通过以下方式处理这个问题:

a.py:

from b import B

class A:
    def __init__(self, test: B) -> None:
        self.test = test

    def process(self):
        return self.test.hi()

b.py:

class B:
    def __init__(self) -> None:
        print(1)

    def hi(self):
        print("hi")

    def import_A(self):
        from a import A
        t = A(self)
        print(t.process())

请注意,如果我将from a import A移到顶部,会出现循环导入错误。有没有办法在开始时导入所有内容而不引发任何错误?

英文:

I have a scenario where I'm working with two classes, A and B, located in separate modules a.py and b.py. Class A uses class B as a type hint, and class B uses class A in its functionality(Association relationship). Currently, my code achieves this functionality, but I'm open to suggestions for improving or simplifying the implementation due to concerns about circular dependencies and maintainability. How can I design this interaction between classes A and B in a cleaner and more organized way while still using type hints effectively?

I currently handle this problem by something like this:

a.py:

from b import B

class A:
    def __init__(self, test: B) -> None:
        self.test = test

    def process(self):
        return self.test.hi()

b.py:

class B:
    def __init__(self) -> None:
        print(1)

    def hi(self):
        print("hi")

    def import_A(self):
        from a import A
        t = A(self)
        print(t.process())

Note that if I move from a import A to the top, a circular import error occurs. Is there any way to import everything at the beginning without causing any error?

答案1

得分: 0

一些建议

完全不要将 A 引入到 B 中

    def import_A(self):
        from a import A
        t = A(self)
        print(t.process())

这段逻辑与 B 没有任何关系,可以写在另一个文件中。

避免具体的导入

from b import B
from a import A

当你从一个文件中导入特定的值时,它会强制 Python 立即解析它。如果你改为这样写:

import x
...
foobar(x.X)

那么你就有机会让一些“循环”导入得以保留。尽量避免过度使用这种方式,这仍然是一种代码异味,很可能意味着设计上有些问题。

将它们放在同一个文件中

如果两个类确实紧密相关,通常将它们放在一起比分开更好,即使这样会使某些文件变得很大。考虑一下 TreeLeaf 节点类,它们有不同的实现,但明显应该放在一起。

在上下方使用共同的文件

将抽象内容放入两个都可以从中导入的共同文件中,通常可以帮助解决问题。这可以与“将它们放在同一个文件中”相结合,将抽象内容放在一起,具体实现分开。

同样,将执行或测试部分放在一个单独的文件中,这样你也可以避免完整逻辑中的循环。

a --\           c           a   b         c
  \-- b    vs  / \    vs     \ /    vs   / \
              a   b           e         a   b
                                         \ /
                                          e
英文:

A few suggestions

don't pull A into b at all

    def import_A(self):
        from a import A
        t = A(self)
        print(t.process())

this logic doesn't really have anything to do with B, and could be written in another file.

avoid concrete imports

from b import B
        from a import A

When you import a specific value from a file, it forces python to resolve that immediately. If you instead say

import x
  ...
    foobar(x.X)

then you have a chance of allowing some "circular" imports surviving.
Try to avoid using this excessively, it is still a code smell and likely means something isn't quite right in the design.

put them in the same file

If two classes are really intertwined, it can often be much more preferable to put them together than apart, even if it makes some files rather large. Consider Tree and Leaf node classes that have different implementations but definitely should reside together.

use common files above and below

Pulling abstractions into common files that both can import from can often help remove issues, this can be combined with "put them in the same file" to have abstractions together and concrete implementations separate.

Likewise, putting the execution or test portions in a separate file means that you also avoid loops in the full logic.

a --\           c           a   b         c
  \-- b    vs  / \    vs     \ /    vs   / \
              a   b           e         a   b
                                         \ /
                                          e

huangapple
  • 本文由 发表于 2023年8月9日 00:45:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76861627.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定