问题描述
我想从同一目录中的另一个文件导入一个函数.
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?
推荐答案
这样的布局很常见...
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.py
或 mypackage/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机械.唯一的用例似乎是运行发生的脚本住在一个模块的目录中,我一直认为它是一个反模式.为了让我改变主意,你必须说服我不是.
在包中运行脚本是否是反模式是主观的,但我个人发现它在包含一些自定义 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 中的相对导入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!