使用模块的名称(字符串)调用模块的函数

Calling a function of a module by using its name (a string)

提问人:ricree 提问时间:8/6/2008 最后编辑:Mateen Ulhaqricree 更新时间:6/5/2022 访问量:1130225

问:

如何使用带有函数名称的字符串调用函数?例如:

import foo
func_name = "bar"
call(foo, func_name)  # calls foo.bar()
Python 对象 反射

评论

8赞 WMRamadan 9/22/2021
使用 eval 可能会带来一些安全问题!
23赞 Nearoo 11/27/2021
仅供参考:通过动态名称访问字段、类和方法的语言特性称为反射。可能会使将来的搜索更容易。

答:

2886赞 Patrick Johnmeyer 8/6/2008 #1

给定一个模块,其方法为:foobar

import foo
bar = getattr(foo, 'bar')
result = bar()

getattr 同样可以用于类实例绑定方法、模块级方法、类方法......这样的例子不胜枚举。

评论

21赞 Shaun 6/3/2014
hasattr 或 getattr 可用于确定是否定义了函数。我有一个数据库映射(eventType 和处理 functionName),我想确保我永远不会“忘记”在我的 python 中定义一个事件处理程序
15赞 Blairg23 6/21/2014
如果您已经知道模块名称,则这有效。但是,如果您希望用户以字符串形式提供模块名称,则这将不起作用。
13赞 geekofalltrades 8/17/2014
如果您需要避免 NoneType is not callable 异常,您还可以使用 getattr: getattr(foo, 'bar', lambda: None) 的三个参数形式。对于格式,我深表歉意;StackExchange Android 应用程序显然很糟糕。
7赞 NuSkooler 6/20/2015
如果您只关心本地/当前模块的功能,另请参阅@sastanin提供的答案。
23赞 Ben Hoyt 12/21/2016
@akki 是的,如果你在模块中,你可以用它来执行此操作:fooglobals()methodToCall = globals()['bar']
471赞 HS. 8/7/2008 #2

根据 Patrick 的解决方案,要动态获取模块,请使用以下命令导入它:

module = __import__('foo')
func = getattr(module, 'bar')
func()

评论

104赞 hoffmaje 5/5/2012
我不明白最后一条评论。__import__有自己的权利,上述文档中的下一句话说:“直接使用 __import__() 很少见,除非您想导入仅在运行时知道名称的模块”。所以:+1 给出的答案。
65赞 glarrain 8/6/2013
用。官方文档说:“这是一个高级函数,在日常 Python 编程中不需要,不像 importlib.import_module()”。docs.python.org/2/library/functions.html#__import__importlib.import_module__import__
10赞 Xiong Chiamiov 9/15/2013
@glarrain 只要你只支持 2.7 及更高版本就可以了。
4赞 cowlinator 10/6/2017
@Xiong Chaimiov,在 3.6 中受支持。查看 docs.python.org/3.6/library/...importlib.import_module
10赞 Xiong Chiamiov 10/6/2017
@cowlinator 是的,3.6 是“2.7 及更高版本”的一部分,无论是在严格的版本控制语义上还是在发布日期上(大约六年后才出现)。在我发表评论后的三年里,它也不存在。;)在 3.x 分支中,该模块从 3.1 开始就存在。2.7 和 3.1 现在已经很古老了;您仍然会发现仅支持 2.6 的服务器,但现在可能值得将 importlib 作为标准建议。
762赞 sastanin 5/7/2009 #3
  • 使用 locals(),它返回一个带有当前本地符号表的字典:

    locals()["myfunction"]()
    
  • 使用 globals(),它返回一个带有全局符号表的字典:

    globals()["myfunction"]()
    

评论

94赞 Joelmob 10/10/2014
如果需要调用的方法在调用的同一模块中定义,则此具有全局/局部变量的方法很好。
1赞 Nick T 1/27/2015
@Joelmob有没有其他方法可以按字符串从根命名空间中获取对象?
1赞 Joelmob 1/27/2015
@NickT我只知道这些方法,但我认为没有其他方法可以满足与这些相同的功能,至少我想不出应该有更多的原因。
2赞 David Stein 1/30/2017
我有一个理由(实际上是导致我来到这里的原因):模块 A 有一个函数 F,需要按名称调用函数。模块 B 导入模块 A,并调用函数 F,并请求调用模块 B 中定义的函数 G。此调用失败是因为,显然,函数 F 仅使用模块 F 中定义的全局变量运行 - 因此 globals()['G'] = None。
43赞 trubliphone 2/14/2012 #4

