我的包具有以下结构:
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.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.py
和sim2.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 次。 因为,simulation1
在sim1.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
子命令init
,log
等。