能否使用Python 相对导入将当前模块的__init__ 文件导入到特定名称下?

Can you use Python relative imports to import the __init__ file of the current module under a specific name?

假设我有一个包含两个文件的模块,如下所示:

mymodule
 |-- __init__.py
 `-- submodule.py

mymodule/__init__.py 包含:

SOME_CONSTANT_ONE = 1
SOME_CONSTANT_TWO = 2
SOME_CONSTANT_THREE = 3
...
SOME_CONSTANT_ONE_HUNDRED = 100

def initialize():
    pass # do some stuff

def support_function():
    pass # something that lots of other functions might need

我已经知道我可以使用相对导入从 __init__.py 文件中引入 特定的 对象,如下所示:

submodule.py:

from . import initialize, support_function

def do_work():
    initialize() # initialize the module
    print(support_function()) # do something with the support function

但现在我想知道的是,我是否可以从 __init__.py 文件中导入 所有 常量,但同时让它们出现在命名空间中。

什么行不通(我有什么 tried/considered):

真正想要的是这样的:

submodule.py:

SOME_CONSTANT_ONE = "one!" # We don't want to clobber this.

import . as outer_module # this does not work, but it illustrates what is desired.

def do_work():
    print(SOME_CONSTANT_ONE)              # should print "one!"
    print(outer_module.SOME_CONSTANT_ONE) # should print "1"

我知道我可以将所有常量移动到一个 constants.py 文件,然后我应该可以用 from . import constants (as something) 导入它,但我正在处理现有代码并进行更改需要大量的重构。虽然这不是一个坏主意,但我想知道,鉴于 Python 确实有办法导入单个对象,并且还可以通过名称 将整个模块 导入显式name,如果我可以用 importlib 做一些事情来完成将所有内容从 __init__.py 导入命名空间?

I could move all of the constants to a constants.py file and then I should be able to import it with from . import constants (as something) but I'm working on existing code and making that change would require a lot of refactoring

您仍然可以将常量重构到新的 constants.py 模块中。要支持依赖于 __init__.py 的现有代码,您可以将常量导入 __init__.py

# constants.py
SOME_CONSTANT_ONE = 1
SOME_CONSTANT_TWO = 2
SOME_CONSTANT_THREE = 3
... # etc
# __init__.py
from .constants import *
# submodule.py
SOME_CONSTANT_ONE = 'dont clobber me!'
from . import constants as something
print(something.SOME_CONSTANT_ONE) # Yay namespaces
# existing_code.py
from . import SOME_CONSTANT_ONE
# still works!
# no refactor required!

通常 来说,__init__.py 文件通常完全是空的,没有任何内容直接定义在那里。如果 __init__.py 中有内容,它们通常是从包中导入的。

加载器设置__package__,您可以使用:

import sys

SOME_CONSTANT_ONE = "one!" # We don't want to clobber this.

outer_module = sys.modules[__package__]

def do_work():
    print(SOME_CONSTANT_ONE)              # should print "one!"
    print(outer_module.SOME_CONSTANT_ONE) # should print "1"

这正是相关导入所基于的属性。 有关详细信息,请参阅 PEP 366

但是,我真的认为另一个答案建议的向后兼容重构可能是更好的方法。