BWW*_*BWW 98 python import circular-dependency
我知道python中循环导入的问题已经出现过很多次了,我已经阅读过这些讨论了.在这些讨论中反复提出的评论是,循环导入是设计错误的标志,应重新组织代码以避免循环导入.
有人可以告诉我如何在这种情况下避免循环导入吗?:我有两个类,我希望每个类都有一个构造函数(方法),它接受另一个类的实例并返回该类的实例.
更具体地说,一个类是可变的,一个是不可变的.散列,比较等需要不可变类.可变类也需要做事.这与sets和frozensets或者列表和元组类似.
我可以将两个类定义放在同一个模块中.还有其他建议吗?
玩具示例是类A,其具有属性是列表,而类B具有属性是元组.然后类A有一个方法,它接受类B的实例并返回类A的实例(通过将元组转换为列表),类似地,类B有一个方法,它接受类A的实例并返回类B的实例(通过将列表转换为元组).
Bre*_*bel 163
考虑以下示例python包在哪里a.py并b.py相互依赖:
/package
__init__.py
a.py
b.py
Run Code Online (Sandbox Code Playgroud)
有几种方法可以在python中导入模块
import package.a # (1) Absolute import
import package.a as a_mod # (2) Absolute import bound to different name
from package import a # (3) Alternate absolute import
import a # (4) Implicit relative import (deprecated, python 2 only)
from . import a # (5) Explicit relative import
Run Code Online (Sandbox Code Playgroud)
不幸的是,只有第一个和第四个选项实际上在你有循环依赖关系时才会起作用(其余全部加注ImportError或AttributeError).通常,您不应该使用第4种语法,因为它仅适用于python2并且存在与其他第三方模块冲突的风险.实际上,只有第一种语法才能保证正常工作.但是,在处理循环依赖项时,您仍有几个选项.
编辑:
ImportError和AttributeError问题只发生在python 2中.在python 3中,导入机制已经被重写,所有这些import语句(4除外)都可以工作,即使是循环依赖.
只需使用上面的第一个导入语法.这种方法的缺点是导入名称对于大型包来说可能会超长.
在 a.py
import package.b
Run Code Online (Sandbox Code Playgroud)
在 b.py
import package.a
Run Code Online (Sandbox Code Playgroud)
我已经看到这个方法在很多软件包中使用了,但它对我来说仍然感觉很讨厌,我不喜欢看不到模块的顶部并看到它的所有依赖项,我不得不去搜索所有的函数同样.
在 a.py
def func():
from package import b
Run Code Online (Sandbox Code Playgroud)
在 b.py
def func():
from package import a
Run Code Online (Sandbox Code Playgroud)
这也有效,但是与第一种方法有同样的问题,其中所有的包和子模块调用都变得超长.它还有两个主要缺陷 - 它强制导入所有子模块,即使你只使用一个或两个,你仍然无法查看任何子模块并快速看到它们的依赖关系在顶部,你必须筛选功能.
在 __init__.py
from . import a
from . import b
Run Code Online (Sandbox Code Playgroud)
在 a.py
import package
def func():
package.b.some_object()
Run Code Online (Sandbox Code Playgroud)
在 b.py
import package
def func():
package.a.some_object()
Run Code Online (Sandbox Code Playgroud)
所以那些是你的选择(他们都有点吮吸IMO).坦率地说,这似乎是python导入机制中的一个明显的错误,但这仅仅是我的观点.
rum*_*pel 88
只导入模块,不要从模块导入:
考虑a.py:
import b
class A:
def bar(self):
return b.B()
Run Code Online (Sandbox Code Playgroud)
并且b.py:
import a
class B:
def bar(self):
return a.A()
Run Code Online (Sandbox Code Playgroud)
这完全没问题.
我们将绝对导入和函数组合在一起,以便更好地阅读和缩短访问字符串.
主/副/ a.py
import main.sub.b
b_mod = lambda: main.sub.b
class A():
def __init__(self):
print('in class "A":', b_mod().B.__name__)
Run Code Online (Sandbox Code Playgroud)
主/副/ b.py
import main.sub.a
a_mod = lambda: main.sub.a
class B():
def __init__(self):
print('in class "B":', a_mod().A.__name__)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
51370 次 |
| 最近记录: |