Используйте __main__.py

Original author: ZEEVO
  • Translation

Зачем нужен __init__.py знает, наверное, любой питонист, но что насчёт __main__.py? Я видел немало проектов либо рабочих, либо на Github, которые не используют это магический файл, хотя могли бы сделать свою жизнь проще. На мой взгляд, __main__.py это лучший способ для взаимодействия с питоновскими модулями, состоящими из нескольких файлов.


Но давайте сначала разберёмся: как большинство людей запускают свои скрипты на Python?


Однажды вы напишете программу, которую захотите использовать и как импортируемый модуль, и как инструмент запускаемый из командной строки. Вы скорей всего в курсе, как обычно поступают в этом случае:


if __name__ == '__main__':
    main(sys.argv)

Когда вы скармливаете скрипт интерпретатору, магическая глобальная переменная __name__ получает значение __main__. Таким образом мы узнаём, что это не импорт, а именно запуск. Например:


python myapp.py

И это прекрасно работает для одиночного файла.


Проблема


Но если вы похожи на меня, вы не захотите, чтобы всё ваше приложение теснилось в единственном файле. Разбиение логики по разным файлам упрощает редактирование и поддержку. Например:


.
├── README.me
├── requirements.txt
├── setup.py
└── src
    ├── __init__.py
    ├── client.py
    ├── logic.py
    ├── models.py
    └── run.py

Но пользователю, который склонировал проект из репозитория будет непонятно — какой из этих файлов главный? Неужели run.py? А может client.py? Где же искать знакомую строку if __name__ == '__main__'? Вот здесь-то __main__.py и способен проявить себя.


__main__.py


Файл __main__.py вызывается при запуске проекта с флагом модуля — -m. И это весьма удобно, если код предназначен и для использования в качестве модуля, и для запуска из консоли. Думайте об этом файле, как о месте куда можно класть всё, что вы обычно кладёте внутрь if __name__ == '__main__'. Давайте изменим проект из примера выше соответственно:


.
├── README.me
├── requirements.txt
├── setup.py
└── myapp
    ├── __init__.py
    ├── __main__.py
    ├── client.py
    ├── logic.py
    ├── models.py

И, вуаля! Теперь можно просто запускать проект как обычный модуль.


python -m myapp

__main__.py будет выполняться автоматически. Это идеальное место для размещения интерфейса командной строки и обработки входных аргументов!

Support the author
Share post

