通过使用其名称调用模块的功能(字符串)

在Python程序中给出带有函数名字符串的函数的最佳方法是什么?例如,假设我有一个模块 foo ,并且我有一个字符串,其内容是“bar”。什么是最好的方式去调用 foo.bar()

我需要获取函数的返回值,这就是为什么我不使用 eval 。我想通过使用 eval 来定义一个返回该函数调用结果的临时函数,但我希望有一种更优雅的方式来完成此操作。

0
额外 编辑
意见: 2

9 答案

帕特里克的解决方案可能是最干净的。 如果您还需要动态获取模块,则可以像下面这样导入它:

module = __import__('foo')
func = getattr(module, 'bar')
func()
0
额外
@glarrain只要你支持2.7以上就可以了。
额外 作者 Xiong Chiamiov,
@cowlinator是的,3.6是“2.7以上”的一部分,无论是严格的版本语义还是发布日期(大约在六年后)。在我发表评论之后的三年里,这也不存在。 ;)在3.x分支中,该模块从3.1开始就已经出现了。 2.7和3.1现在很古老,你仍然会发现只支持2.6的服务器,但是现在可能需要将importlib作为标准的建议。
额外 作者 Xiong Chiamiov,
在3.6中支持@Xicha Chaimiov, importlib.import_module 。请参阅 docs.python.org/3.6/library/…
额外 作者 cowlinator,
使用 importlib.import_module 。官方文档提到 __ import __ :“这是一个高级函数,在日常Python编程中不需要,与importlib.import_module()不同。” docs.python.org/2/library/functions.html#__import__
额外 作者 glarrain,
我不明白最后的评论。 __import__有它自己的权利,并且在提到的文档中的下一句话是这样的:“直接使用__import __()是很少见的,除非你想导入一个名字只在运行时才知道的模块”。所以:给定的答案+1。
额外 作者 hoffmaje,

没有任何建议帮助了我。但我确实发现了这一点。

.__getattribute__()() 

我使用python 2.66

希望这可以帮助

0
额外
在哪方面比getattr()更好?
额外 作者 V13,

对于它的价值,如果您需要将函数(或类)名称和应用程序名称作为字符串传递,那么您可以这样做:

myFnName  = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn  = getattr(app,myFnName)
0
额外
更通用的是 handler = getattr(sys.modules [__ name__],myFnName)
额外 作者 lony,

给定一个字符串,一个完整的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()
0
额外
这帮助了我。它是 __ import __ 函数的轻量级版本。
额外 作者 Pankaj Bhambhani,
整洁的解决方案队友!
额外 作者 Nebulosar,
locals()["myfunction"]()

要么

globals()["myfunction"]()

locals returns a dictionary with a current local symbol table. globals returns a dictionary with global symbol table.

0
额外
@Joelmob有没有其他方法可以通过字符串从根名称空间中获取对象?
额外 作者 Nick T,
如果您需要调用的方法在您调用的同一个模块中定义,则使用全局变量或本地变量的方法是很好的。
额外 作者 Joelmob,
@NickT我只知道这些方法,我认为没有其他人能够完成相同的功能,至少我想不出应该有更多的原因。
额外 作者 Joelmob,
我有一个理由给你(实际上是什么引导了我):模块A有一个函数F,需要按名称调用一个函数。模块B导入模块A,并调用函数F调用模块B中定义的函数G的请求。此调用失败,因为显然,函数F仅与模块F中定义的全局变量一起运行 - 所以全局变量() ['G'] =无。
额外 作者 David Stein,

假设模块 foo 带有方法 bar

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

就此而言,第2行和第3行可以压缩为:

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

如果这对你的用例更有意义。您可以以这种方式在类实例绑定方法,模块级方法,类方法上使用 getattr ...列表继续。

0
额外
为了目前的价值,没有人会感谢这个伟大的答案。
额外 作者 Coolio2654,
这不适用于使用装饰器的函数。 getattr返回外部函数
额外 作者 azmeuk,
hasattr或getattr可用于确定函数是否已定义。我有一个数据库映射(eventType和处理函数名),我想确保我从来没有“忘记”在我的python中定义一个事件处理程序
额外 作者 Shaun,
咩。我花了10分钟尝试 foo.getattr('bar')foo.get_attr('bar')的变体。
额外 作者 Eric Duminil,
另请参阅@sastanin提供的答案,如果您只关心本地/当前模块的功能。
额外 作者 NuSkooler,
注意:很酷的+1,这让我再次明白,在Python中,一切都是一个对象。因此,它也适用于变量,您可以像访问其他对象的变量一样访问模块的变量。
额外 作者 tuned,
@akki是的,如果你在 foo 模块中,你可以使用 globals()来实现这一点: methodToCall = globals( )[ '酒吧'] </代码>
额外 作者 Ben Hoyt,
@PatrickJohnmeyer我从来没有完全排除模式/范式......这就是为什么我问了一个问题而不是一言两语的原因。过度使用这种模式会产生很多负面影响......哪些(至少在我的经验中)是常见的。
额外 作者 KeatsKelleher,
你可以做到这一点,但应该吗?当代码库变大时,如何查找函数调用的所有实例?没有任何要求,并且没有IDE会找到该参考。这使得这种动态调用真的很麻烦。无论如何,你的同事们是不是更清楚一点?较少的代码并不总是意味着更多的可读性。
额外 作者 KeatsKelleher,
如果您已经知道模块名称,这将起作用。但是,如果您希望用户将模块名称作为字符串提供,则这不起作用。
额外 作者 Blairg23,
@KeatsKelleher因为我们不知道用例,只有问题,我可以肯定地说,有许多用例适用于你的观点,有些则不适用。在规则引擎,DSL,应用内脚本等中执行这样的事情是很常见和合理的,其中您正在编写的代码存在以运行其他代码。可能还有很多其他的“好”时间来做到这一点,我现在没有想到。所以,我们应该这样做?与大多数语言中的大多数语言功能一样,答案是“这取决于”。
额外 作者 Patrick Johnmeyer,
如果您需要避免NoneType不可调用的异常,则也可以使用getattr:getattr(foo,'bar',lambda:None)的三参数形式。我对格式化表示抱歉; stackexchange android应用显然非常糟糕。
额外 作者 geekofalltrades,
如果你有深层次的结构,下面的语法可能是有用的:从functools import reduce reduce(getattr,“a.b.c.d.e.f.g”.split('。'),deepStructure)
额外 作者 Robert Parcus,
这是一个非常有用的答案,当模块foo是当前模块本身时,我无法解决它。有谁知道如何做到这一点?
额外 作者 akki,

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

# 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')
0
额外

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

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")()
0
额外

尝试这个。虽然这仍然使用eval,但它只是用它来从当前上下文召唤函数。然后,您可以根据需要使用真正的功能。

我从中得到的主要好处是,你会在召唤这个函数的时候得到任何与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)
0
额外
这将是有风险的。字符串可以有任何东西,并且eval最终可以毫无顾虑地评估它。
额外 作者 iankit,
当然,考虑到这些风险,您必须注意您使用的环境,无论这是否合适。
额外 作者 tvt173,