【问题标题】:Python: call a function from string name [duplicate]Python:从字符串名称调用函数[重复]
【发布时间】:2011-12-17 16:55:25
【问题描述】:

我有一个 str 对象,例如:menu = 'install'。我想从此字符串运行安装方法。例如,当我调用menu(some, arguments) 时,它会调用install(some, arguments)。有什么办法吗?

【问题讨论】:

    标签: python


    【解决方案1】:

    如果它在一个类中,你可以使用getattr:

    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()
    

    或者如果它是一个函数:

    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()
    

    【讨论】:

    • 感谢您的回答。但是如果方法不在一个类中呢?
    • 非常感谢斯多兰。我尝试过使用 globals 而不是 locals 并且它有效。
    • 后者在变异之前不会 .copy() 全局变量,从而引发各种麻烦。它有一个错误,因为它在检查方法之前立即调用该方法,然后再次调用其结果。此外,通常的做法是使用前缀,以防止仅调用命名空间中的任何元素(例如“do_install()”)。
    • @pyroscope: 很好地抓住了全局变量。我已经更新了示例代码来做到这一点。我也同意前缀,并在我自己的代码中有意义的地方这样做。我不知道 OPs 问题的具体情况,所以我尽量不得出任何结论。
    • @Nihat 请参考这个问题。 stackoverflow.com/questions/7969949/…
    【解决方案2】:

    你也可以使用字典。

    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)
    

    【讨论】:

    • 我相信使用字典比在接受的答案中依赖 globals().copy() 更干净。
    • @AgnivaDeSarker 确保在设置字典时,您没有调用函数 - 即,您只使用函数名称,没有括号:{'install': install}
    • 我更喜欢这个,因为它很容易传递参数,你可以用字典轻松控制方法列表
    • 我更喜欢这种方法而不是接受的答案,但我似乎无法使其与类方法一起使用。
    • @navjotk 在您的字典声明中:methods = {'install': self.install}(或obj.install
    【解决方案3】:

    为什么我们不能只使用 eval()?

    def install():
        print "In install"
    

    新方法

    def installWithOptions(var1, var2):
        print "In install with options " + var1 + " " + var2
    

    然后你调用如下方法

    method_name1 = 'install()'
    method_name2 = 'installWithOptions("a","b")'
    eval(method_name1)
    eval(method_name2)
    

    这将输出为

    In install
    In install with options a b
    

    【讨论】:

    • 他正在寻求一种方法来调用带有参数的函数。能详细点吗?
    • 是的,它也可以以相同的方式处理参数。
    • 如果你使用上述策略,就意味着你在动态定义你的方法/函数,换句话说,它们可以是很多东西,包括恶意代码。我建议你this article,然后,永远不要再使用 eval。需要时,只需使用json
    • @Justas 当然。理论上。但是现在该代码永远存在,并且由于使用了 eval 语句,在另一个文件中看似无害的更改现在却打开了一个巨大的安全漏洞。你应该建立尽可能少的假设。因为谁知道他们什么时候会改变。
    • eval(method_name1)(a,b) 也可以。关于安全的公平点——对于小型私人脚本来说还可以,但它们会保持这种状态吗?例如,如果字符串来自网站,请务必小心。 eval 不是这里唯一的问题——在任意来源的字符串上使用 getattr 同样危险。
    猜你喜欢
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2023-03-18
    • 2017-07-02
    • 1970-01-01
    • 1970-01-01
    • 2020-11-15
    • 2015-04-06
    相关资源
    最近更新 更多