我正在努力解决在我看来是一个非常基本和常见的问题,经过数小时的互联网搜索后我找不到任何答案的事实告诉我,我一定做错了什么......
我只是想找到一种优雅的方式来处理我的包的导入。
的背景 :
我的包裹结构如下:
mypackage/
__init__.py
model/
__init__.py
A.py
B.py
controllers/
__init__.py
A.py
B.py
# mypackage/model/A.py
class A:
def __init__(self):
print("This is A's model.")
# mypackage/model/B.py
from mypackage.model.A import A as AModel
class B:
def __init__(self):
self._a_model = AModel()
print("This is B's model.")
# mypackage/controllers/A.py
class A:
def __init__(self):
print("This is A's controller.")
# mypackage/controllers/B.py
from mypackage.controllers.A import A as AController
class B:
def __init__(self):
self._a = AController()
print("This is B's controller.")
问题 :两件事是真的这个设计困扰着我。
第一:我想使用命名空间
我真的不喜欢写作
from mypackage.controllers.A import A as AController
...
self._a = AController()
感觉很麻烦,而且不是很pythonic......我更喜欢使用如下命名空间:
from mypackage import controllers
...
self._a = controllers.A.A()
但如果我尝试,我会得到 AttributeError: module 'mypackage.controllers' has no attribute 'A'
第二:我真的不喜欢输入类的文件名我真的不喜欢写作
from mypackage.controllers.A import A as AController
我会选择 :from mypackage.controllers import A as AController
什么没有奏效将所有内容放在一个文件中
我知道我可以通过将所有 Controller 的类(A 和 B)定义放在一个文件(controllers.py)中来得到我想要的,并对模型做同样的事情......
我读过几次,将多个类定义放在一个文件中是在 python 中很常见的事情......但对于大型单独的类,我不能。如果 A 和 B 是数百行并且彼此无关(除了作为 Controller 和模型),那么将它们的定义放在单个文件中是不可用的。
在 中使用导入初始化 .py 文件
确实可以解决我所有的问题...
除了那个 :
我在这里...
我的推理有什么问题?
最佳答案
Using imports in the
__init__.py
file
这就是要走的路。
对不起,如果它看起来对你来说太多样板,但如果你的项目很大,那就是需要的。
至于循环导入问题:无论您编写导入,它都会启动
在
__init__
文件与否,只是后勤问题。如果在您的
__init__
文件,你以正确的顺序编写导入,就不会有循环问题。IE。在您的
myproject/models/__init__.py
你有:from .A import A as AModel
from .B import B as BModel
当然,您将 .py 文件命名为与类相同的名称对您没有帮助 - 如果您至少放开文件名中的大小写,您可以编写:from .a import A
from .b import B
否则,您可以这样做:import myproject.models.A
import myproject.models.B
A = myproject.models.A.A
B = myproject.models.B.B
为了能够使用“myproject.models.A”作为类:姓名
A
里面 __init__
将覆盖模块对象同名。
一文
import myproject.models.A
将进入模块,但通过这样做from myproject.models import A
你得到了模块。如果这让人感到困惑......尽量不要为模块文件使用与类相同的名称。即使在忽略大小写的文件系统(如 Windows)中,您也会
反正模棱两可。遵守约定:snake_case 中的模块名,CamelCase 中的类名
回到循环导入问题:关键是在这个设计中,
b.py
仅在 a.py
之后读取已经导入,没有循环导入问题。这并不总是可能的 - 有时需要子模块之间的交叉引用。在这些情况下可以做的是移动
import
进入函数或方法,而不是作为全局语句。这样,当执行导入时,引用的模块已经初始化。
在您的示例中,这将是:
mypackage.models.b.py
# mypackage/model/B.py
class B:
def __init__(self):
from mypackage.model.A import A as AModel
self._a_model = AModel()
print("This is B's model.")
关于Python 子包和命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67609395/