为什么对实例方法的引用存储在每个实例对象中而不是存储在类对象中?

时间:2012-03-19 16:31:43

标签: python methods python-3.x internals

据我所知,类的每个实例都存储对实例方法的引用。

我认为,在概念上,类的所有实例都具有相同的实例方法。如果是这样,内存节省和逻辑清晰度似乎都表明实例方法应该存储在类对象而不是实例对象中(实例对象通过类对象查找它们;当然,每个实例都有一个对它的引用类)。为什么不这样做?

第二个问题。为什么实例方法不能以类似于实例属性的方式访问,即通过__dict__或通过其他系统属性?有没有办法查看(也许更改)名称和对实例方法的引用?

编辑:

哎呀,抱歉。我完全错了。我看到了以下Python 2代码,并错误地从中得出结论,实例方法存储在实例中。我不确定它是做什么的,因为我不使用Python 2,new已经从Python 3中删除。

import new
class X(object):
  def f(self):
    print 'f'
a = X()
b = X()
def g(self):
  print 'g'
# I thought this modified instance method just in a, not in b
X.f = new.instancemethod(g, a, X)

4 个答案:

答案 0 :(得分:6)

Python中对象的属性查找非常重要。但实例方法肯定不存储在实例对象上!

  

属性访问的默认行为是从对象的字典中获取,设置或删除属性。例如,a.x的查询链以a.__dict__['x']开头,然后是type(a).__dict__['x'],并继续通过type(a)的基类排除元类。

docs

请注意, 可以在实例上存储函数。但那不是实例方法!当解释器查找属性并发现它是(a)函数和(b)类对象时,它会自动将它包装在通过self的绑定方法对象中。


  

有没有办法查看(也许更改)名称和对实例方法的引用?

嗯,您可以在定义后修改类对象。但我认为你的意思是“你可以使特定实例的x方法做一些不同的事情吗?”

这是Python,答案是“是”:只需将a.x定义为一些新功能。然后在查看课程之前,您将获得该功能。

但是,当您尝试理解代码时,这可能会让您感到困惑!

答案 1 :(得分:5)

  

据我所知,类的每个实例都存储对实例方法的引用。

我不知道你从哪里得到这个,但这是错的。他们没有。

  

为什么实例方法无法以类似于实例属性的方式访问,即通过__dict__或其他系统属性?

好吧,因为它们没有存储在实例上。

  

有没有办法查看(也许更改)名称和对实例方法的引用?

由于这些引用不存在,您无法更改它们。您当然可以通过正常分配创建所需的任何属性,但请注意,实例上存储的函数不会像普通方法那样对待 - 隐式传递self参数的机制不适用于它们。

答案 2 :(得分:1)

不正确的。实例不存储对每个方法的引用。

例如:

class Foo():
    def bar(self):
        print 'bar'

f = Foo()
def alternate_bar(self):
    print 'alternate bar'

f.bar()    
Foo.bar = alternate_bar # modifies the class!
f.bar()

打印

bar
alternate bar

这也是您为类中定义的每个方法提供self的原因。如果没有self的引用,该方法就不知道它正在处理哪个实例。

答案 3 :(得分:1)

另一个例子

class Point:
    def __init__(self, xcoord, ycoord):
        self.x = xcoord
        self.y = ycoord
    def draw(self):
        print self.x, " ", self.y

p = Point(205.12, 305.21)

#draw the coordinates of the point instance

p.draw()

# now define a new point drawing function vdraw()

def vdraw(q):
    print "[",q.x,",",q.y,"]"

#p.draw()

#now reassign the draw() method to vdraw()

Point.draw = vdraw

# now print the coordinates of the point instance 

print p.x
print p.y

#now draw the coordinates of the point instance
p.draw()