, к сожалению, этот модуль должен находиться внутри пакета, и иногда он должен исполняться как скрипт. Любая идея, как я мог бы это достичь?
Это довольно распространенный способ иметь такой макет ...
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()
... a
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()
... и a
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
... но он несколько подробный и не очень хорошо сочетается с строкой shebang, например
#!/usr/bin/env python3
.Самое простое исправление для этого случая, если имя
mymodule
уникально глобально, было бы избежать использования относительного импорта и просто использовать ...from mymodule import as_int
... хотя, если это не уникально или ваша структура пакета более сложна, вам нужно будет включить каталог, содержащий каталог вашего пакета в
PYTHONPATH
, и сделать это так:from mypackage.mymodule import as_int
.. . Если вы хотите, чтобы он работал «из коробки», вы можете frob
PYTHONPATH
в коде сначала с этим ...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
Это какая-то боль, но есть clu e о том, почему в электронное письмо написано неким Гвидо ван Россумом ...
Я на этом и на любых других предложенных твидлингах
__main__
. Единственный случай использования, похоже, заключается в запуске скриптов, которые, случается, живут внутри каталога модуля, который я всегда рассматривал как антипаттерн. Чтобы заставить меня передумать, вы должны были бы убедить меня, что это не так.Не работает ли скрипт внутри пакета антипаттерн или нет, но лично я нахожу его действительно полезно в пакете, который содержит некоторые пользовательские виджеты wxPython, поэтому я могу запустить скрипт для любого из исходных файлов, чтобы отобразить
wx.Frame
, содержащий только этот виджет для тестирования.