Это плохая практика - вызывать аргументы в main () в Python - PullRequest
0 голосов
/ 08 ноября 2018

Если имя функции main() всегда должно быть пустым и иметь аргументы, вызываемые внутри самой функции, или допустимо иметь их в качестве входных данных для функции, например, main(arg1, arg2, arg3)?

Я знаю, что это работает, но мне интересно, если это плохая практика программирования. Извиняюсь, если это дубликат, но я не смог увидеть вопрос, на который конкретно ответили для Python.

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Следуя шаблону:

def main():
    ...stuff...

if __name__ == '__main__':
    main()

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

См .: https://setuptools.readthedocs.io/en/latest/setuptools.html#automatic-script-creation

Вы бы добавили к setup.py что-то вроде:

entry_points={
    'console_scripts': [
        'my_script = my_module:main'
    ]
}

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

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

Хорошая идея - разрешить импорт сценария и предоставить его функциональность как для повторного использования кода, так и для тестирования. Я бы порекомендовал что-нибудь из этого шаблона:

import argparse

def parse_args():
    parser = argparse.ArgumentParser()
    #
    # ... configure command line arguments ...
    #
    return parser.parse_args()

def do_stuff(args):
    #
    # ... main functionality goes in here ...
    #

def main():
    args = parse_args()
    do_stuff(args)

if __name__ == '__main__':
    main()

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

Этот пост был упомянут в комментариях: https://www.artima.com/weblogs/viewpost.jsp?thread=4829, который использует аргумент по умолчанию для main, чтобы разрешить внедрение зависимостей для тестирования, однако это очень старая запись блога (библиотека getopt была заменена с тех пор дважды), и я думаю, что эта модель лучше.

0 голосов
/ 08 ноября 2018

Я определенно предпочел бы, чтобы main принимал аргументы, а не обращался к sys.argv напрямую.

Это значительно упрощает повторное использование основной функции другими модулями Python.

import sys

def main(arg):
    ...

if __name__ == "__main__":
    main(sys.argv[1])

Теперь, если я хочу выполнить этот модуль как скрипт из другого модуля, я могу просто написать (в моем другом модуле).

from main_script import main

main("use this argument")

Если main использует sys.argv, это сложнее.

0 голосов
/ 08 ноября 2018

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

int main(char *argv[], int argc)

Для обозначения аргументов, переданных параметру. Однако в Python они доступны через модуль sys:

import sys

def main():
    print(sys.argv, len(sys.argv))

Но тогда вы могли бы расширить это так, чтобы вы проходили через argv и argc в вашу функцию python, подобно другим языкам yes:

import sys

def main(argv, arc):
    print(argv, arc)

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

Но давайте пока что забудем об argv / argc - почему вы хотите передать что-то в main. Вы создаете что-то вне main и хотите передать это через main. И это может произойти в двух случаях:

  1. Вы вызываете main несколько раз из других функций.
  2. Вы создали переменные вне main, через которые вы хотите пройти.

Пункт № 1 определенно плохая практика. main должен быть уникальным и вызываться только один раз в начале вашей программы. Если вам нужно вызывать его несколько раз, то код внутри main не принадлежит внутри main. Разделите это.

Может показаться, что пункт 2 имеет смысл, но тогда вы делаете это на практике:

def main(a, b):
    print(a, b)

if __name__ == '__main__':
    x = 4
    y = 5
    main(x, y)

Но тогда не являются ли x и y глобальными переменными? И хорошая практика предполагает, что они находятся в верхней части вашего файла (и множество других свойств - они постоянны и т. Д.), И вам не нужно передавать их в качестве аргументов.

...