值得一提的是,如果您需要将函数(或类)名称和应用名称作为字符串传递,那么您可以这样做:

myFnName  = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn  = getattr(app,myFnName)

评论

2赞 lony 10/6/2017
只是更通用一点是handler = getattr(sys.modules[__name__], myFnName)
1赞 Jürgen K. 9/6/2021
如果函数是类函数,它是如何工作的?
164赞 Sourcegeek 8/19/2012 #5

只是一个简单的贡献。如果我们需要实例化的类在同一个文件中,我们可以使用如下内容:

# Get class from globals and create an instance
m = globals()['our_class']()

# Get the function (from the instance) that we need to call
func = getattr(m, 'function_name')

# Call it
func()

例如:

class A:
    def __init__(self):
        pass

    def sampleFunc(self, arg):
        print('you called sampleFunc({})'.format(arg))

m = globals()['A']()
func = getattr(m, 'sampleFunc')
func('sample arg')

# Sample, all on one line
getattr(globals()['A'](), 'sampleFunc')('sample arg')

而且,如果不是类:

def sampleFunc(arg):
    print('you called sampleFunc({})'.format(arg))

globals()['sampleFunc']('sample arg')

评论

2赞 Jürgen K. 9/6/2021
如果在类函数中调用此函数会怎样?
18赞 Natdrip 12/29/2012 #6

这些建议都没有帮助我。不过,我确实发现了这一点。

<object>.__getattribute__(<string name>)(<params>)

我正在使用 python 2.66

希望这会有所帮助

评论

23赞 V13 7/29/2016
这在哪些方面比 getattr() 更好?
1赞 ioaniatr 8/7/2018
正是我想要的。像魅力一样工作!完善!! 等于self.__getattribute__('title')self.title
0赞 ioaniatr 8/17/2018
self.__getattribute__('title')毕竟在任何情况下都不起作用(不知道为什么),但确实如此。所以,也许最好改用func = getattr(self, 'title'); func();getattr()
23赞 Aran-Fey 10/23/2018
不了解python的人可以停止投票吗?请改用 getattr
158赞 ferrouswheel 10/16/2013 #7

给定一个字符串,其中包含一个函数的完整 python 路径,这就是我获取所述函数结果的方式:

import importlib
function_string = 'mypackage.mymodule.myfunc'
mod_name, func_name = function_string.rsplit('.',1)
mod = importlib.import_module(mod_name)
func = getattr(mod, func_name)
result = func()

评论

4赞 Pankaj Bhambhani 12/16/2015
这帮助了我。它是功能的轻量级版本。__import__
5赞 SdSaati 1/22/2020
我认为这是最好的答案。
72赞 00500005 4/9/2014 #8

答案(我希望)没有人想要

类似 Eval 的行为

getattr(locals().get("foo") or globals().get("foo"), "bar")()

为什么不添加自动导入

getattr(
    locals().get("foo") or 
    globals().get("foo") or
    __import__("foo"), 
"bar")()

如果我们有额外的词典,我们想检查

getattr(next((x for x in (f("foo") for f in 
                          [locals().get, globals().get, 
                           self.__dict__.get, __import__]) 
              if x)),
"bar")()

我们需要更深入地研究

getattr(next((x for x in (f("foo") for f in 
              ([locals().get, globals().get, self.__dict__.get] +
               [d.get for d in (list(dd.values()) for dd in 
                                [locals(),globals(),self.__dict__]
                                if isinstance(dd,dict))
                if isinstance(d,dict)] + 
               [__import__])) 
        if x)),
"bar")()

评论

26赞 pevinkinel 5/21/2020
这可以通过递归扫描目录树和自动挂载 USB 驱动器来改进
1赞 ArjunSahlot 2/28/2021
这绝对是我想要的答案。完善。
88赞 user3946687 10/24/2016 #9

