我有一个str对象,例如:menu = 'install'。我想从这个字符串运行install方法。例如,当我调用menu(some, arguments)时,它将调用install(some, arguments)。有什么办法吗?
如果是在一个类中,你可以使用getattr:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class MyClass(object):
def install(self):
print"In install"
method_name = 'install' # set by the command line options
my_cls = MyClass()
method = None
try:
method = getattr(my_cls, method_name)
except AttributeError:
raise NotImplementedError("Class `{}` does not implement `{}`".format(my_cls.__class__.__name__, method_name))
method() |
或者如果它是一个函数:
1 2 3 4 5 6 7 8 9 10
| def install():
print"In install"
method_name = 'install' # set by the command line options
possibles = globals().copy()
possibles.update(locals())
method = possibles.get(method_name)
if not method:
raise NotImplementedError("Method %s not implemented" % method_name)
method() |
- 谢谢你的回答。但是如果方法不在类中呢?
- 非常感谢sdolan。我试过用全局变量而不是局部变量,效果不错。
- 后者在修改全局变量之前不会.copy(),这会带来各种麻烦。它有一个bug,因为它在检查方法之前立即调用该方法,然后再次调用它的结果。此外,通常使用前缀来防止仅调用名称空间中的任何元素(例如。"do_install ()")。
- @高温镜:全球捕捉得很好。我已经更新了示例代码来实现这一点。我也同意前缀,并且在我自己的代码中这样做是有意义的。我不知道OPs问题的具体细节,所以我尽量不急于下结论。
- @sdolan,完美的答案,但是一个小错误getattr没有响应None if属性不存在,而是引发一个异常,所以如果不方法:引发异常("方法%s未实现"% method_name)是不需要的
- @Sarathsp:哈哈,很好。人们只用了4.5年的时间就发现了这种病毒;)
- 如果确定该方法存在,可以使用:globals().get(method_name)()或local ().get(method_name)()
- 您的第一个答案是:引发NotImplementedError("Class {}不实现{}")。应该是:raise NotImplementedError("Class {}没有实现{}".format(my_cls. _class__)。__name__, method_name))
- @MoAli cool,刚刚更新添加了额外的paren。
你也可以用字典。
1 2 3 4 5 6 7 8 9 10
| def install():
print"In install"
methods = {'install': install}
method_name = 'install' # set by the command line options
if method_name in methods:
methods[method_name]() # + argument list of course
else:
raise Exception("Method %s not implemented" % method_name) |
- 我认为使用dictionary比在可接受的答案中依赖globals().copy()干净一些。
- @AgnivaDeSarker确保在设置字典时没有调用函数,即,只使用函数名,没有括号:{'install': install}
- 我更喜欢这样,因为它很容易传递参数,而且可以使用dictionalry轻松控制方法列表
- 与公认的答案相比,我更喜欢这种方法,但我似乎无法让它与类方法一起工作。
- @navjotk在您的字典声明中:methods = {'install': self.install}(或obj.install)
- 嗯,我在这里尝试了类似的方法,但是没有成功:stackoverflow.com/questions/50359442/…
- 如果使用字典来存储方法,方法必须在字典之前定义——就像在方法定义中必须在字典所在的行之上,否则就会得到;name错误:名称"X"没有定义
为什么我们不能直接使用eval()呢?
1 2
| def install():
print"In install" |
新方法
1 2
| def installWithOptions(var1, var2):
print"In install with options" + var1 +"" + var2 |
然后调用下面的方法
1 2 3 4
| method_name1 = 'install()'
method_name2 = 'installWithOptions("a","b")'
eval(method_name1)
eval(method_name2) |
这将输出为
1 2
| In install
In install with options a b |
- 他在寻找一种用参数调用函数的方法。你能详细吗?
- 是的,它也能用同样的方式处理论点。
- 如果您使用上述策略,这意味着您正在动态定义方法/函数,换句话说,它们可以是很多东西,包括恶意代码。我建议您阅读本文,然后,不要再使用eval。如果需要,只需使用json。
- @lucastamoios:至少在OP中不是真的——使用预定义的字符串作为函数名。
- 您如何建议使用installWithOptions为任意参数列表构建参数列表?在这里显示硬编码的示例当然不能说明问题。当然,这完全忽略了使用eval的实践是多么可怕。我从未见过它的合法用例
- 如果输入是可信的,那么使用eval()是安全的
- @Justas确定。理论上是这样。但是现在代码永远都在那里了,而在另一个文件中看似无害的更改现在却因为使用了eval语句而打开了一个巨大的安全漏洞。你应该建立尽可能少的假设。因为谁知道他们什么时候会改变。
- eval(method_name1)(a,b)同样适用。关于安全的公平观点——对于小型私有脚本来说是可以的,但是它们会保持这种状态吗?例如,如果字符串来自某个网站,请非常小心。这里唯一的问题不是eval——对来自任意源的字符串使用getattr同样危险。