Solución:
Un atributo es una variable que se busca en otro objeto usando la sintaxis de puntos: obj.attribute
. La forma en que está diseñado Python, las búsquedas de atributos pueden hacer una variedad de cosas, y esa variedad a veces puede provocar errores si realmente no comprende lo que está sucediendo (esto es sobre lo que advierte la documentación que vinculó).
El problema más básico es que una búsqueda de atributos puede encontrar un valor almacenado en el diccionario de instancia del objeto o puede encontrar algo de la clase del objeto (o una clase base, si hay herencia). Los métodos son funciones almacenadas en la clase, pero normalmente las usa buscándolas en una instancia (que “enlaza” el método, insertando el objeto como el primer argumento cuando se llama al método).
La secuencia exacta de lo que se verifica cuando es un poco complicada (describí el proceso completo en una respuesta a otra pregunta), pero en el nivel más básico, los atributos de instancia generalmente tienen prioridad sobre el atributo de clase.
Si existen un atributo de instancia y un atributo de clase con el mismo nombre, normalmente solo se podrá acceder al atributo de instancia. Esto puede resultar muy confuso si no es intencionado.
Considere el siguiente código:
class Foo(object):
def __init__(self, lst):
self.lst = lst
def sum(self):
self.sum = sum(self.lst)
return self.sum
f = Foo([1,2,3])
print(f.sum())
print(f.sum())
En la parte inferior de este código, hacemos dos llamadas idénticas. El primero funciona bien, pero el segundo generará una excepción.
Esto se debe a que la primera vez que miramos hacia arriba f.sum
encontramos un método en el Foo
clase. Podemos llamar al método sin problemas. El problema proviene del hecho de que el sum
El método asigna el resultado de su cálculo (la suma de los elementos en self.lst
) a un atributo de instancia también denominado sum
. Esto esconde el sum
método de la vista.
Cuando segundo f.sum()
llamada mira hacia arriba f.sum
, encuentra el atributo de instancia, que contiene el entero 6
, en lugar del método esperado. Un número entero no se puede llamar, por lo que obtenemos una excepción.
La solución, por supuesto, es no usar el mismo nombre para el método y el atributo. El código anterior es un ejemplo bastante trivial. Los errores causados por este tipo de cosas en un código más complejo pueden ser mucho más difíciles de descifrar.
Si está escribiendo código que agrega atributos a objetos de los que no sabe mucho, debe tener cuidado de evitar los nombres comunes. Si está escribiendo una clase mixin, considere usar dos guiones bajos iniciales en los nombres de los atributos para activar el cambio de nombre de Python, que está diseñado exactamente para este tipo de situación.
Un atributo es cualquier cosa por la falta de una palabra mejor vinculada a un objeto, por ejemplo:
class Dog:
def __init__(self):
self.name = "Rufus"
def bark(self):
print "Woof Woof!"
En este caso, el atributo de datos es el nombre, que es simplemente un valor vinculado a la instancia del Perro. En cuanto a un atributo de método, una respuesta sería el método de ladrido, ya que no es tanto un valor como una acción. Es como está en inglés. Un atributo de datos es exactamente como suena; son datos, es simplemente una propiedad. Un método es un procedimiento, una acción, y esto es exactamente lo que es un atributo de método.
Un atributo es básicamente cualquier cosa que puedas hacer instance.attribute_name
con. Por ejemplo en:
class Hello(object):
def __init__(self, word):
self.word = word
def greet(self):
print "Hello: "+self.word
__init__
, greet
y word
todos serían atributos. Supongo que un método es cualquier cosa que se declare con def en el alcance de la clase (en lugar de hacer self.func = lambda x: x * x, por ejemplo). En este caso, ingresa a métodos vinculados vs no vinculados y similares. La parte importante es que para un atributo de miembro cuando lo haces instance.method_name
obtienes un método vinculado, que cuando lo llamas llamará al método original con la instancia como primer argumento.
Además, después de leer parte de esa sección, su redacción es algo confusa / errónea. Por ejemplo, dicen “Los atributos de datos anulan los atributos de método con el mismo nombre”, lo que, hasta donde yo sé, sería mejor poner como atributo de instancia anular atributos de clase con el mismo nombre. Del ejemplo que di si expandimos esto a:
class Hello(object):
greeting = "Hello: "
def __init__(self, word):
self.word = word
def greet(self):
print self.greeting+self.word
Entonces podríamos hacer:
>>> a = Hello("world")
>>> a.greeting = "Goodbye "
>>> a.greet()
"Goodbye world"
Esto se debe al hecho de que colocamos un atributo de instancia de saludo sobre el atributo de clase de saludo. Dado que los métodos definidos en la clase (la forma habitual) son atributos de clase, serán reemplazados por cualquier atributo de instancia (datos o de otro tipo).