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
...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()
...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()
...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()
...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
...but it's somewhat verbose, and doesn't mix well with a shebang line like #!/usr/bin/env python3
.
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
...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
...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
It's kind of a pain, but there's a clue as to why in an email written by a certain Guido van Rossum...
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.
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.
总结:加了点之后,就变成了模块,不能直接作为脚本执行了,脚本模式不支持相对导入。只能在main中作为模块导入。
一个点,当前目录,二个点,上级目录。
包中的文件可以直接点,但是下面的目录只能导入。
转载:https://stackoverflow.com/questions/16981921/relative-imports-in-python-3#