Comments 58

    +2
    что-то смысл немного ускользает.
    зачем такое при использовании как пакета?
    опять же есть __init__
    за уши удалось примерную стратегию применения притянуть, но несколько сомнительна
      +7
      Смотрите, вот есть у вас папка image_utils, в ней куча питоновских файлов, связанных с обработкой файлов. __init__.py делает папку модулем, который можно импортировать для других проектов.

      Допустим, вы хотите этот модуль не только импортировать, но и при случае использовать из командной строки как-нибудь так:

      python -m image_utils -convert=png someimage.jpg


      Так команда не сработает, даже если положить if __name__ == '__main__' внутрь __init__.py. Напишет:

      No module named image_utils.__main__; 'image_utils' is a package and cannot be directly executed

      Как быть? Кладёте внутрь папки __main__.py, куда добавляете обработку командной строки и всё начинает работать. Бонусом, что не надо больше постоянно писать if __name__ == '__main__'

        +6
        init.py делает папку модулем, который можно импортировать для других проектов.

        Начиная с Python 3.3 __init__.py для этого не нужен.


        Допустим, вы хотите этот модуль не только импортировать, но и при случае использовать из командной строки как-нибудь так:

        Нужно каждый раз писать python -m, неудобно же. Удобнее и проще регистрировать скрипты.


        Я думаю, так мало людей использует __main__.py как раз из-за того, что setup.py представляет более удобный функционал.

          +5
          Никогда не использовали python -m http.server и python -m compileall .?
            +1
            python -m venv /path/to/venv туда же. Очень удобно, имхо.
              0

              Использовал, удобно.

                +2
                Никогда не использовали python -m http.server и python -m compileall .?

                Использовал, конечно. А вы никогда не использовали jupyter notebook? По-моему, удобнее, чем python -m jupyter notebook.

              +1
              но тогда получается теперь нельзя запускать по человечески просто нужный файл.
              без всякого этого -m и python
                0

                Ответьте на вопрос — а нужно ли это ???
                Если очень хочется, ну, или сделайте симлинк на этот main.py из /usr/local/bin, или положите туда тупой двухстрочный шелл-скрипт, который за Вас сделает python -m module-name @$

                  0
                  симлинк на main при таком варианте ничем не поможет.
                  а шелл-скрипт — замечательное в своей оптимальности решение.
                    0

                    Ага, больше врапперов богу врапперов.
                    А Вы не подумали, что просто положив скрипт на питоне куда-либо — Вы убиваете всю возможность его версионировать. И доставлять через родное для питона окружение (pip install). Все равно по уму тогда нужно либо начать писать свои пакеты нативные для операционной системы, т.к. упаковывать python скрипты в deb, rpm — это вот все. И правильно прописывать зависимости от других пакетов (поверьте, это сложно). Либо использовать какие-то внешние способы доставки (а-ля ansible).


                    Касательно примеров вызова python -m против сразу вызов скрипта — смотрите ansible, сам pip, j2 из j2cli и пр. консольные утилиты, написанные на Питоне. Можете даже запилить сравнение, что они делают, чтобы быть доступными для пользователя по "простой" команде. И, да, в половине случаев, если не больше — Вы увидите враппер (может не на Шелл, но на питоне).

                      0
                      pip и пакетные менеджеры с удовольствием будут работать с нормальными питоновоскими скриптами.
                      а зачем тут вобще врапперы?
                      просто нужный файлик делаем исполняемым.
                      инерпретатор указываем env python (env python3)
                      и все замечательно запускается, версионифецируется
                        0

                        Нет. Неверно. Тот же pip — он устанавливается в систему по определенному пути (/usr/bin/pip), что не оставляет возможности иметь ДВА pip'а в системе. В случае с python3 выкрутились попросту устанавливая его в /usr/bin/pip3, но все равно при определенных обстоятельствах основной указывает не туда, куда надо. Более того — то, что по этому пути это не полноценный pip, а враппер:


                        #!/usr/bin/python3
                        # EASY-INSTALL-ENTRY-SCRIPT: 'pip==19.1.1','console_scripts','pip3.7'
                        __requires__ = 'pip==19.1.1'
                        import re
                        import sys
                        from pkg_resources import load_entry_point
                        
                        if __name__ == '__main__':
                            sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
                            sys.exit(
                                load_entry_point('pip==19.1.1', 'console_scripts', 'pip3.7')()
                            )

                        о чем выше я и сообщил.


                        При использовании его через python3 -m pip — есть гарантия, что он всегда вызывается в нужном окружении.

                        0
                        И, да, в половине случаев, если не больше — Вы увидите враппер (может не на Шелл, но на питоне).

                        Вы ведь в курсе, что никто врапперы для питоновских модулей вручную не пишет, а они генерируются автоматически по записи в entry_points?

                          0

                          Прикол в том, что эти врапперы могут отнимать целых полсекунды на запуск из-за импорта модуля pkg_resources, поэтому я иногда пишу врапперы вручную на шелле, потому что они тупо быстрее)

                            0

                            А не, я слегка облажался: долгий импорт pkg_resources появляется, если устанавливать модуль с опцией --editable, а без неё всё нормально. К несчастью, --editable мне очень часто нужен)

                  0
                  и по прежнему не понимаю, как мне просто проимпортировать пакет теперь.
                +2
                Очень просто, а главное полезно, спасибо
                  +6

                  Гораздо удобнее прописать в setup.py все точки входа. И тогда не нужно запускать интерпретатор с ключом -m, так как все точки входа будут обычными консольными командами. if __name__ == '__main__' в этом случае тоже не нужен.

                    0

                    Ага, больше логики в setup.py.
                    Я лично считаю упомянутую Вами практику порочной. Не вижу бенефитов от точек входа в setup.py, кроме путаницы, если нужно установить один модуль в два и более интерпретатора.

                      +1

                      О какой логике речь? Мне кажется, вы не совсем поняли, что я имею в виду. Нужно лишь дописать в setup.py что-то вроде:


                      setuptools.setup(
                          ...
                          entry_points={
                              'console_scripts': [
                                  'my_script=my_module:main',
                              ],
                          },
                          ...

                      И после установки через pip у вас появится общесистемная команда my_script. И точка входа main может находиться где угодно в соответствии с логикой кода, не обязательно в __main__.py.


                      Если нужно установить один модуль в несколько интерпретаторов, то это значит, что у вас несколько виртуальных окружений. Соответственно, какое окружение активно, такой скрипт и будет вызван.


                      И это не порочная практика, а повсеместная и рекомендованная Python Packaging Authority. Посмотрите в bin/ своего виртуального окружения. И взгляните на официальный пример проекта от PyPA.

                        0

                        Я про эту штуку выше и писал — про врапперы. По ходу они pip'ом сами формируются и устанавливаются. ОК. Не самый плохой вариант. Уж всяко лучше, чем свои скрипты закидывать в /usr/local/bin...

                    +3

                    Этот файл придётся исключать из coverage при тестировании, ведь импорт модуля __main__.py приведёт к запуску программы. Это приведёт к тому, что в __main__.py будет очень простой код, например код ниже, чтобы этот код не требовал покрытия тестами. В итоге, мы вернёмся к if __name__ == '__main__'


                    import run
                    run.main()
                      +3
                      Да, это так, вы же в __init__.py бизнес логику не прописываете?
                        0

                        Видел очень много проектов, в которых в __init__.py написано очень много логики.

                          +4
                          Смотря какая логика, если бизнес то это плохо, не ориентируйтесь на них. Если именно логика импорта, то это нормально, например, если модуль содержит кроме питоновского кода, ещё и плюсовый/сишный, то логика импорта может быть сложной и платформеннозависимой.
                            +2

                            И что? Миллион мух не может ошибаться? То что все говнячат — это, во-первых, не означает, что это нормально, а, во-вторых, отвечайте сами за свой продукт.
                            В третьих, наличие всякой хитрой логики, что в setup.py, что в init.py — за это надо руки отрывать

                          +2
                          импорт модуля main.py приведёт к запуску программы

                          Нет, если в __main__.py точно так же запускать программу внутри if __name__ == '__main__'

                            –1

                            если называние модуля __main__.py, то ваша проверка лишена смысла: модуль и так будет всегда называться __main__ (по названию файла), как бы вы его не запускали или импортировали.

                              +1
                              Всё там нормально будет.
                              Попробуйте
                                0

                                Спасибо, век живи — век учись

                                0
                                Проверка пройдёт только при запуске напрямую (python my_package/__main__.py) или через -m (python -m my_package). Если __main__.py импортируется из другого модуля, его __name__ будет my_package.__main__.
                            +1

                            Считаю что оформлять приложения в виде модулей это плохая идея, вместо этого использую *.py в корне проекта для приложений и подкаталоги для библиотек. Так сразу видно что можно запускать напрямую без поиска __main__.py, не нужно никаких python -m для запуска, не создаётся искусственных связей между приложениями и библиотеками, которые потом мешают расширять проект (т.е. добавлять новые приложения, разбивать и объединять библиотеки, разбивать весь репозиторий). Примерная структура одного из текущих проектов:


                            ├── mycoolservice-updater.py    # backend демон обновляющий данные 
                            ├── mycoolservice-*.py          # какие-то ещё вспомогательные backend утилиты
                            ├── mycoolservice-webapp.py     # веб-приложение
                            ├── mycoolservice               # основная логика, используется всеми 
                            │   ├── __init__.py
                            │   └── *.py
                            └── mycoolserviceweb            # логика специфичная для веб приложения, вьюхи
                                ├── __init__.py
                                └── *.py

                            А __main__.py я бы оставил только для особой функциональности модулей типа python -m json.tool

                              +1

                              И потом получать геморрой с публикацией всех этих скриптов на PyPI?

                                0

                                Никакого геморроя. Много кто так и делает, см., например, ansible и black.

                                  0

                                  Ок, я забыл про эту фичу (но всё равно не вижу смысла так делать)


                                  setup(
                                      # ...
                                      scripts=[
                                          'bin/ansible',
                                          'bin/ansible-playbook',
                                          'bin/ansible-pull',
                                          'bin/ansible-doc',
                                          'bin/ansible-galaxy',
                                          'bin/ansible-console',
                                          'bin/ansible-connection',
                                          'bin/ansible-vault',
                                          'bin/ansible-config',
                                          'bin/ansible-inventory',
                                      ],
                                      # ...
                                  )
                                +1

                                Оформлять приложения в виде модулей это наиболее правильная идея, которая может возникнуть в рамках инфраструктуры и экосистемы питона. Типичный пример. Мне часто приходится работать с несколькими версиями питона на одной машине. И речь не про 2 vs 3, а про версии даже внутри одной линейки. Если скрипт запускать как исполняемый файл, то велика вероятность, что он запуститься не тем интерпретатором. В случае вызова python3.6 -m имя_модуля такой двусмысленности нет. И более того — если интерпретатор вырубается на отсутствующий модуль, то будет понятно, что делать.

                                  +1

                                  Скрипт можно запускать точно так же, причём на 1 аргумент короче.

                                    0

                                    Сомнительное преимущество. Здесь скорее дело в том, как "скрипт" установлен — как отдельно стоящий скрипт в /usr/bin и аналогах или как полноценный питон модуль.
                                    В любом случае вопрос ещё в том, как грамотно обернуть питон-модуль — или в pypi, или в нативный пакет для операционной системы. Меня, честно говоря, очень расстраивает, когда setup.py приносит в систему то, что не ожидается изначально. Примеров масса.

                                      0

                                      Если ставить пакеты в виртуальные окружения, то всё, что пакеты приносят, остаётся в директории виртуального окружения и проблем нет. Всегда можно снести и поставить пакеты заново, если что-то пошло не так.


                                      Ставить как нативные для системы особого смысла нет. Лишняя возня со сборкой, а премуществ никаких особо и нет.

                                        0

                                        Ну, чего все такие категоричные? Я вообще ума приложить не могу.
                                        Часть вещей — действительно имеет смысл ставить в venv. Даже тот же хваленый airflow. Ansible — тоже скорее да, чем нет. Пользоваться, конечно, становится неудобно, но для сервисов это не проблема — обернул в сервис и понеслась. Часть вещей — не имеет смысла ставить в venv. Вообще — это какие-то общесистемные вещи, например, пакет для управления docker. Или еще что-то подобное. Ну, и опять же — мой тезис, что setup.py в теории может любую дрянь притащить в систему. Мне кажется, что не нужно пытаться противопоставлять средства нативной доставки приложений (deb/rpm в первую очередь) и pip, а все-таки пытаться их дружить. Благо в первых все-таки есть средства рекурсивной валидации зависимостей — для Питон-экосистемы это прям больное место.

                                          0

                                          Да, может, с категоричностью я палку перегнул, наверное. Просто сужу с точки зрения задач, которые именно я решал. Спорить не буду, я уже ниже написал, что каждый инструмент хорош, когда его используют по назначению.


                                          Насчёт дряни — это к мейнтейнеру. Скрипты deb-пакетов тоже могут дел натворить. Или вы плавно ведёте к экзотике вроде Nix/Guix?

                                          0
                                          Ставить как нативные для системы особого смысла нет.

                                          Не будь смысла, опакечивание Python модулей не было бы распространено повсеместно: https://repology.org/projects/?search=python%3A


                                          Лишняя возня со сборкой, а премуществ никаких особо и нет.

                                          Возня со сборкой получается когда пакеты собираются вне системного репозитория, и зачастую не могут найти нужные нативные библиотеки и компилятор. А потом получается ещё больше возни, потому что системные библиотеки обновляются или удаляются, не зная ничего о том что от них зависят питоновские модули, в итоге ломая последние. Нет, система управления пакетами должна быть единой для всего.

                                            0
                                            Не будь смысла, опакечивание Python модулей не было бы распространено повсеместно:

                                            Я, возможно, потерял нить разговора, но речь шла о собственных проектах. Не берусь судить о всех, но лично мне проще устанавливать пакеты через pip прямо из репозитория git, чем поддерживать пакеты и держать репозитории для разных операционных систем. Чтоб не компилировать каждый раз бинарные модули, можно держать один репозиторий с wheel-файлами. Это удобнее, если, например, разработка ведётся под MacOS, на серверах Ubuntu, а в докере вообще какой-нибудь Alpine.


                                            Возня со сборкой получается когда пакеты собираются вне системного репозитория, и зачастую не могут найти нужные нативные библиотеки и компилятор.

                                            Допускаю, что такое возможно, хотя я с таким не сталкивался. Ещё раз замечу, что дискуссия ведётся в контексте организации своего проекта, так как статья была об этом. А не о преимуществах и недостатках разных способов дистрибуции вообще.


                                            У меня же сложилось такое мнение (не обязательно верное). Если пакет зависит от каких-то нативных библиотек, то ничто не мешает проверять наличие этих библиотек при компиляции и установке. Или вовсе помещать их в wheel-файл. Пакеты под линукс следует собирать не на коленке, а в официальном докере manylinux1, что даст какую-то уверенность в работоспособности. Мне кажется, что перечисленные проблемы — это не проблема способа дистрибуции, а проблема мейнтейнера. Вот, тот же numpy. Отлично ставится через pip, хотя насквозь бинарный.


                                            С другой стороны, если пользоваться установленными в систему пакетами, то как работать с виртуальными окружениями? Да, на сервере это нечасто нужно, чтоб стояло несколько окружений. Но на машине разработчика — очень даже.


                                            В общем, всё средства хороши на своём месте.

                                              0

                                              Мы тоже pip'ом ставим из гита. Это действительно удобно и способствует быстрой разработке.
                                              Но нормальные пакеты (в первую очередь deb/rpm, во вторую pypi/wheel) становятся жизненно необходимы, если этими модулями будут пользоваться другие люди. Условно — решил проблему — поделись с сообществом. Ничего там сверхсекретного в твоей разработке скорее всего нет. Тот же ML — там ноу-хау в моделях (т.е. весовых коэффициентах), а не во фреймворках обучения.


                                              Касательно дружить — да, все верно, что setup py ничего не знает о системе, куда будет установлен. Скажем, Вам нужна библиотека для работы с БД Postgres. В разных дистрибутивах она может быть разной версии, лежать по разным путям и устанавливаться из пакетов с разными именами. Унификации здесь нет и в ближайшее время не предвидится. В результате ставя питон-пакет из официального репозитория ОС — эти зависимости подтягиваются, т.к. мейнтейнеры их описали и гарантируют их. А ставя через pip — либо как повезет, либо там будет дичь в setup.py.


                                              Насчёт дичи в deb/rpm — да, она тоже возможна, но мейнтейнеры официальных репозиториев такое не пропустят, т.е. проблема возможна только со сторонними репами

                                          0
                                          или в pypi, или в нативный пакет для операционной системы

                                          Я ни разу не встречал проблем с опакечиванием питоновых приложений хоть с PyPI, хоть напрямую с GitHub — setup.py делает всё что нужно и создаёт исполняемые файлы в bin — это работает и c __main.py__, и со скриптами.


                                          Проблема, повторюсь, возникает при работе с репозиторием, потому что с __main__.py скриптов в нём не будет и чтобы пользоваться приложением из чекаута репозитория вам придётся, по сути, сначала руками распарсить entry_points из setup.py, или искать __main__.py.

                                    +1
                                    И это прекрасно работает для одного проекта или как запуск некоторых модулей вполне себе хорошее решение:
                                    `python -m venv`
                                    `json.tool` — выше написали :)
                                    А вот если это действительно приложение, да еще и не одно вращается на сервере или более того в контейнерах, то использование __main__.py или просто run.py даже вредит. Когда приходит OOM Killer, мы не видим какое конкретно приложение было «убито», а только python. Стараемся использовать шебанг в service_name.py или иное указываем в README.md.
                                      0

                                      Очень спорный аргумент
                                      В случае оом — лучше настроить эти питоновские скрипты как юниты системди и указать им политику рестарта...

                                        0
                                        Способ реализации запуска/перезапуска приложения это инфраструктурный вопрос и легко решаем. Самостоятельно перезапущенное приложение показатель ненормальной работы сервиса и с этим надо разбираться. Представим ситуацию, что количество пользователей возросло, а мы используем по-прежнему сервер с 2ГБ ОЗУ. Мы получим ООМ периодически и systemd будет это отрабатывать. И в логах периодически будем видеть
                                        [1395278.160214] python invoked oom-killer: gfp_mask=0xd0, order=0, oom_score_adj=996

                                        Для одного-двух проектов это легко отыскать и исправить проблему. Если же больше, то иди-разберись какое из 30+ приложений упало. А если это еще приложение в kubernetes/swarm со скейлом 3 (мой вариант), то совсем не радостно становится искать логи упавшего сервиса. А еще надо как то в тикете описать что нужно править :)
                                          0

                                          Вы несомненно правы, что искать по логам ООМкиллера не очень удобно. Но это очень похоже на борьбу не с причиной проблемы, а со следствием. Смотрите.


                                          1. В случае системд юнитов, почему я вообще о них заговорил, часть головной боли по задаче "понять, что отвалилось" перекладывается на системд. Ес-но, это не полное решение. Рестарт — это такая же затычка и Вам решать нужно ли его ставить (как будто в кубе приложения автоматически не перезапускаются в случае сбоя).
                                          2. Обвесить все мониторингом. Вообще все. Любое долгоживущие приложение должно быть под мониторингом. Упало? Получили Алерт и это увидели. С пакетными заданиями сложнее, но тоже реально. В этом кейсе становится сложнее понять, если отвалился внутренний компонент приложения, а не его основная часть, но тоже нужно смотреть по ситуации — наверняка есть решение.
                                          3. В идеальном мире — оом быть не должно. Разработчики должны ставить сайзинг на все свои решения. С небольшим, но запасом. И в лучшем случае ООМ никогда не будет, но ценой наличия незадействованных ОЗУ.
                                            0
                                            Надо было начать с того, что я не разработчик. Я устраняю следствие, а после пишу тикет с описанием проблемы и ссылкой на логи. Далее устраняют причины.

                                            2. Не получится. На некоторых приложениях настроен kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale.
                                            3. Запас есть, но он тоже ограничен.
                                            Кубер при скейлинге так же может упереться в ограничение по количеству подов на рабочей ноде (110 штук, такое у нас пока не возможно) или в лимит ОЗУ прописанный в деплоях. Период опроса мониторинга 15 секунд и когда словишь «эффект домино», то несколько сервисов могут остановится в этом промежутке и на дашборде не будет видно в какой последовательности это произошло. Единственное место это логи ОС, но там раньше было по 2-4 записи подряд на подобии указанной мной в предыдущем комменте. Т.е. какой процесс был прибит ООМ, а какой был остановлен автоскейлером приходилось искать по тоннам логов потому, что stack trace в syslog указывал на python, а не конкретное приложение.
                                              0

                                              С одной стороны, понимаю Вашу боль, с другой — повторюсь, что в одиночку эту проблему не решить, нужно кооперироваться с разработчиками, повышать культура кодирования.


                                              1. Не получится. На некоторых приложениях настроен kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale.

                                              В условиях ограниченных ресурсов. Ну, а что — молодцы! К сожалению, не вижу Вашей инфры, поэтому не могу дать аргументированное мнение, но выглядит прям странно.


                                              Период опроса мониторинга 15 секунд и когда словишь «эффект домино», то несколько сервисов могут остановится в этом промежутке и на дашборде не будет видно в какой последовательности это произошло

                                              последовательность нужна для пост-мортема, а не для починить "прямо сейчас". Очень странная у Вас конфигурация, прям скажу, потому что кубер ведь должен мочь перезапускать поды. А если даже это не так — у Вас же мониторинг на прометеусе наверняка есть? Эластик есть, куда приложения логи отправляют?


                                              Т.е. какой процесс был прибит ООМ, а какой был остановлен автоскейлером приходилось искать по тоннам логов потому, что stack trace в syslog указывал на python, а не конкретное приложение.

                                              ну, и чем лог syslog'а поможет в случае, если отвалился не python процесс с pid=1, а какой-то дочерний? Вы просто сделали несколько слоев абстракций (k8s -> docker -> linux) и пытаетесь как будто использовать не тот инструмент исследования не для той задачи.

                                                0
                                                последовательность нужна для пост-мортема, а не для починить «прямо сейчас». Очень странная у Вас конфигурация, прям скажу, потому что кубер ведь должен мочь перезапускать поды.

                                                пост-мортем используется для локализации проблемы со стороны разработчиков то же. Вроде я не писал про невозможность перезапуска подов? Кубер с этим очень хорошо справляется.
                                                Я писал про цепочку падения микросервисов. Они восстанавливаются сразу же, но это не есть хорошо. По этому пишу пост-мортем, делаю тикет, туда всю инфу пишу и уже разработка разрабатывает :) Так что в одиночку я ничего не устраняю. У меня на это гораздо больше времени уйдет, чем у человека который писал этот микросервис.

                                                ну, и чем лог syslog'а поможет в случае, если отвалился не python процесс с pid=1, а какой-то дочерний?

                                                Jun 17 09:33:06 slave-1 kernel: [ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name
                                                Jun 17 09:33:06 slave-1 kernel: [25793] 0 25793 394 62 4 0 0 http_server
                                                Jun 17 09:33:06 slave-1 kernel: [25851] 0 25851 1911 1488 7 0 0 python
                                                Jun 17 09:33:06 slave-1 kernel: Memory cgroup out of memory: Kill process 25851 (python) score 1459 or sacrifice child


                                                видно какой сервис отвалился. Не просто python, а http_server
                                        0
                                        Стараемся использовать шебанг в service_name.py или иное указываем в README.md.

                                        Просто зарегистрируйте точку входа в setup.pyи скрипт запуска с шебангом будет создан автоматически. А для Windows и вовсе exe-файл, если вдруг вам Windows нужен.

                                        0
                                        Мне, как начинающему разрабочику на python, тяжело от таких статей. 7 разных мнений в комментариях, до конца непонятно — как и когда использовать __main__. Причём в официальной документации инфы об этом настолько мало, что просто страшно.
                                          +1

                                          Официальная документация рекомендует использовать setuptools для модулей, а те — регистрировать точки входа в setup.py. Инфы не мало, просто она неочевидным образом распределена. Если только начинаете разбираться, то посмотрите на официальный пример модуля. Там много комментариев, и охвачены разные аспекты: от пакетирования до тестирования.


                                          __main__.py имеет смысл использовать, если мы не делаем полноценный модуль, который будем устанавливать, а просто сделали модуль в виде папочки или zip-архива и так и запускаем.

                                          0
                                          Простите, но разве это не сработает?
                                          chmod +x ./myapp/__main__.py
                                          ./myapp/__main__.py
                                          
                                            +1

                                            Это плохой подход. Вот причины:


                                            • нужно знать путь к модулю (а мало ли в какое окружение он будет установлен),
                                            • нужно прописать shebang,
                                            • это не работает в Windows, например.

                                            Регистрация точек входа в setup.py и __main__.py лишены этих недостатков.

                                          Only users with full accounts can post comments. Log in, please.