¿Por qué las referencias a los métodos de instancia se almacenan en cada objeto de instancia en lugar de en el objeto de clase?

Por lo que entiendo, cada instancia de una clase almacena referencias a los métodos de la instancia.

Pensé, en concepto, que todas las instancias de una clase tienen los mismos métodos de instancia. Si es así, tanto el ahorro de memoria como la claridad lógica parecen sugerir que los métodos de instancia deberían almacenarse en el objeto de clase en lugar del objeto de instancia (con el objeto de instancia buscando en ellos a través del objeto de clase; por supuesto, cada instancia tiene una referencia a su clase). ¿Por qué no se hace esto?

Una pregunta secundaria. ¿Por qué los métodos de instancia no son accesibles de una manera similar a los atributos de instancia, es decir, a través de __dict__ , o a través de algún otro atributo del sistema? ¿Hay alguna forma de ver (y tal vez cambiar) los nombres y las referencias a los métodos de instancia?

EDITAR:

Ups, lo siento. Estaba totalmente equivocado. Vi el siguiente código de Python 2 y, de forma incorrecta, llegué a la conclusión de que los métodos de instancia se almacenan en las instancias. No estoy seguro de lo que hace, ya que no uso Python 2, y lo new existe en 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 Xf = new.instancemethod(g, a, X) 

Por lo que entiendo, cada instancia de una clase almacena referencias a los métodos de la instancia.

No sé de dónde sacaste esto, pero está mal. Ellos no

¿Por qué los métodos de instancia no son accesibles de una manera similar a los atributos de instancia, es decir, a través de __dict__ , o a través de algún otro atributo del sistema?

Bueno, porque no están almacenados en la instancia.

¿Hay alguna forma de ver (y tal vez cambiar) los nombres y las referencias a los métodos de instancia?

Como estas referencias no existen, no puedes cambiarlas. Por supuesto, puede crear cualquier atributo que desee mediante asignaciones normales, pero tenga en cuenta que las funciones almacenadas en la instancia no se tratan como métodos ordinarios: el mecanismo que pasa implícitamente el parámetro self no se aplica a ellos.

La búsqueda de atributos en objetos en Python no es trivial. ¡Pero los métodos de instancia ciertamente no se almacenan en el objeto de instancia!

El comportamiento predeterminado para el acceso a atributos es obtener, configurar o eliminar el atributo del diccionario de un objeto. Por ejemplo, ax tiene una cadena de búsqueda que comienza con a.__dict__['x'] , luego type(a).__dict__['x'] , y continúa a través de las clases base de type(a) excluyendo metaclases.

( docs )

Tenga en cuenta que es posible almacenar una función en una instancia. ¡Pero eso no es un método de instancia! Cuando el intérprete busca un atributo y encuentra que es (a) una función y (b) en el objeto de clase, lo envuelve automáticamente en un objeto de método enlazado que se pasa a self .


¿Hay alguna forma de ver (y tal vez cambiar) los nombres y las referencias a los métodos de instancia?

Bueno, ciertamente puedes modificar el objeto de clase después de definirlo. Pero supongo que lo que quiere decir es “¿puede hacer que el método x de una instancia en particular haga algo diferente?”

Siendo Python, la respuesta es “sí”: simplemente defina ax como una nueva función. Luego, recuperarás esa función antes de mirar a la clase.

¡Esto puede causarle mucha confusión cuando intenta entender el código, sin embargo!

Incorrecto. Las instancias no almacenan referencias a cada método.

Por ejemplo:

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

huellas dactilares

 bar alternate bar 

Esta es también la razón por la que se proporciona un self a cada método que define en una clase. Sin una referencia a self , el método no tiene idea de en qué instancia está trabajando.

Otro ejemplo

 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 "[",qx,",",qy,"]" #p.draw() #now reassign the draw() method to vdraw() Point.draw = vdraw # now print the coordinates of the point instance print px print py #now draw the coordinates of the point instance p.draw()