Python 个子包和命名空间
Python subpackages and namespaces
我正在努力解决在我看来是一个非常基本和常见的问题,经过数小时的互联网搜索后我找不到任何答案这一事实告诉我,我一定是做错了什么...
我只是想找到一种优雅的方式来处理我的包裹的进口。
背景:
我的包裹结构如下:
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'
其次:我真的不喜欢输入 class 的文件名
我真的不喜欢写作
from mypackage.controllers.A import A as AController
我更愿意:
from mypackage.controllers import A as AController
什么没用
将所有内容放在一个文件中
我知道我可以通过将所有控制器的 class(A 和 B)定义放在一个文件中(controllers.py)来获得我想要的东西,并对模型执行相同的操作...
我多次读到,在 python 中将几个 class 定义放在一个文件中是很常见的事情...但是对于大的单独 classes 我只是不能。如果 A 和 B 是数百行并且彼此无关(除了作为控制器和模型),将它们的定义放在一个文件中是不可用的。
在 init.py 文件中使用导入
的确,它会解决我所有的问题...
除了:
- 这会导致循环导入。如您所见,我需要在 B 的模型中使用 A 的模型...因此,如果在我需要访问其中一个模型时导入所有模型,我陷入了恶性循环...
- 看起来不是很pythonic。如果只是因为它强制用户加载每个模块。
我在这里...
我的推理有什么问题?
# mypackage/controllers/__init__.py
from A import A
然后你可以在 mypackage 之外创建一个新文件。
# check.py
from mypackage.controllers import A as AController
from mypackage import controllers
a = controllers.A()
>>> This is A's controller.
让我们知道它是否适合您。
[我脑子里乱七八糟的,没有测试]
I really don't like writing
from mypackage.controllers.A import A as AController
#...
self._a = AController()
It feels cumbersome and not very pythonic... I would prefer using
namespaces like in :
from mypackage import controllers
# ...
self._a = controllers.A.A()
在 mypackage/controllers/__init__.py
你需要:from . import A
.
I really don't like writing
from mypackage.controllers.A import A as AController
I would prefer :
from mypackage.controllers import A as AController
在 mypackage/controllers/__init__.py
你需要 from A import A
.
Using imports in the __init__.py
file
这就是要走的路。
对不起,如果它看起来对你来说太多样板,但如果你的项目很大,那就是需要的。
至于循环导入问题:它会在你写你的导入时起作用
是否在 __init__
文件中,这只是一个后勤问题。
如果在你的 __init__
文件中,你以正确的顺序写入导入,就不会有循环问题。
即在你的 myproject/models/__init__.py
中你有:
from .A import A as AModel
from .B import B as BModel
当然,您将 .py 文件命名为与 classes 相同的名称对您没有帮助 - 如果您至少放弃文件名中的大小写,您可以这样写:
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”用作 class:
__init__
中的名称 A
将覆盖模块对象
同名
一个写作
import myproject.models.A
将到达模块,但是通过执行
from myproject.models import A
你得到了模块。
如果这让人感到困惑...尽量不要对模块文件使用与 classes 相同的名称。即使在忽略大小写的文件系统中,比如 Windows 你会
总之模棱两可。坚持约定:snake_case 中的模块名称,CamelCase
中的 class 名称
回到循环导入问题:关键是在这个设计中,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.")
我正在努力解决在我看来是一个非常基本和常见的问题,经过数小时的互联网搜索后我找不到任何答案这一事实告诉我,我一定是做错了什么...
我只是想找到一种优雅的方式来处理我的包裹的进口。
背景:
我的包裹结构如下:
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'
其次:我真的不喜欢输入 class 的文件名
我真的不喜欢写作
from mypackage.controllers.A import A as AController
我更愿意:
from mypackage.controllers import A as AController
什么没用
将所有内容放在一个文件中
我知道我可以通过将所有控制器的 class(A 和 B)定义放在一个文件中(controllers.py)来获得我想要的东西,并对模型执行相同的操作...
我多次读到,在 python 中将几个 class 定义放在一个文件中是很常见的事情...但是对于大的单独 classes 我只是不能。如果 A 和 B 是数百行并且彼此无关(除了作为控制器和模型),将它们的定义放在一个文件中是不可用的。
在 init.py 文件中使用导入
的确,它会解决我所有的问题...
除了:
- 这会导致循环导入。如您所见,我需要在 B 的模型中使用 A 的模型...因此,如果在我需要访问其中一个模型时导入所有模型,我陷入了恶性循环...
- 看起来不是很pythonic。如果只是因为它强制用户加载每个模块。
我在这里...
我的推理有什么问题?
# mypackage/controllers/__init__.py
from A import A
然后你可以在 mypackage 之外创建一个新文件。
# check.py
from mypackage.controllers import A as AController
from mypackage import controllers
a = controllers.A()
>>> This is A's controller.
让我们知道它是否适合您。
[我脑子里乱七八糟的,没有测试]
I really don't like writing
from mypackage.controllers.A import A as AController #... self._a = AController()
It feels cumbersome and not very pythonic... I would prefer using namespaces like in :
from mypackage import controllers # ... self._a = controllers.A.A()
在 mypackage/controllers/__init__.py
你需要:from . import A
.
I really don't like writing
from mypackage.controllers.A import A as AController
I would prefer :
from mypackage.controllers import A as AController
在 mypackage/controllers/__init__.py
你需要 from A import A
.
Using imports in the
__init__.py
file
这就是要走的路。 对不起,如果它看起来对你来说太多样板,但如果你的项目很大,那就是需要的。
至于循环导入问题:它会在你写你的导入时起作用
是否在 __init__
文件中,这只是一个后勤问题。
如果在你的 __init__
文件中,你以正确的顺序写入导入,就不会有循环问题。
即在你的 myproject/models/__init__.py
中你有:
from .A import A as AModel
from .B import B as BModel
当然,您将 .py 文件命名为与 classes 相同的名称对您没有帮助 - 如果您至少放弃文件名中的大小写,您可以这样写:
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”用作 class:
__init__
中的名称 A
将覆盖模块对象
同名
一个写作
import myproject.models.A
将到达模块,但是通过执行
from myproject.models import A
你得到了模块。
如果这让人感到困惑...尽量不要对模块文件使用与 classes 相同的名称。即使在忽略大小写的文件系统中,比如 Windows 你会 总之模棱两可。坚持约定:snake_case 中的模块名称,CamelCase
中的 class 名称回到循环导入问题:关键是在这个设计中,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.")