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

Posted

技术标签:

【中文标题】在 Python 中,我可以调用导入模块的 main() 吗?【英文标题】:In Python, can I call the main() of an imported module? 【发布时间】:2013-01-08 03:22:21 【问题描述】:

在 Python 中,我有一个 module myModule.py,我在其中定义了一些函数和一个 ma​​in(),它需要一些命令行参数。

我通常从 bash 脚本调用这个 main()。现在,我想把所有东西都放在一个小的中,所以我想也许我可以把我简单的 bash 脚本变成 Python 脚本,然后放在包里。

那么,我该如何从 MyFormerBashScript.py 的 main() 函数 调用 myModule.py 的 main() 函数?我什至可以这样做吗?如何将任何参数传递给它?

【问题讨论】:

如果你已经导入了myModule,那么你应该可以调用myModule.main()。到目前为止,您尝试过什么? 我很担心输入参数,我通常从 shell 脚本传递。 subprocess 模块调用它有意义吗? 我想这会更容易,是的。 【参考方案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参数。

这里的技巧是检测您的模块何时被用作脚本;当您将 python 文件作为主脚本 (python filename.py) 运行时,没有使用 import 语句,因此 python 调用该模块 "__main__"。但是如果同样的filename.py 代码被视为一个模块(import filename),那么 python 会使用它作为模块名称。在这两种情况下,变量 __name__ 都已设置,并且针对该变量进行测试会告诉您代码是如何运行的。

【讨论】:

当然。但是输入参数呢?我使用argparse,所以当我从终端调用脚本时,我使用$ python myModule -a input_a -b input_b --parameterC input_c。它如何在 python 代码中工作?这是我通过简单搜索找不到的。 @RickyRobinson:扩展显示你可以同时拥有它;只需传入已解析或要解析的参数即可。 谢谢。您能否还指定哪些代码摘录属于哪个模块或脚本?它看起来比我一开始想的要麻烦得多。 @RickyRobinson:两个摘录都属于同一个模块;我已经明确表示了。【参考方案2】:

Martijen 的回答是有道理的,但它遗漏了一些对其他人来说似乎很明显但我很难弄清楚的关键内容。

在你使用argparse的版本中,需要在正文中有这一行。

args = parser.parse_args(args)

通常当您只在您编写的脚本中使用 argparse 时

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 脚本运行,你可以这样做

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

返回

X center: 7.0
Y center: 6.0

【讨论】:

这正是我所需要的——非常感谢您提供的有用的附录 这可能适用于 Python 2,但在 Python 3 中不再适用,无法调用模块的 main() 函数:AttributeError: module 'sqlacodegen' has no attribute 'main' @NaturalBornCamper 这是由于sqlacodegen 的编写方式。它是mainsqlacodegen.cli 中,并且被写入仅解析来自sys.argv[1:] 的args。您不能向main 提供参数。【参考方案3】:

这取决于。如果主代码受if 保护,如下所示:

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

那么不,你不能让 Python 执行它,因为你不能影响自动变量 __name__

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

import myModule

myModule.main()

即使模块使用__all__ 保护自己,这也有效。

from myModule import * 可能无法让您看到main,因此您确实需要导入模块本身。

【讨论】:

哦,好的,感谢您的澄清。我把所有东西都放在一个 main() 函数中,所以应该没问题。我更关心如何将输入参数传递给这个“第二个”主。有什么简单的方法吗? 当然:import sys; module.main(sys.argv); 这是关于访问__main__ 的一个很好的替代解释,它帮助了我,感谢@AaronDigulla 这是从另一个函数调用 main 的技巧:***.com/a/20158605/3244382【参考方案4】:

我也有使用argparse 的相同需求。 问题是argparse.ArgumentParser 对象实例的parse_args 函数默认从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函数。 稍后,要使用 main,您只需按照 Martijn 的说明进行操作即可。

【讨论】:

【参考方案5】:

我正在寻找的答案在这里得到了回答:How to use python argparse with args other than sys.argv?

如果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)

【讨论】:

【参考方案6】:

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

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])f(*a) => f(1,2,3) 您可以轻松地执行 myModule.main(sys.argv[1], "other value", 39) 或其他任何操作。【参考方案7】:

我遇到了这个问题,我无法调用文件Main() 方法,因为它被这些点击选项修饰,例如:

# @click.command()
# @click.option('--username', '-u', help="Username to use for authentication.")

当我删除这些装饰/属性时,我可以从另一个文件中成功调用 Main() 方法。

from PyFileNameInSameDirectory import main as task
task()

【讨论】:

以上是关于在 Python 中,我可以调用导入模块的 main() 吗?的主要内容,如果未能解决你的问题,请参考以下文章

python 中 使用 pyinstaller 打包的exe程序如何调用外部模块?

Python基础----import模块导入和包的调用

Python:在模块中编写函数以导入包

Python模块:如何防止导入新模块调用的模块

为啥在我导入模块时 Python 会运行我的模块,如何停止它?

是否可以根据用户输入导入模块和调用函数? [复制]