2012-11-15 71 views
5

我知道,在Python有可能在运行时的方法添加到类:覆盖在运行时__setattr__

class Test: 
    def __init__(self): 
     self.a=5 

test=Test() 

import types 
def foo(self): 
    print self.a 
test.foo = types.MethodType(foo, test) 
test.foo() #prints 5 

而且我也知道,它可能覆盖默认SETATTR类定义:

class Test: 
    def __init__(self): 
     self.a=5 
    def __setattr__(self,name,value): 
     print "Possibility disabled for the sake of this test" 

test=Test() #prints the message from the custom method called inside __init__ 

然而,现在看来,这是不可能的,在运行时SETATTR覆盖:

class Test: 
    def __init__(self): 
     self.a=5 

test=Test() 

import types 
def __setattr__(self,name,value): 
    print "Possibility disabled for the sake of this test" 
test.__setattr__ = types.MethodType(__setattr__, test) 
test.a=10 #does the assignment instead of calling the custom method 

在最后两种情况下,dir(测试)还报告了方法setattr。但是,在第一种情况下,它正常工作,而在第二种情况下则不正确。请注意,我也可以明确地调用它,在这种情况下它可以工作。似乎是这样,虽然该方法已被定义,但尚未正确映射以覆盖默认分配方法。我错过了什么吗?

我正在使用Python 2.7。问题主要是学术问题,因为从程序设计的角度来看,做这样的事情可能不是一个好主意,但它仍然值得回答 - 尽管我搜索了,但我无法在任何地方找到它。

回答

2

见Python文档的这一部分:Special method lookups for new-style classes

对于新样式类,特殊的方法隐含调用是只能保证正常工作,如果一个对象的类型定义,而不是在对象的实例字典。

请按照链接了解这背后的基本原理。我理解的基本思想是,适用于实例对象和类型对象(如__repr__)的特殊方法需要一致调用,而不是有时需要显式参数,有时需要接收隐式参数。通过始终调用对象类型的方法,我们知道总是传递一个明确的参数 - 但副作用是实例字典被绕过。

+0

请注意,这明确地说“新风格的类”,而OP在他的示例中有一个旧式类 – lqc

3

它记录在Data model,部分“类实例”:

属性分配和删除更新实例的字典里,从来没有 类的字典。 如果类有一个__setattr__()__delattr__()方法,则调用此方法而不是直接更新实例字典。

因此,无论是旧式还是新式,这两种检查总是在类型上进行,而不是在实例上进行。

+0

谢谢,我确实看了一下Data模型,但我错过了那部分。那么我在我发布的代码中看到的行为就很有道理。也许一个愚蠢的问题:当它说“如果这个类有一个__setattr__”,那么这个负面可能性实际上是否存在?是否有可能创建一个没有__setattr__的类? – Spock