在Python中,我可以调用导入模块的main()吗?


85

在Python中,我有一个模块myModule.py,其中定义了一些函数和一个main(),它接受了一些命令行参数。

我通常从bash脚本中调用此main()。现在,我想将所有内容放入一个小包装中,因此我想也许可以将我简单的bash脚本转换为Python脚本并将其放入包装中。

因此,实际上如何MyFormerBashScript.py的main()函数调用myModule.py的main()函数?我什至可以那样做吗?如何传递任何参数


如果已导入myModule,则应该可以调用myModule.main()。你试过什么了?
Marius

我担心输入参数,通常是从Shell脚本传递过来的。
里奇·罗宾逊

subprocess模块调用它有意义吗?
BenDundee 2013年

我想这会容易些,是的。
Ricky Robinson

Answers:


114

这只是一个功能。导入并调用它:

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参数。

这里的技巧是检测何时将模块用作脚本。当您运行python文件作为主脚本(python filename.py)时,未import使用任何语句,因此python调用该模块"__main__"。但是,如果将相同的filename.py代码视为模块(import filename),则python会将其用作模块名称。在这两种情况下,__name__都设置了变量,并针对该变量进行测试,以告诉您如何运行代码。


3
当然。但是输入参数呢?我使用argparse,所以当我从终端调用脚本时,我会这样做$ python myModule -a input_a -b input_b --parameterC input_c。它如何在python代码中工作?这就是我从简单的搜索中找不到的内容。
瑞奇·罗宾逊

@RickyRobinson:展开显示可以同时使用两种方法;只需传入已解析或将要解析的参数即可。
马丁·彼得

1
谢谢。您还可以指定哪个代码摘录属于哪个模块或脚本吗?它看起来比我一开始想的要麻烦。
瑞奇·罗宾逊

@RickyRobinson:两个摘录在同一个模块中属于同一类;我已经明确指出了这一点。
马丁·皮特斯

42

马丁(Martijen)的答案是有道理的,但是它缺少了一些关键的东西,对其他人来说似乎很明显,但是我很难弄清楚。

在使用argparse的版本中,您需要在主体中包含此行。

args = parser.parse_args(args)

通常,当您仅在脚本中使用argparse时,您只需编写

args = parser.parse_args()

和parse_args从命令行中找到参数。但是在这种情况下,main函数无法访问命令行参数,因此您必须告诉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脚本运行,则可以执行

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

哪个返回

X center: 7.0
Y center: 6.0

4
这正是我需要的-非常感谢您提供有用的附录
HFBrowning

这可能适用于Python 2,但在Python 3中不再起作用,无法调用模块的main()函数:AttributeError: module 'sqlacodegen' has no attribute 'main'
NaturalBornCamper

24

这取决于。如果主代码受的保护,if例如:

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

那么不,您不能让Python执行该操作,因为您无法影响自动变量__name__

但是,当所有代码都在一个函数中时,便可以。尝试

import myModule

myModule.main()

即使模块使用来保护自己,它也可以工作__all__

from myModule import *可能main对您不可见,因此您确实需要导入模块本身。


好的,谢谢您的澄清。我把所有东西都放在main()函数中,所以应该没问题。我更关心如何将输入参数传递给此“第二个”主要对象。有任何简单的方法吗?
Ricky Robinson

当然:import sys; module.main(sys.argv);
Aaron Digulla

__main__@AaronDigulla,这是关于访问的一个很好的替代解释,这对我有所帮助,谢谢
Charlie G

这是从另一个函数调用主函数的技巧:stackoverflow.com/a/20158605/3244382
PatriceG

3

我也有同样的需求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:])

关键是将args传递给parse_args函数。稍后,使用Martijn讲的就可以了。


3

我在搜索的答案在这里得到了答案:如何将python argparse与sys.argv以外的args一起使用?

如果main.pyparse_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)

然后,您可以在另一个python脚本中调用main()和解析参数parser.parse_args(['--input', 'foobar.txt'])

# 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)

0

假设您也尝试传递命令行参数。

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:])

谢谢。我实际上是使用argparse而不是sys.argv。在这种情况下会如何变化?另外,从外部脚本中,我只想传递用户输入的几个输入参数,而内部脚本的其他输入参数(myModule.py)由我进行硬编码。
瑞奇·罗宾逊

如果不看代码本身,很难回答具体问题。通常,您只要传递任何参数即可。在*解包的数组f(a) => f([1,2,3])VSf(*a) => f(1,2,3) 你可以很轻松地做myModule.main(sys.argv[1], "other value", 39)或什么的。
agoebel 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.