Python 3 中的相对导入 [英] Relative imports in Python 3

查看:66
本文介绍了Python 3 中的相对导入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to import a function from another file in the same directory.

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

Sometimes it works for me with from .mymodule import myfunction but sometimes I get a:

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

有时它与 from mymodule import myfunction 一起工作,但有时我也会得到:

Sometimes it works with from mymodule import myfunction, but sometimes I also get a:

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

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

I don't understand the logic here, and I couldn't find any explanation. This looks completely random.

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

Could someone explain to me what's the logic behind all this?

推荐答案

不幸的是,这个模块需要在包内,而且它也有时需要作为脚本运行.知道我怎么能达到这个目标?

unfortunately, this module needs to be inside the package, and it also needs to be runnable as a script, sometimes. Any idea how I could achieve that?

这样的布局很常见...

It's quite common to have a layout like this...

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

...使用这样的 mymodule.py...

...with a mymodule.py like this...

#!/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...

...a myothermodule.py like this...

#!/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...

...and a main.py like this...

#!/usr/bin/env python3

from mypackage.myothermodule import add

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

if __name__ == '__main__':
    main()

...当您运行 main.pymypackage/mymodule.py 时运行良好,但使用 mypackage/myothermodule.py 失败>,由于相对导入...

...which works fine when you run main.py or mypackage/mymodule.py, but fails with mypackage/myothermodule.py, due to the relative import...

from .mymodule import as_int

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

The way you're supposed to run it is...

python3 -m mypackage.myothermodule

...但它有点冗长,并且不能与像 #!/usr/bin/env python3 这样的shebang 行很好地混合.

...but it's somewhat verbose, and doesn't mix well with a shebang line like #!/usr/bin/env python3.

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

The simplest fix for this case, assuming the name mymodule is globally unique, would be to avoid using relative imports, and just use...

from mymodule import as_int

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

...although, if it's not unique, or your package structure is more complex, you'll need to include the directory containing your package directory in PYTHONPATH, and do it like this...

from mypackage.mymodule import as_int

...或者如果您希望它开箱即用",您可以首先使用代码中的PYTHONPATH...

...or if you want it to work "out of the box", you can frob the PYTHONPATH in code first with this...

import sys
import os

PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))

from mypackage.mymodule import as_int

这有点痛苦,但在 一封由 Guido van Rossum 撰写的电子邮件...

It's kind of a pain, but there's a clue as to why in an email written by a certain Guido van Rossum...

我在这个和任何其他提议的 __main__ 的摆弄上都是 -1机械.唯一的用例似乎是运行发生的脚本住在一个模块的目录中,我一直认为它是一个反模式.为了让我改变主意,你必须说服我不是.

I'm -1 on this and on any other proposed twiddlings of the __main__ machinery. The only use case seems to be running scripts that happen to be living inside a module's directory, which I've always seen as an antipattern. To make me change my mind you'd have to convince me that it isn't.

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

Whether running scripts inside a package is an antipattern or not is subjective, but personally I find it really useful in a package I have which contains some custom wxPython widgets, so I can run the script for any of the source files to display a wx.Frame containing only that widget for testing purposes.

这篇关于Python 3 中的相对导入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