python 命名空间与包:使包成为默认命名空间
python namespaces vs packages: making a package the default namespace
我有一个包含总体命名空间的项目,其中包含包。这是文件夹结构:
pypackage
├── pypackage <-- Source code for use in this project.
| |
│ ├── bin <-- Module: Cli entry point into pyproject.
| | ├── __init__.py
| | └── pypackage.py
| |
| └── core <-- Module: Core functionality.
| ├── __init__.py
| └── pypackage.py
|
├── tests
├── README.md
└── setup.py
很简单。如果我想导入它,我使用:
from pypackage.core import pypackage
效果很好,因为我的 setup.py 看起来像这样:
from setuptools import setup, find_packages
...
NAME = 'pypackage'
setup(
name=NAME,
namespace_packages=[NAME],
packages=[f'{NAME}.{p}' for p in find_packages(where=NAME)],
entry_points={
"console_scripts": [
f'{NAME} = {NAME}.bin.{NAME}:cli',
]
},
...
)
但是,我有遗留代码导入这个 pypackage
,而它曾经只是一个独立的 python 文件。像这样:
import pypackage
那么,我该怎么做才能使命名空间和子包的结构保持不变,但仍然以旧方式导入它?我如何打开它:
from pypackage.core import pypackage
进入这个:
import pypackage
换句话说,当我将 pypackage
导入外部项目时,如何将 pypackage.core.pypackage
模块别名为 pypackage
?
您可以通过导入顶级包来在新包中添加 'old' 名称。
在 pypackage/__init__.py
中作为全局变量导入的名称是 pypackage
包中的属性。利用它可以访问 'legacy' 个位置:
# add all public names from pypackage.core.pypackage to the top level for
# legacy package use
from .core.pypackage import *
现在任何使用 import pypackage
的代码都可以使用 pypackage.foo
和 pypackage.bar
,如果实际上这些对象是在 pypackage.core.pypackage
中定义的话。
现在,因为 pypackage
是 setuptools namespace package,所以您遇到了不同的问题;命名空间包用于安装多个单独的发行版,因此顶级包必须是 空 或仅包含最小 __init__.py
文件(使用空目录创建的命名空间包需要Python3.3).
如果您是唯一使用此命名空间的发行版发布者,您可以在这里稍微作弊并在 core
中使用 单个 __init__.py
文件] 包可以使用 pkg-util-style __init__.py
file 和我上面使用的附加导入,但是你 不能在其他分发包 中使用任何 __init__.py
文件或要求它们全部使用完全相同的 __init__.py
内容。协调是关键。
或者您将不得不使用不同的方法。将 pypackage
保留为遗留包装器模块,并重命名新的包格式以使用可以与旧模块相邻的新的、不同的顶级名称。此时,您可以直接将遗留包作为额外的顶级模块包含在您的项目中。
如果我使用包,Martin Pieters 的想法是正确的,但命名空间包是一个设置工具的事情。
所以那没有用。经过更多研究,我了解到没有办法做我想做的事情。因此,如果我真的想这样做,我必须将所有内容转换为常规包层次结构而不是命名空间包,然后使用马丁的解决方案。
我决定修改遗留代码,而不是以新方式导入它。
我有一个包含总体命名空间的项目,其中包含包。这是文件夹结构:
pypackage
├── pypackage <-- Source code for use in this project.
| |
│ ├── bin <-- Module: Cli entry point into pyproject.
| | ├── __init__.py
| | └── pypackage.py
| |
| └── core <-- Module: Core functionality.
| ├── __init__.py
| └── pypackage.py
|
├── tests
├── README.md
└── setup.py
很简单。如果我想导入它,我使用:
from pypackage.core import pypackage
效果很好,因为我的 setup.py 看起来像这样:
from setuptools import setup, find_packages
...
NAME = 'pypackage'
setup(
name=NAME,
namespace_packages=[NAME],
packages=[f'{NAME}.{p}' for p in find_packages(where=NAME)],
entry_points={
"console_scripts": [
f'{NAME} = {NAME}.bin.{NAME}:cli',
]
},
...
)
但是,我有遗留代码导入这个 pypackage
,而它曾经只是一个独立的 python 文件。像这样:
import pypackage
那么,我该怎么做才能使命名空间和子包的结构保持不变,但仍然以旧方式导入它?我如何打开它:
from pypackage.core import pypackage
进入这个:
import pypackage
换句话说,当我将 pypackage
导入外部项目时,如何将 pypackage.core.pypackage
模块别名为 pypackage
?
您可以通过导入顶级包来在新包中添加 'old' 名称。
在 pypackage/__init__.py
中作为全局变量导入的名称是 pypackage
包中的属性。利用它可以访问 'legacy' 个位置:
# add all public names from pypackage.core.pypackage to the top level for
# legacy package use
from .core.pypackage import *
现在任何使用 import pypackage
的代码都可以使用 pypackage.foo
和 pypackage.bar
,如果实际上这些对象是在 pypackage.core.pypackage
中定义的话。
现在,因为 pypackage
是 setuptools namespace package,所以您遇到了不同的问题;命名空间包用于安装多个单独的发行版,因此顶级包必须是 空 或仅包含最小 __init__.py
文件(使用空目录创建的命名空间包需要Python3.3).
如果您是唯一使用此命名空间的发行版发布者,您可以在这里稍微作弊并在 core
中使用 单个 __init__.py
文件] 包可以使用 pkg-util-style __init__.py
file 和我上面使用的附加导入,但是你 不能在其他分发包 中使用任何 __init__.py
文件或要求它们全部使用完全相同的 __init__.py
内容。协调是关键。
或者您将不得不使用不同的方法。将 pypackage
保留为遗留包装器模块,并重命名新的包格式以使用可以与旧模块相邻的新的、不同的顶级名称。此时,您可以直接将遗留包作为额外的顶级模块包含在您的项目中。
如果我使用包,Martin Pieters 的想法是正确的,但命名空间包是一个设置工具的事情。
所以那没有用。经过更多研究,我了解到没有办法做我想做的事情。因此,如果我真的想这样做,我必须将所有内容转换为常规包层次结构而不是命名空间包,然后使用马丁的解决方案。
我决定修改遗留代码,而不是以新方式导入它。