根据 Python 编程常见问题解答,最佳答案是:

functions = {'myfoo': foo.bar}

mystring = 'myfoo'
if mystring in functions:
    functions[mystring]()

此技术的主要优点是字符串不需要与函数的名称匹配。这也是用于模拟案例结构的主要技术

46赞 tvt173 12/8/2016 #10

试试这个。虽然它仍然使用 eval,但它只使用它从当前上下文中调用函数。然后,您就拥有了可以随心所欲地使用的真正功能。

对我来说,这样做的主要好处是,在调用函数时,您会遇到任何与评估相关的错误。然后,调用时只会收到与函数相关的错误。

def say_hello(name):
    print 'Hello {}!'.format(name)

# get the function by name
method_name = 'say_hello'
method = eval(method_name)

# call it like a regular function later
args = ['friend']
kwargs = {}
method(*args, **kwargs)

评论

3赞 iankit 12/31/2016
这将是有风险的。字符串可以包含任何内容,而 eval 最终会不加考虑地对其进行评估。
7赞 tvt173 1/7/2017
当然,考虑到这些风险,您必须注意使用它的上下文,无论这是否合适。
6赞 red777 8/14/2018
函数不应该负责验证它的参数 - 这是另一个函数的工作。说将 eval 与字符串一起使用是有风险的,就是说使用每个函数都是有风险的。
3赞 moi 1/14/2019
除非绝对必要,否则切勿使用。 在这种情况下,是一个更好的选择。evalgetattr(__module__, method_name)
21赞 Serjik 3/27/2019 #11

作为这个问题 如何使用方法名称赋值来动态调用类中的方法 [duplicate] 标记为重复的变量 [duplicate],我在这里发布了一个相关的答案:

场景是,一个类中的某个方法想要动态调用同一类上的另一个方法,我在原始示例中添加了一些细节,它提供了一些更广泛的场景和清晰度:

class MyClass:
    def __init__(self, i):
        self.i = i

    def get(self):
        func = getattr(MyClass, 'function{}'.format(self.i))
        func(self, 12)   # This one will work
        # self.func(12)    # But this does NOT work.


    def function1(self, p1):
        print('function1: {}'.format(p1))
        # do other stuff

    def function2(self, p1):
        print('function2: {}'.format(p1))
        # do other stuff


if __name__ == "__main__":
    class1 = MyClass(1)
    class1.get()
    class2 = MyClass(2)
    class2.get()

输出 (Python 3.7.x)

函数 1:12

函数 2:12

评论

1赞 M M 4/12/2022
很好的回答,谢谢:)我正在尝试相同的方法,但失败了,因为我知道我必须再次在实际函数调用中包含“self”。你能解释为什么这是必要的吗?
1赞 Serjik 4/20/2022
我最好的猜测:Python 中的 obj.method 实际上调用了 method(self, ...),在 getattr 的情况下,Python 解释器无法应用这种合成糖。
2赞 drascom 5/12/2022
最佳答案。关键是在 getattr 命令中使用类名而不是“self”,我试图使用 getattr(self, key)() 并且它给出了错误,例如 int 不可调用,但是当我将其更改为“ getattr(HomeScreen, key)(self)”时,它现在可以工作了。顺便说一句,“HomeScreen”是类名。谢谢。。。
-16赞 Number File 8/29/2019 #12

这是一个简单的答案,例如,这将允许您清除屏幕。下面有两个示例,分别使用 eval 和 exec,它们在清理后会在顶部打印 0(如果您使用的是 Windows,请更改为 ,Linux 和 Mac 用户保持原样)或分别执行它。clearcls

eval("os.system(\"clear\")")
exec("os.system(\"clear\")")

评论

5赞 Tuncay Göncüoğlu 11/14/2019
这不是op所要求的。
13赞 Jean-François Fabre 7/17/2020
此代码片段包含最严重的 2 个安全漏洞,嵌套。某种记录。
0赞 InSync 11/3/2023
这一定是在错误的问题中发布的。请删除它。
8赞 정도유 7/1/2020 #13

getattr从对象中按名称调用方法。 但是这个对象应该是调用类的父级。 父类可以通过以下方式获取super(self.__class__, self)

