__init__
de la clase y se acceden utilizando la sintaxis self.nombre_atributo
__init__
__init__
y se acceden utilizando la sintaxis self.nombre
y self.edad
class Persona:
# Atributo de clase
esperanza_vida = 80
def __init__(self, nombre, edad):
# Atributo de instancia
self.nombre = nombre
self.edad = edad
# Crear dos objetos de la clase Persona
persona1 = Persona("Juan", 30)
persona2 = Persona("María", 25)
# Acceder a los atributos de cada objeto
print(persona1.nombre) # Salida: "Juan"
print(persona1.edad) # Salida: 30
print(persona2.nombre) # Salida: "María"
print(persona2.edad) # Salida: 25
# Acceder al atributo de clase desde la clase
print(Persona.esperanza_vida) # Salida: 80
# Acceder al atributo de clase desde un objeto
print(persona1.esperanza_vida) # Salida: 80
print(persona2.esperanza_vida) # Salida: 80
Juan 30 María 25 80 80 80
Podemos crear varios objetos de una misma clase. Cada uno de estos objetos puede tener diferentes valores para estos atributos, lo que les confiere sus propias características.
Por ejemplo, podemos tener dos instancias de la clase Perro (bobby y teddy) que tengan atributos como nombre, edad, raza, pelo, ... que sean diferentes y que identifican el carácter propio de cada uno de ellos.
Tener diferentes valores de los atributos es lo que define el estado de un objeto.
Existen dos tipos de atributos:
Por ejemplo, para la clase Perro son comunes genero = "Canis", orden = "Carnívora", cuadrupedo = True.
Por ejemplo, nombre, edad, raza, pelo,...
En general:
class Perro:
genero = "Canis" # atributos de clase compartidos por todas las instancias
orden = "Carnívora"
cuadrupedo = True
def __init__(self, nombre, raza):
self.nombre = nombre # atributos de instancia únicos para cada instancia
self.raza = raza
l = Perro('Laika', 'Siberiana')
k = Perro('Kasper', 'Pastor alemán')
l.genero # compartido por todos los perros
'Canis'
k.genero # compartido por todos los perros
'Canis'
l.nombre # único para l
'Laika'
k.nombre # único para k
'Kasper'
Supongamos que para recoger los trucos que saben hacer los perros creamos una variable trucos en forma de lista. Nuestro error será crearla como atributo de clase, común para todas las instancias, cuando debiera haber sido creado como atributo de instancia.
class Perro:
trucos = [] # uso incorrecto de una variable de clase
def __init__(self, nombre):
self.nombre = nombre
def incluir_truco(self, truco):
self.trucos.append(truco)
l = Perro('Laika')
k = Perro('Kasper')
l.incluir_truco('darse la vuelta')
k.incluir_truco('hacerse el muerto')
l.trucos # inesperadamente compartido por todas las instancias de la misma clase
['darse la vuelta', 'hacerse el muerto']
class Perro:
def __init__(self, nombre):
self.nombre = nombre
self.trucos = [] # creamos una lista vacía para cada perro
def incluir_truco(self, truco):
self.trucos.append(truco)
l = Perro('Laika')
k = Perro('Kasper')
l.incluir_truco('darse la vuelta')
k.incluir_truco('hacerse el muerto')
print(l.trucos) # ahora los trucos que sabe hacer cada perro están separados
print(k.trucos)
['darse la vuelta'] ['hacerse el muerto']
Se pueden modificar los atributos de clase desde fuera de la propia clase. Si existe el mismo nombre de atributo en la clase y en la instancia se prioriza el de la instancia.
class Bomberos:
helicoptero = False # atributos de clase ¿compartidos por todas las instancias?
region = 'Norte' # ¿Todas las estaciones de bombero que se instancian serán del Norte y sin helicóptero?
b1 = Bomberos() # Instanciamos la primera estación de bomberos y resulta ser del Norte y sin helicóptero
print(b1.helicoptero, b1.region)
False Norte
b2 = Bomberos() # Instanciamos la segunda estación de bomberos
b2.helicoptero = True # Podemos acceder a modificar el atributo de clase desde fuera de la clase
print(b2.helicoptero, b2.region) # Ahora vemos que esta estación de bomberos si tiene helicóptero
True Norte
# cambiar el atributo de b2 no afecta a b1
print(b1.helicoptero) # b1 continúa sin tener helicópteros
False
Python, por defecto, no impide, salvo por convenio, que un usuario pueda modificar un atributo de clase desde fuera de su propia clase.
En otros lenguajes, por ejemplo, en JAVA cualquier atributo que se declara ha de ser público (Public) o privado (Private), de forma que los privados no son accesibles desde fuera de su propia clase.
Al igual que una función puede desde el interior de su código llamar a otra función, un método (que es una función) puede llamar a otro método ambos dentro de una clase.
class Acuario:
def __init__(self):
self.poblacion = [] # atributo población en forma de lista, inicialmente vacía
def incluir(self, pez):
self.poblacion.append(pez)
def incluir_pareja(self, pez):
self.incluir(pez) # invocamos desde un método otro método dentro de la misma clase
self.incluir(pez) # volvemos a invocar el método incluir para hacer la pareja
a = Acuario() # instanciamos un objeto de tipo Acuario
a.incluir('Guppy') # Añadimos nuestro primer pez
a.poblacion # consultamos nuestra variable población
['Guppy']
a.incluir_pareja('Neón') # incluimos una pareja de peces
a.poblacion # al consultar la población vemos que se ha añadido la pareja
['Guppy', 'Neón', 'Neón']
type
y dir
¶type(a) # la instancia 'a' es un objeto de tipo Acuario
__main__.Acuario
type(a.incluir) # el método 'incluir' es de método
method
type(a.poblacion) # el atributo 'poblacion' es una variable de tipo lista
list
dir(a) # al hacer un dir de un objeto obtenemos todos sus atributos y métodos incluidos los especiales
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'incluir', 'incluir_pareja', 'poblacion']