poo - programacion orientada a objetos python pdf
Python: ¿Qué sucede cuando el atributo de clase, el atributo de instancia y el método tienen todos el mismo nombre? (4)
¿Cómo distingue Python un atributo de clase, un atributo de instancia y un método cuando los nombres son los mismos?
class Exam(object):
test = "class var"
def __init__(self, n):
self.test = n
def test(self):
print "method : ",self.test
test_o = Exam("Fine")
print dir(test_o)
print Exam.test
print test_o.test
test_o.test()
Salida:
[''__class__'', ''__delattr__'', ''__dict__'', ''__doc__'', ''__format__'', ''__getattribute__'', ''__hash__'', ''__init__'', ''__module__'', ''__new__'', ''__reduce__'', ''__reduce_ex__'', ''__repr__'', ''__setattr__'', ''__sizeof__'', ''__str__'', ''__subclasshook__'', ''__weakref__'', ''test'']
<unbound method load.test>
Fine
Traceback (most recent call last):
File "example.py", line 32, in <module>
test_o.test()
TypeError: ''str'' object is not callable
Como llamar
- atributo de clase,
Exam.test
-><unbound method load.test>
output muestra el método - atributo de instancia
test_o.test
->"Fine"
- método
test_o.test()
->TypeError: ''str'' object is not callable
Como llamar
atributo de clase,Exam.test
No se puede porque al ejecutar def test(self)
la test
nombre está ligada al método en la clase y la referencia a "class var"
se pierde.
atributo de instancia
test_o.test
-> "Bien"
Ya hiciste eso.
método
test_o.test()
No puede llamarlo así porque al ejecutar self.test = n
la test
del nombre está vinculada a cualquier objeto n
referencias en la instancia y se pierde la referencia al método en la instancia.
Pero como se señaló en otras respuestas, puede llamar al método en la clase y pasarle la instancia: Exam.test(test_o)
Los atributos de clase son accesibles a través de la clase:
YourClass.clsattribute
o a través de la instancia (si la instancia no ha sobrescrito el atributo de clase):
instance.clsattribute
Los métodos, tal como lo establece ecatmur en su respuesta , son descriptores y se establecen como atributos de clase.
Si accede a un método a través de la instancia, la instancia se pasa como el parámetro self
al descriptor. Si desea llamar a un método de la clase, debe pasar explícitamente una instancia como primer argumento. Entonces estos son equivalentes:
instance.method()
MyClass.method(instance)
Usar el mismo nombre para un atributo de instancia y un método hará que el método se oculte a través de la instancia, pero el método todavía está disponible a través de la clase:
#python3
>>> class C:
... def __init__(self):
... self.a = 1
... def a(self):
... print(''hello'')
...
>>> C.a
<function a at 0x7f2c46ce3c88>
>>> instance = C()
>>> instance.a
1
>>> C.a(instance)
hello
Conclusión: no den el mismo nombre a los atributos y métodos de la instancia. Evito esto dando nombres significativos. Los métodos son acciones, por lo que usualmente uso verbos u oraciones para ellos. Los atributos son datos, por lo que uso sustantivos / adjetivos para ellos, y esto evita usar los mismos nombres para ambos métodos y atributos.
Tenga en cuenta que simplemente no puede tener un atributo de clase con el mismo nombre que un método, porque el método lo anularía completamente (al final, los métodos son solo atributos de clase que son invocables y que automáticamente reciben una instancia de la clase como primer atributo) .
Puede llamar al método como método de clase y pasar su instancia en él:
Exam.test(test_o)
O bien, si no desea usar el Exam
:
type(test_o).test(test_o)
Puedes escribir
Exam.test(test_o)
o
Exam.test.__get__(test_o)()
En este último caso, está utilizando el hecho de que los métodos son descriptors para convertir el <unbound method load.test>
a un método vinculado, por lo que puede llamarlo con corchetes individuales.
Cuando escribe test_o.test()
, Python no sabe que está intentando llamar a un método; es posible que intente llamar a una función o objeto invocable que se haya instalado en el objeto como un miembro de datos de instancia. En cambio, busca la test
atributo, primero en el objeto y luego en su clase, pero como el atributo existe en el objeto, oculta el método en la clase.
El miembro de la clase
test = "class var"
no es accesible (de hecho, no existe en ninguna parte), porque está sobrescrito por la test
método; cuando se ejecuta una declaración de class
, su espacio de nombre se recopila en un dict antes de pasarlo a su metaclase, y los nombres posteriores anulan los anteriores.