оригинал:BRETT CANNON
Переводчик: Кот под цветком гороха @Python Cat
Английский:придурковатый. руб/его и-удовлетворенный-вау…
запустили для насПлагин Python для VS Code[1], я написалПростой скрипт для создания журнала изменений[2] (аналогичноTowncrier[3], но проще, поддерживает Markdown, что соответствует нашим потребностям). В процессе публикации одним из шагов является запускpython news, который укажет Python на каталог «news» в нашем коде.
На днях соавтор спросил, как это работает, и кажется, что все в нашей команде знают, как использовать-m? (см. мойСтатья об использовании pip с -m[4], понятно почему)более подробная статья)
Это заставило меня осознать, что существуют всевозможные способы указать Python на исполняемый код, о котором другие могут не знать, отсюда и этот пост.
1. Через стандартный ввод и пайпы
Поскольку передача чего-либо в процесс является частью оболочки, я не буду подробно объяснять это. Излишне говорить, что вы можете передавать код в Python.
# 管道传内容给 python
echo "print('hi')" | python
Это, очевидно, также работает, если вы перенаправляете файл на Python.
# 重定向一个文件给 python
python < spam.py
Благодаря наследию Python для UNIX это не стало неожиданностью.
2. Пройти-cуказанная строка
Если вам просто нужно что-то быстро проверить, вы можете передать код в виде строки в командной строке.
# 使用 python 的 -c 参数
python -c "print('hi')"
Я лично использую его, когда мне нужно изучить всего одну или две строки кода, а не запускать REPL.python, войдет в интерактивный интерпретатор. Использование параметра -c может сэкономить процесс входа в интерфейс интерпретатора).
3. Путь к файлу
Вероятно, самый известный способ передать код в python — через путь к файлу.
# 指定 python 的文件路径
python spam.py
Ключом к этому является размещение каталога, содержащего файл, вsys.pathвнутри. Таким образом, весь ваш импорт будет продолжать работать. Но именно поэтому вы не можете/не должны передавать путь к модулю, содержащемуся в пакете. так какsys.pathКаталог пакета может быть не включен, поэтому весь импорт будет относиться к каталогу, отличному от ожидаемого вами пакета.
4. Используйте -m для пакетов
Правильный способ выполнить пакет Python — использовать -m и указать имя запускаемого пакета.
python -m spam
он используется под капотомrunpy[5]. Для этого в своем проекте достаточно указать__main__.pyфайл, он будет рассматриваться как__main__воплощать в жизнь. И подмодули можно импортировать, как и любой другой модуль, поэтому вы можете выполнять на них различные тесты.
Я знаю, что некоторые люди любят писать пакет в пакетеmainподмодуль, то__main__.pyнаписано как:
from . import main
if __name__ == "__main__":
main.main()
Лично я не простужаюсь в одиночествеmainмодуль, но напрямую поместите весь соответствующий код в__main__.py, потому что мне кажется, что эти имена модулей избыточны.
(Аннотация: То есть автор не заботится о модулях "main" или "__main__" как о входных файлах, т.к. при выполнении нужны только имена их пакетов. Думаю, это также подразумевает, что входные модули не должны импортироваться другими модулями , яПредыдущая статья[6] Радикальнее, чем точка зрения автора, что даже в том случае оператор не должен быть написан. )
5. Каталог
определение__main__.pyМожет также распространяться на каталоги. Если вы посмотрите на пример, который привел к этому сообщению в блоге,python newsИсполняемый, потому что каталог новостей имеет__main__.pyдокумент. Этот каталог выполняется Python как путь к файлу.
Теперь вы можете спросить: «Почему бы просто не указать путь к файлу?» Честно говоря, есть одна вещь, которую нужно прояснить в отношении пути к файлу. 😄 В процессе релиза я могу просто написать инструкцию и запуститьpython news/announce.py, но точной причины существования этого механизма нет.
Плюс я могу изменить имя файла позже, и никто не заметит. Кроме того, я знаю, что код будет поставляться со вспомогательными файлами, поэтому имеет смысл поместить его в каталог, а не как отдельный файл.
Конечно, я мог бы также сделать его пакетом, используя -m, но в этом нет необходимости, так как сценарий анонса прост, я знаю, что он останется одним самодостаточным файлом (менее 200 строк, а тестовый модуль примерно одинаковая длина).
Кроме,__main__.pyДокументация очень проста.
import runpy
# Change 'announce' to whatever module you want to run.
runpy.run_module('announce', run_name='__main__', alter_sys=True)
Теперь, очевидно, вам придется иметь дело с зависимостями, но если ваш скрипт использует только стандартную библиотеку или помещает зависимые модули в__main__.pyРядом с ним (Аннотация: То есть каталог того же уровня), то достаточно!
(Аннотация: я думаю, что автор здесь немного «показушный», потому что предпосылкой этого метода написания является знание использования runpy, но, как и в предыдущей статье для запуска пакета с параметром -m, также используется runpy на нижнем уровне. Тем не менее, преимущества навыков ослепления также весьма очевидны, а именно__main__.pyНет необходимости импортировать модуль анонса, или он выполняется как основной модуль, и исходное отношение импорта зависимостей не будет уничтожено)
6. Запустите сжатый файл
Если у вас есть несколько файлов и/или зависимых модулей и вы хотите выпустить весь код как единое целое, вы можете использовать__main__.py, поместите его в сжатый файл и поместите каталог, в котором находится сжатый файл, в sys.path, Python запустит его для вас.__main__.pyдокумент.
# 将一个压缩包传给 Python
python app.pyz
В настоящее время люди обычно называют такие сжатые файлы расширением .pyz, но это чисто устаревшее и ни на что не влияет; конечно, вы также можете использовать расширение файла .zip.
Для упрощения создания таких исполняемых сжатых файлов стандартная библиотека предоставляетzipapp[7] Модуль. он будет генерировать для вас__main__.pyи добавляет строку shebang, поэтому вам даже не нужно указывать python, если вы не хотите указывать его в UNIX. Это хороший подход, если вы хотите перемещать кучу чистого кода Python.
К сожалению, запуск zip-файла таким образом возможен только в том случае, если весь код, содержащийся в zip-файле, написан на чистом Python. Выполнение zip-файлов не влияет на модули расширения (поэтому в setuptools естьzip_safe[8] причина флага). (Аннотация: модуль расширения модуля расширения, то есть файлы, отличные от Python, такие как C/C++)
Чтобы загрузить модули расширения, Python должен вызватьdlopen()[9], которая принимает путь к файлу, который, очевидно, не работает, когда путь к файлу включен в zip-файл.
Я знаю по крайней мере одного человека, который разговаривал с командой glibc о поддержке передачи буферов памяти в zip-файлы, чтобы Python мог считывать модули расширения в память и передавать их в zip-файл, но если мне не изменяет память, команда glibc не не согласен.
Однако не все надежды потеряны! вы можете использовать что-то вродеshiv[10], который объединяет ваш код и предоставляет__main__.pyдля обработки извлечения сжатых файлов, кэширования, а затем выполнения кода для вас. Хотя это и не такое идеальное решение, как решение на чистом Python, оно работает и в данном случае элегантно.
(Аннотация: Уровень перевода ограничен, и отклонения неизбежны. Я аннотировал часть контента, надеюсь, будет полезно прочитать. Пожалуйста, найдите и подпишитесь на «Python cat», чтобы прочитать больше качественных оригинальных или переведенных работ. )
Ссылка на ссылку
[0] придурковатый. руб/его и-удовлетворенный-вау…
[1] marketplace.visual studio.com/items?item N…
[3] Leatherskin.org/project/tow…
[4] да наркий.руб/почему-да-да ой…
[5] docs.Python.org/3/library/…
[6] Tickets.WeChat.QQ.com/Yes/1e и SR5NH…
[7] docs.Python.org/3/library/…
[8] setup tools.read the doc s.io/en/latest/ be...