【问题标题】:Call Python function using dynamic string variables使用动态字符串变量调用 Python 函数
【发布时间】:2023-03-24 05:25:02
【问题描述】:

我正在尝试创建一个动态方法执行器,其中我有一个始终包含两个元素的列表。第一个元素是文件名,第二个元素是要执行的方法的名称。

我怎样才能做到这一点?

不幸的是,我下面的代码不起作用,但它可以很好地说明我想要实现的目标。

from logic.intents import CenterCapacity

def method_executor(event):
    call_reference = ['CenterCapacity', 'get_capacity']

    # process method call
    return call_reference[0].call_reference[1]

谢谢!

【问题讨论】:

    标签: python python-3.x string function


    【解决方案1】:

    您可以使用__import__ 按名称查找模块,然后使用getattr 查找方法。例如,如果以下代码位于名为exec.py 的文件中,则

    def dummy(): print("dummy")
    
    def lookup(mod, func):
        module = __import__(mod)
        return getattr(module, func)
    
    if __name__ == "__main__":
        lookup("exec","dummy")()
    

    会输出

    dummy
    

    附录

    也可以使用importlib.import_module,虽然有点冗长,但可能更容易使用。

    这两个函数最重要的区别在于import_module()返回的是指定的包或模块(例如pkg.mod),而__import__()返回的是顶层包或模块(例如pkg)。

    def lookup(mod, func):
        import importlib
        module = importlib.import_module(mod)
        return getattr(module, func)
    

    【讨论】:

    • 我假设查找函数中的模块需要是文件的完整路径?例如:lookup("config.intents.exec", "dummy") 那么它会在文件“exec”中调用“dummy”,对吗?另外,如果我需要在类中调用方法,我应该将模块传递为:lookup("package.file.class", "dummy")?
    • 您可以阅读__import__的详细信息,可以配置。
    • 我还添加了一个使用importlib.import_module 的变体,它更适合检索子模块
    • 谢谢。我让它与 importlib 模块一起工作!很棒。
    【解决方案2】:

    起点:

    from logic.intents import CenterCapacity
    
    def method_executor(event):
        call_reference = ['CenterCapacity', 'get_capacity']
    
        # process method call
        return call_reference[0].call_reference[1]
    

    选项 1

    我们有几个选项,第一个是使用类引用和getattr。为此,我们必须删除类周围的',并在调用引用之前实例化该类(当方法是staticmethod 时,您不必实例化该类。)

    def method_executor(event):
        call_reference = [CenterCapacity, 'get_capacity']  # We now store a class reference
    
        # process method call
        return getattr(call_reference[0](), call_reference[1])
    

    选项 2

    第二个选项基于this 答案。它围绕使用getattr 方法两次。我们首先使用sys.modules[__name__] 获取模块,然后使用getattr 从那里获取类。

    import sys
    
    def method_executor(event):
        call_reference = ['CenterCapacity', 'get_capacity'] 
        class_ref = getattr(sys.modules[__name__], call_reference[0])
        return getattr(class_ref, call_reference[1])
    

    选项 3

    第三个选项可以基于完整的导入路径并使用__import__('module.class'),请查看this SO 帖子。

    【讨论】:

    • 我很少将类用于我的代码中的不同意图,这是因为我的代码每次请求都会执行一次。每次最终用户对聊天机器人(我正在处理的工作)有意图时,AWS lambda 都会执行我的代码。
    【解决方案3】:

    (注意:这个答案假设必要的导入已经发生,你只需要一种机制来调用导入模块的功能。如果你还希望导入由某些人完成程序代码,我将不得不添加那部分,使用importlib库)

    你可以这样做:

    globals()[call_reference[0]].__dict__[call_reference[1]]()
    

    说明:

    globals() 返回全局变量名与其引用对象之间的映射。导入模块的名称算作当前模块的这些全局变量之一。

    使用call_reference[0] 索引此映射对象会返回包含要调用的函数的模块对象。

    模块对象的__dict__ 将模块的每个属性名称映射到该属性引用的对象。模块中定义的函数也算作模块的属性。

    因此,使用函数名称 call_reference[1] 索引 __dict__ 会返回函数对象。

    【讨论】:

    • 好主意!这也很简单。使用importlib不是更好吗,如果是的话,该怎么做?
    猜你喜欢
    • 2014-09-06
    • 2018-06-21
    • 2020-05-28
    • 2021-11-17
    • 2021-05-07
    • 2012-03-12
    • 1970-01-01
    • 1970-01-01
    • 2017-02-27
    相关资源
    最近更新 更多