【问题标题】:Python: Attribute Error When Passing Method as Function ArgumentPython:将方法作为函数参数传递时出现属性错误
【发布时间】:2014-08-27 08:24:14
【问题描述】:

我确信在堆栈溢出的某个地方会有这个问题的答案,但我一直找不到;其中大部分是关于将函数而不是方法作为函数的参数传递。

我目前正在使用 Python 2.7.5,我正在尝试定义这样的函数:

def func(object, method):
    object.method()

当这样调用时:

some_object_instance = SomeObject()
func(some_object_instance, SomeObject.some_object_method)

使用这样定义的类:

class SomeObject:
    def some_object_method(self):
        # do something

基本上相当于这样做:

some_object_instance.some_object_method()


但是,我不断收到属性错误——类似于

'SomeObject' has no attribute 'method'

我的印象是,当以上述方式使用时,我可以合法地将方法作为参数传递并让它们正确评估。我错过了什么?

【问题讨论】:

    标签: python oop python-2.7 functional-programming


    【解决方案1】:

    这不是方法调用的工作方式。 foo.bar 语法在foo 对象上查找方法命名 bar。如果您已经有了该方法,只需调用它:

    def func(object, method):
        method(object)
    
    func(some_object_instance, SomeObject.some_object_method)
    

    SomeObject.some_object_method 是所谓的“未绑定方法”:它是一个没有绑定self 的方法对象,因此您必须将self 显式传递给它。

    用一个具体的例子可能更有意义:

    >>> s = 'ABC'
    >>> s_lower = s.lower # bound method
    >>> s_lower()
    'abc'
    >>> str_lower = str.lower # unbound method
    >>> str_lower(s)
    'abc'
    

    相比之下,some_object_instance.some_object_method 是一个“绑定方法”,您可以直接调用它,而 some_object_instance 已经作为 self 参数“绑定”了:

    def func2(method):
        method()
    func2(some_object_instance.some_object_method)
    

    教程中没有详细解释未绑定的方法;它们在bound methods 部分中进行了介绍。所以你必须去参考手册获取文档(在[标准类型层次结构] (https://docs.python.org/2/reference/datamodel.html#the-standard-type-hierarchy),在“用户定义的方法”小节中),这对于新手来说可能有点令人生畏。


    就我个人而言,直到我了解到它是如何在幕后工作的,我才真正明白这一点。大约一年前,我写了一篇博客文章How methods work 试图向其他人解释它(但在 Python 3.x 术语中,略有不同);它可能会有所帮助。要真正得到它,你必须通过Descriptor HOWTO,这可能需要在交互式解释器中进行几次阅读和大量播放才能真正点击,但希望你能理解在到达这一点之前,方法背后的基本概念。

    【讨论】:

    • 我不知道调用绑定方法与未绑定方法之间的区别。它奏效了,但我觉得我应该多研究一下。谢谢!
    • @austin_sherron:就我个人而言,直到我了解到它是如何在幕后工作的,我才真正明白这一点。大约一年前,我写了一篇博客文章How methods work 试图向其他人解释它(但在 Python 3.x 术语中,略有不同);它可能会对你有所帮助。
    【解决方案2】:

    由于您将未绑定的方法传递给函数,因此您需要将其调用为:

    method(object)
    

    或者最好将方法名称作为字符串传递,然后使用getattr

    getattr(object, method)()
    

    【讨论】:

    • 为什么按名称传递而不是通常“更好”?
    • @abarnert 因为在这种情况下我们直接处理实例的方法。在第一种情况下,我们必须确保传递完全相同的实例类,传递基类的未绑定方法是行不通的。
    • 如果你想调用对象的实际类的方法,你可以这样做;如果你想调用基类的方法,你也可以这样做。他们都是合法的,这只是你想要的问题。如果你想确保你调用object自己的method,你传递一个绑定的方法,而不是一个未绑定的方法加上一个对象一个字符串加上一个对象。
    猜你喜欢
    • 1970-01-01
    • 2018-10-02
    • 2011-08-18
    • 2013-05-06
    • 1970-01-01
    • 2017-07-29
    • 1970-01-01
    • 2021-02-10
    • 1970-01-01
    相关资源
    最近更新 更多