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 sim1sim1.py运行,python -m mypackage sim2运行sim2.py

我试过以下方法:

import sys
from mypackage.simulation import sim1,sim2
if __name__ == '__main__':
for arg in sys.argv:
arg

但它运行两个脚本,而不是在参数中传递的脚本。

sim1.pysim2.py我有以下代码

from mypackage.model import modelfile
print('modelfile.ModelClass.someattr')

你可以简单地用模块名称作为参数调用__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.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会被打印 2 次。 因为,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

你的代码没有做你想要它做的事情。 只是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是仅在用户明确请求时才要导入的模块名称,那也不难做到;请参阅在模块名称位于变量中时导入模块,但随后无法在脚本中更早地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')

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

也许切线研究第三方库,如click,它很容易让你将选定的函数公开为Python脚本的"子命令",隐约类似于git子命令initlog等。

最新更新