python中用于运行两个脚本之一的命令行参数

2024-09-28 21:45:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我的包具有以下结构:

mypackage
|-__main__.py
|-__init__.py
|-model
  |-__init__.py
  |-modelfile.py
|-simulation
  |-sim1.py
  |-sim2.py

文件__main__.py的内容是

from mypackage.simulation import sim1

if __name__ == '__main__':
    sim1

因此,当我执行python -m mypackage时,脚本sim1.py运行。 现在我想向命令行添加一个参数,以便python -m mypackage sim1运行sim1.pypython -m mypackage sim2运行sim2.py

我试过以下方法:

import sys
from mypackage.simulation import sim1,sim2

if __name__ == '__main__':
    for arg in sys.argv:
        arg

但它运行两个脚本,而不是传入参数的脚本

在{}和{}中,我有以下代码

from mypackage.model import modelfile

print('modelfile.ModelClass.someattr')

Tags: namefrompyimport脚本参数modelif
3条回答

您只需使用模块名作为参数调用__import__,例如:

new_module = __import__(arg)

在你的循环中

例如,您的主程序名为example.py

import sys

if __name__ == '__main__':
    for arg in sys.argv[1:]:
        module=__import__(arg)
        print(arg, module.foo(1))

请注意sys.argv[0]包含程序名

你有你的sim1.py

print('sim1')

def foo(n):
    return n+1

和你的sim2.py

print('sim2')

def foo(n):
    return n+2

然后你可以打电话

python example.py sim1 sim2

输出:

sim1
sim1 2
sim2
sim2 3

你的代码没有达到你想要的效果。只是sim1实际上并没有调用函数;这样做的语法是sim1()

您可以使Python脚本将命令行中的随机字符串作为Python表达式进行计算,但这并不是解决此问题的安全或优雅的方法。相反,将字符串映射到内部函数,这些函数可能具有相同的名称,也可能不具有相同的名称。比如说,

if __name__ == '__main__':
     import sys
     for arg in sys.argv[1:]:
         if arg == 'sim1':
            sim1()
         if arg == 'mustard':
            sim2()
         if arg == 'ketchup':
            sim3(sausages=2, cucumber=user in cucumberlovers)
         else:
            raise ValueError('Anguish! Don\'t know how to handle %s' % arg)

如图所示,您在命令行上接受的符号不需要与要运行的函数的名称相对应。如果您希望成为这种情况,您可以将其简化为使用字典:

if __name__ == '__main__':
    import sys
    d = {fun.__name__: fun for fun in (sim1, sim2)}
    for arg in sys.argv[1:]:
        if arg in d:
            d[arg]()
        else:
            raise ValueError('Anguish! etc')

这里可能需要注意的是,您可以从命令行中准确地选择要让用户访问的Python符号,并且不允许其他符号泄漏。这将是一个安全问题(想想如果有人传入'import shutil; shutil.rmtree("/")'作为要运行的参数会发生什么)。这在精神上类似于避免eval的许多理由,你会发现谷歌很容易找到这些理由(如果你不熟悉的话,你可能应该这样做)

如果sim1是一个模块名,您只想在用户明确请求时导入它,这也不难做到;请参见importing a module when the module name is in a variable,但是您不能在脚本的前面部分import使用它

if __name__ == '__main__':
    import sys
    modules = ['sim1', 'sim2']
    for arg in sys.argv[1:]:
        if arg in modules:
            globals()[arg] = __import__(arg)
        else:
            raise ValueError('Anguish! etc')

但是一般来说,模块应该只定义函数,并让调用者在调用模块之后的某个时间决定是否以及何时运行它们

也许可以从另一个角度来研究像click这样的第三方库,它很容易让您将所选函数作为Python脚本的“子命令”公开,这与git的子命令initlog等类似

假设您有包含以下内容的文件


sim1.py

def simulation1():
    print("This is simulation 1")

simulation1()

main.py

import sim1

sim1.simulation1()

output

This is simulation 1
This is simulation 1

当您将sim1导入main.py并调用其函数simulation1时,This is simulation 1将被打印两次。 因为,simulation1sim1.py内调用,也在main.py内调用

如果希望在sim1.py中运行该函数,但不希望在导入sim1时运行,则可以将其放置在if __name__ == "__main__":


sim1.py

def simulation1():
    print("This is simulation 1")

if __name__ == "__main__":
    simulation1()

main.py

import sim1

sim1.simulation1()

output

This is simulation 1

相关问题 更多 >