【问题标题】:Can you use Python relative imports to import the __init__ file of the current module under a specific name?可以使用 Python 相对导入以特定名称导入当前模块的 __init__ 文件吗?
【发布时间】:2021-10-07 18:56:57
【问题描述】:

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

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 文件中引入 特定 对象,如下所示:

子模块.py:

from . import initialize, support_function

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

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

什么不起作用(我尝试过/考虑过的):

  • import mymodule as outer_module 有效,因为导入系统已经知道模块的位置。但是,如果我需要更改外部模块的名称,该代码将会中断。
  • import . as outer_module 不起作用。
  • 执行from . import * 确实有效,但会将__init__.py 中的所有对象放在当前命名空间而不是子命名空间中。
  • from . import SOME_CONSTANT_ONE as outer_constant_1, SOME_CONSTANT_TWO as outer_constant_2, SOME_CONSTANT_THREE as outer_constant_3, ... 是丑陋的,如果它们稍后在 __init__.py 中定义,也不会引入任何新常量。

真正想要的是这样的:

子模块.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 确实有一种方法可以导入单个对象,并且如果可以的话,还可以将整个模块 按名称 导入一个明确的名称使用importlib 来完成将__init__.py 中的所有内容导入命名空间?

【问题讨论】:

    标签: python python-import python-importlib


    【解决方案1】:

    加载器设置你可以使用的__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

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

    【讨论】:

      【解决方案2】:

      我可以将所有常量移动到 constants.py 文件中,然后我应该能够使用 from . import constants (as something) 导入它,但我正在处理现有代码,并且进行更改需要大量重构

      您仍然可以将常量重构到新的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 中有内容,它们通常是从包中导入的。 https://stackoverflow.com/a/4116384/5747944

      【讨论】:

        猜你喜欢
        • 2021-10-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-16
        • 2015-04-30
        • 2013-04-21
        • 2022-08-21
        • 2016-07-30
        相关资源
        最近更新 更多