class Base:
    def call_base(func):
        """This does not work"""
        def new_func(self, *args, **kwargs):
            name = func.__name__
            getattr(super(self.__class__, self), name)(*args, **kwargs)
        return new_func

    def f(self, *args):
        print(f"BASE method invoked.")

    def g(self, *args):
        print(f"BASE method invoked.")

class Inherit(Base):
    @Base.call_base
    def f(self, *args):
        """function body will be ignored by the decorator."""
        pass

    @Base.call_base
    def g(self, *args):
        """function body will be ignored by the decorator."""
        pass

Inherit().f() # The goal is to print "BASE method invoked."
17赞 Lukas 7/16/2020 #14

虽然 getattr() 是优雅的(速度大约快 7 倍),但你可以从函数(local、class 方法、模块)中获取返回值,eval 和 .当你实现一些错误处理时,那么非常安全(同样的原则可以用于 getattr)。模块导入和类示例:x = eval('foo.bar')()

# import module, call module function, pass parameters and print retured value with eval():
import random
bar = 'random.randint'
randint = eval(bar)(0,100)
print(randint) # will print random int from <0;100)

# also class method returning (or not) value(s) can be used with eval: 
class Say:
    def say(something='nothing'):
        return something

bar = 'Say.say'
print(eval(bar)('nice to meet you too')) # will print 'nice to meet you' 

当模块或类不存在(拼写错误或更好的任何内容)时,会引发 NameError。当函数不存在时,将引发 AttributeError。这可用于处理错误:

# try/except block can be used to catch both errors
try:
    eval('Say.talk')() # raises AttributeError because function does not exist
    eval('Says.say')() # raises NameError because the class does not exist
    # or the same with getattr:
    getattr(Say, 'talk')() # raises AttributeError
    getattr(Says, 'say')() # raises NameError
except AttributeError:
    # do domething or just...
    print('Function does not exist')
except NameError:
    # do domething or just...
    print('Module does not exist')
3赞 Bowen 404 6/15/2021 #15

我之前遇到过类似的问题,即将字符串转换为函数。但是我不能使用 eval()ast.literal_eval(),因为我不想立即执行此代码。

例如,我有一个字符串,我想将其作为函数名称而不是字符串分配给它,这意味着我可以通过按需调用函数。"foo.bar"xx()

这是我的代码:

str_to_convert = "foo.bar"
exec(f"x = {str_to_convert}")
x()

至于您的问题,您只需要添加您的模块名称和之前,如下所示:foo.{}

str_to_convert = "bar"
exec(f"x = foo.{str_to_convert}")
x()

警告!!eval() 或 exec() 都是危险的方法,您应该确认安全性。 警告!!eval() 或 exec() 都是一种危险的方法,您应该确认安全性。 警告!!eval() 或 exec() 都是危险的方法,您应该确认安全性。

评论

1赞 Lecdi 3/24/2022
eval()可以在这里代替 ,并且可能会使代码更具可读性:只需使用相同的结果即可。exec()x = eval(str_to_convert)
0赞 Bowen 404 3/25/2022
@Lecdi是的,你是对的!这也使该变量对以下代码可见。谢谢!
0赞 Bowen 404 3/25/2022
@Lecdi但是 exec 可以让我定义一系列具有不同名称的变量,例如 exec(f“x{i} = {i}”),这是 eval 无法做到的。
17赞 Aliakbar Ahmadi 7/7/2021 #16

在 python3 中,您可以使用该方法。请参阅以下示例,其中包含列表方法名称字符串:__getattribute__

func_name = 'reverse'

l = [1, 2, 3, 4]
print(l)
>> [1, 2, 3, 4]

l.__getattribute__(func_name)()
print(l)
>> [4, 3, 2, 1]

评论

2赞 Lecdi 3/24/2022
这是此答案的重复,并且出于相同的原因也不是最佳实践:只需改用即可。getattr(obj, attr)
11赞 U13-Forward 9/20/2021 #17

还没有人提到:operator.attrgetter

>>> from operator import attrgetter
>>> l = [1, 2, 3]
>>> attrgetter('reverse')(l)()
>>> l
[3, 2, 1]
>>>