将函数分配给对象属性

时间:2011-06-25 14:28:08

标签: python methods

根据我对Python's data model的理解,特别是“实例方法”这一小节,每当你读取一个值为“用户定义函数”类型的属性时,一些魔法就会启动,你得到一个绑定的实例方法而不是实际的原始函数。这就是为什么在调用方法时没有显式传递self参数的原因。

但是,我希望能够用具有相同签名的函数替换对象的方法:

class Scriptable:
    def __init__(self, script = None):
        if script is not None:
            self.script = script   # replace the method
    def script(self):
        print("greetings from the default script")

>>> scriptable = Scriptable()
>>> scriptable.script()
greetings from the default script

>>> def my_script(self):
...     print("greetings from my custom script")
...
>>> scriptable = Scriptable(my_script)
>>> scriptable.script()
Traceback (most recent call last):
  ...
TypeError: script() takes exactly 1 positional argument (0 given)

我正在创建Scriptable的实例,并将其script属性设置为具有单个参数的用户定义函数,就像在类中定义的那样。因此,当我阅读scriptable.script属性时,我会期待魔法开始并给我一个不带参数的绑定实例方法(就像我没有替换script时那样)。相反,它似乎回馈了我传入的完全相同的函数,self参数和所有。方法绑定魔法没有发生。

为什么在我在类声明中定义方法时,方法绑定魔法会起作用,但在我分配属性时却不行?是什么让Python以不同的方式对待这些情况?

如果它有任何不同,我正在使用Python3。

4 个答案:

答案 0 :(得分:15)

以下是您的操作方法:

import types
class Scriptable:
    def __init__(self, script = None):
        if script is not None:
            self.script = types.MethodType(script, self)   # replace the method
    def script(self):
        print("greetings from the default script")

作为评论中提到的ba _friend,方法存储在class对象上。当您从实例访问属性时,类对象上的描述符将函数作为绑定方法返回。

当你为instance分配一个函数时,没有任何特殊情况发生,所以你必须自己包装这个函数。

答案 1 :(得分:9)

感谢Alex Martelli的answer这是另一个版本:

class Scriptable:
    def script(self):
        print(self)
        print("greetings from the default script")

def another_script(self):
    print(self)
    print("greetings from the another script")

s = Scriptable()
s.script()

# monkey patching:
s.script = another_script.__get__(s, Scriptable)
s.script()

答案 2 :(得分:6)

看看这个:

>>> scriptable = Scriptable()
>>> scriptable.script
<bound method Scriptable.script of <__main__.Scriptable instance at 0x01209DA0>>
>>> scriptable = Scriptable(my_script)
>>> scriptable.script
<function my_script at 0x00CF9730>

语句self.script = script只创建一个类对象的属性,没有任何“魔法”。

类定义中的语句def script(self):创建一个描述符 - 实际使用self参数管理所有内容的特殊对象。

您可以在上面提到的数据模型参考中阅读有关Python中描述符的更多信息:implementing-descriptors

Raymond Hettinger关于Python中描述符的另一篇精彩文章: How-To Guide for Descriptors

答案 3 :(得分:1)

我无法真正回答你的问题为什么它是这样的,你必须问Guido van Rossum,但我可以给你一个可能的解决方法:

class Scriptable:
    def __init__(self, script = None):
        self._script = script # replace the method
    def script(self):
        if self._script: return self._script(self)
        return self._defaultscript()
    def _defaultscript(self):
        print("greetings from the default script")