В Python я могу вызвать main() импортированного модуля?

В Python у меня есть модуль myModule.py, где я определяю несколько функций и main(), что требует нескольких аргументов командной строки.

Обычно я называю это main() от bash script. Теперь я хотел бы поместить все в небольшой пакет, поэтому я подумал, что, возможно, я могу превратить свой простой bash script в Python script и поместить его в пакет.

Итак, как мне на самом деле вызвать функцию main() myModule.py из функции main() MyFormerBashScript.py? Могу ли я это сделать? Как передать любые аргументы на него?

Ответ 1

Это просто функция. Импортируйте его и назовите его:

import myModule

myModule.main()

Если вам нужно проанализировать аргументы, у вас есть два варианта:

  • Разделите их в main(), но передайте sys.argv в качестве параметра (весь код ниже в том же модуле myModule):

    def main(args):
        # parse arguments using optparse or argparse or what have you
    
    if __name__ == '__main__':
        import sys
        main(sys.argv[1:])
    

    Теперь вы можете импортировать и вызывать myModule.main(['arg1', 'arg2', 'arg3']) из другого другого модуля.

  • Иметь main() принимать параметры, которые уже разобраны (снова весь код в модуле myModule):

    def main(foo, bar, baz='spam'):
        # run with already parsed arguments
    
    if __name__ == '__main__':
        import sys
        # parse sys.argv[1:] using optparse or argparse or what have you
        main(foovalue, barvalue, **dictofoptions)
    

    и импортировать и вызывать myModule.main(foovalue, barvalue, baz='ham') в другом месте и передавать аргументы python по мере необходимости.

Трюк здесь заключается в том, чтобы определить, когда ваш модуль используется как script; когда вы запускаете файл python в качестве основного оператора script (python filename.py) no import, поэтому python вызывает этот модуль "__main__". Но если этот же код filename.py обрабатывается как модуль (import filename), тогда python использует это вместо имени модуля. В обоих случаях устанавливается переменная __name__, и тестирование на это указывает вам, как был выполнен ваш код.

Ответ 2

Это зависит. Если основной код защищен if, как в:

if __name__ == '__main__':
    ...main code...

то нет, вы не можете заставить Python выполнить это, потому что вы не можете влиять на автоматическую переменную __name__.

Но когда весь код находится в функции, он может быть способен. Попробуйте

import myModule

myModule.main()

Это работает, даже если модуль защищает себя с помощью __all__.

from myModule import * может не сделать main видимым для вас, поэтому вам действительно нужно импортировать сам модуль.

Ответ 3

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

В версии, где вы используете argparse, вам нужно иметь эту строку в основном теле.

args = parser.parse_args(args)

Обычно, когда вы используете argparse только в script, вы просто пишете

args = parser.parse_args()

и parse_args найти аргументы из командной строки. Но в этом случае основная функция не имеет доступа к аргументам командной строки, поэтому вы должны сказать argparse, что аргументы.

Вот пример

import argparse
import sys

def x(x_center, y_center):
    print "X center:", x_center
    print "Y center:", y_center

def main(args):
    parser = argparse.ArgumentParser(description="Do something.")
    parser.add_argument("-x", "--xcenter", type=float, default= 2, required=False)
    parser.add_argument("-y", "--ycenter", type=float, default= 4, required=False)
    args = parser.parse_args(args)
    x(args.xcenter, args.ycenter)

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

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

python ./mytest.py -x 8
python ./mytest.py -x 8 -y 2
python ./mytest.py 

который возвращает соответственно

X center: 8.0
Y center: 4

или

X center: 8.0
Y center: 2.0

или

X center: 2
Y center: 4

Или, если вы хотите запустить с другого python script, вы можете сделать

import mytest
mytest.main(["-x","7","-y","6"]) 

который возвращает

X center: 7.0
Y center: 6.0

Ответ 4

Мне тоже нужно было использовать argparse. Вещь parse_args функция экземпляра объекта argparse.ArgumentParser неявно принимает свои аргументы по умолчанию от sys.args. Работа вокруг, следуя линии Martijn, состоит в том, чтобы сделать это явным, поэтому вы можете изменить аргументы, которые вы передаете на parse_args как желание.

def main(args):
    # some stuff
    parser = argparse.ArgumentParser()
    # some other stuff
    parsed_args = parser.parse_args(args)
    # more stuff with the args

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

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

Ответ 5

Предполагая, что вы также пытаетесь передать аргументы командной строки.

import sys
import myModule


def main():
    # this will just pass all of the system arguments as is
    myModule.main(*sys.argv)

    # all the argv but the script name
    myModule.main(*sys.argv[1:])

Ответ 6

Ответ, который я искал, ответил здесь: Как использовать python argparse с аргументами, отличными от sys.argv?

Если main.py и parse_args() записаны таким образом, тогда синтаксический анализ может быть выполнен красиво

# main.py
import argparse
def parse_args():
    parser = argparse.ArgumentParser(description="")
    parser.add_argument('--input', default='my_input.txt')
    return parser

def main(args):
    print(args.input)

if __name__ == "__main__":
    parser = parse_args()
    args = parser.parse_args()
    main(args)

Затем вы можете вызвать main() и проанализировать аргументы с помощью parser.parse_args(['--input', 'foobar.txt']) к нему в другом python script:

# temp.py
from main import main, parse_args
parser = parse_args()
args = parser.parse_args([]) # note the square bracket
# to overwrite default, use parser.parse_args(['--input', 'foobar.txt'])
print(args) # Namespace(input='my_input.txt')
main(args)