避免创建新方法对象

时间:2016-07-26 04:45:04

标签: python python-2.7 object inheritance methods

根据Python 2.7.12文档,

  

当属性是用户定义的方法对象时,新方法   object仅在从中检索它的类时创建   与存储在中的类相同或派生类   原始方法对象; 否则,原始方法对象是   按原样使用。

我试图通过编写代码来理解这一段:

# Parent: The class stored in the original method object
class Parent(object):
    # func: The underlying function of original method object
    def func(self): 
        pass
    func2 = func

# Child: A derived class of Parent
class Child(Parent):
    # Parent.func: The original method object
    func = Parent.func

# AnotherClass: Another different class, neither subclasses nor subclassed
class AnotherClass(object):
    # Parent.func: The original method object
    func = Parent.func

a = Parent.func
b = Parent.func2
c = Child.func
d = AnotherClass.func

print b is a
print c is a
print d is a

输出结果为:

False
False
False

我希望它是:

False
False
True

1 个答案:

答案 0 :(得分:3)

每次编写Parent.func时,都会获得一个新的未绑定方法对象。所以AnotherClass.func永远不会改变,但Parent.func会改变。如果你这样做,你可以看到这个:

a = Parent.func
a2 = Parent.func
b = Parent.func2
c = Child.func
d = AnotherClass.func
d2 = AnotherClass.func

然后:

>>> a is a2
False
>>> d is d2
True

因此,您对“原始方法对象”的评论有些误导。评估Parent.func的代码的每个部分都获得了不同的方法对象。 (请注意,您提供的引用不适用于Parent.func,因为func中写的Parent不是方法对象;它是一个函数对象。只有当您访问时才通过编写Parent.func来获取方法对象的属性。)

我在这里添加一点来澄清你给出的报价。

我认为你误解了引用的内容。这可能是因为引用对于“属性”与获取该属性所检索的值之间的区别有些模糊。

让我通过分离两个概念来澄清。在像something.attr这样的表达式中,我将使用“原始值”来表示存储在类/对象字典中的实际值,即something.__dict__['attr']的值。我将使用“评估值”来指代评估something.attr的实际结果。两者之间的区别在于,在原始值上激活descriptor protocol以获得评估值。

您引用的文档描述了 raw 值是方法对象的情况。在Child和AnotherClass的定义中就是这种情况。引用适用于Parent内的func,因为在这种情况下,原始值不是方法;这是一个功能。在这种情况下,文件的以下段落适用:

  

通过检索用户定义的函数对象创建用户定义的方法对象时...

换句话说,您引用的文档(“当属性是用户定义的方法对象时”)适用于以下情况:

obj = [a method object]

class Foo(object):
    attr = obj

您引用的文档不适用于以下情况。在这种情况下,属性是“用户定义的函数对象”:

func = [a function object]

class Foo(object):
    attr = func

在您的示例中,没有“原始方法对象”。在定义类之后,您只能获取方法对象。 “原始”对象是一个功能对象。当您在类体中编写func时,您正在定义一个函数;只有当您访问 Parent.func时才能获得方法对象。