Почему ссылки на методы экземпляра хранятся в каждом объекте экземпляра, а не в объекте класса? - PullRequest
4 голосов
/ 19 марта 2012

Насколько я понимаю, каждый экземпляр класса хранит ссылки на методы экземпляра.

Я думал, что в принципе все экземпляры класса имеют одинаковые методы экземпляров. Если это так, то как экономия памяти, так и логическая ясность позволяют предположить, что методы экземпляра должны храниться в объекте класса, а не в объекте экземпляра (при этом объект экземпляра просматривает их через объект класса; конечно, каждый экземпляр имеет ссылку на свой объект). учебный класс). Почему это не сделано?

Вторичный вопрос. Почему методы экземпляра недоступны способом, аналогичным атрибутам экземпляра, т. Е. Через __dict__ или через какой-либо другой системный атрибут? Есть ли способ посмотреть (и, возможно, изменить) имена и ссылки на методы экземпляра?

EDIT:

Ой, прости. Я был совершенно неправ. Я видел следующий код 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 ]

6 голосов
/ 19 марта 2012

Поиск атрибутов на объектах в Python нетривиален.Но методы экземпляра определенно не хранятся в объекте экземпляра!

Поведение по умолчанию для доступа к атрибуту - получить, установить или удалить атрибут из словаря объекта.Например, a.x имеет цепочку поиска, начинающуюся с a.__dict__['x'], затем type(a).__dict__['x'] и продолжающуюся до базовых классов type(a), исключая метаклассы.

( docs )

Обратите внимание, что возможно для сохранения функции в экземпляре.Но это не метод экземпляра!Когда интерпретатор ищет атрибут и обнаруживает, что он (a) является функцией и (b) объекта класса, он автоматически оборачивает его в связанный объект метода, который передает self.


Есть ли способ посмотреть (и, возможно, изменить) имена и ссылки на методы экземпляра?

Что ж, вы, безусловно, можете изменить объект класса после его определения.Но я предполагаю, что вы имеете в виду «можете ли вы заставить x метод конкретного экземпляра сделать что-то другое?»

Это Python, ответ «да»: просто определитеa.x чтобы быть какой-то новой функцией.Затем вы вернете эту функцию обратно, прежде чем заглянуть в класс.

Это может вызвать у вас путаницу, когда вы пытаетесь понять код!

5 голосов
/ 19 марта 2012

Насколько я понимаю, каждый экземпляр класса хранит ссылки на методы экземпляра.

Я не знаю, откуда вы это взяли, но это неправильно.Они этого не делают.

Почему методы экземпляров недоступны способом, аналогичным атрибутам экземпляра, например, через __dict__ или через какой-либо другой системный атрибут?

Ну, потому что они не хранятся в экземпляре.

Есть ли способ посмотреть (и, возможно, изменить) имена и ссылки на методы экземпляра?

Поскольку эти ссылки не существуют, вы не можете их изменить.Конечно, вы можете создать любой атрибут, который хотите, с помощью обычных присваиваний, но обратите внимание, что функции, хранящиеся в экземпляре, не обрабатываются как обычные методы - механизм, который неявно передает параметр self, к ним не применяется.

1 голос
/ 19 марта 2012

Другой пример

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()
1 голос
/ 19 марта 2012

Неправильно.Экземпляры не хранят ссылки на каждый метод.

Например:

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()

print *

bar
alternate bar

Именно поэтому вы предоставляете self для каждого методаВы определяете в классе.Без ссылки на self метод не знает, над каким экземпляром он работает.

...