小编典典

Python 3 中的相对导入

all

我想从同一目录中的另一个文件导入一个函数。

有时它对我有用,from .mymodule import myfunction但有时我得到:

SystemError: Parent module '' not loaded, cannot perform relative import

有时它适用于from mymodule import myfunction,但有时我也会得到:

SystemError: Parent module '' not loaded, cannot perform relative import

我不明白这里的逻辑,我找不到任何解释。这看起来完全随机。

有人可以向我解释这一切背后的逻辑是什么吗?


阅读 108

收藏
2022-02-25

共1个答案

小编典典

不幸的是,这个模块需要在包中,有时它还需要作为脚本运行。知道我怎么能做到这一点吗?

有这样的布局很常见......

main.py
mypackage/
    __init__.py
    mymodule.py
    myothermodule.py

......mymodule.py像这样......

#!/usr/bin/env python3

# Exported function
def as_int(a):
    return int(a)

# Test function for module  
def _test():
    assert as_int('1') == 1

if __name__ == '__main__':
    _test()

……myothermodule.py像这样……

#!/usr/bin/env python3

from .mymodule import as_int

# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

……还有main.py这样的……

#!/usr/bin/env python3

from mypackage.myothermodule import add

def main():
    print(add('1', '1'))

if __name__ == '__main__':
    main()

…当您运行main.py或时工作正常,但由于相对导入mypackage/mymodule.py而失败…mypackage/myothermodule.py

from .mymodule import as_int

你应该运行它的方式是......

python3 -m mypackage.myothermodule

…但它有点冗长,并且不能与像#!/usr/bin/env python3.

对于这种情况,最简单的解决方法是,假设名称mymodule是全局唯一的,将避免使用相对导入,而只需使用…

from mymodule import as_int

…虽然,如果它不是唯一的,或者您的包结构更复杂,您需要在 中包含包含您的包目录的目录PYTHONPATH,并这样做…

from mypackage.mymodule import as_int

…或者,如果您希望它“开箱即用”,您可以PYTHONPATH先用这个来敲击 in 代码…

import sys
import os

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(SCRIPT_DIR))

from mypackage.mymodule import as_int

这有点痛苦,但在某位 Guido van Rossum
的电子邮件中,有一个线索可以解释为什么......

我对此以及任何其他提议的__main__
机器玩弄都是-1。唯一的用例似乎是运行恰好位于模块目录中的脚本,我一直将其视为反模式。要让我改变主意,你必须说服我它不是。

在包中运行脚本是否是反模式是主观的,但我个人发现它在我拥有的包含一些自定义 wxPython
小部件的包中非常有用,因此我可以为任何源文件运行脚本以显示wx.Frame仅包含该小部件用于测试目的。

2022-02-25