【问题标题】:Avoiding creating new method object避免创建新的方法对象
【发布时间】:2016-11-29 14:05:29
【问题描述】:

根据 Python 2.7.12 文档,

当属性是用户定义的方法对象时,新方法 仅当从中检索对象的类时才创建对象 与存储在 原始方法对象; 否则,原来的方法对象是 照原样使用。

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

# 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

【问题讨论】:

  • 试试:print Parent.func is Parent.func.
  • @Robᵩ print Parent.func is Parent.func 给出False,但print a is a 给出True

标签: python python-2.7 object inheritance methods


【解决方案1】:

每次你写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

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

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

我认为你误解了那句话的意思。这可能是因为引用对“属性”和通过获取该属性检索到的值之间的区别有些模糊。

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

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

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

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

obj = [a method object]

class Foo(object):
    attr = obj

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

func = [a function object]

class Foo(object):
    attr = func

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

【讨论】:

  • 但是为什么每次都返回一个新对象呢?
  • @Rawing:在您引用的同一文档中进一步查看:“请注意,每次从类中检索属性时,都会发生从函数对象到(未绑定或绑定)方法对象的转换,或者实例。”对象每次都不同的事实本质上是一个实现细节(在 Python 3 中未绑定的方法对象不再存在),但当然不能保证方法对象永远相同。
  • @Rawing:方法对象的寿命很短,很容易从空闲列表中分配。保留它们会增加内存消耗并使实现复杂化。
  • 谢谢。这正是我的引文所指的。
  • 嗯...你说“请注意,你给出的报价不适用于Parent.func”是什么意思?我知道函数定义def func(self): pass 给了我一个函数对象,而不是一个方法对象。 Parent.func 是一个属性访问,给了我一个方法对象,所以恕我直言,引用应该适用于它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-28
  • 1970-01-01
  • 2013-07-07
  • 1970-01-01
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
相关资源
最近更新 更多