POO: Propiedades en Python
Este documento explora las variables de instancia y de clase en Python. Se abordarán las diferencias entre estos tipos de variables, su uso adecuado y cómo afectan el comportamiento de las instancias de una clase.

Variables de Instancia
En la Programación Orientada a Objetos (POO), una variable de instancia representa un atributo propio de cada objeto, definido típicamente dentro del método constructor __init__
de la clase. Dicha variable se caracteriza por pertenecer exclusivamente a una instancia específica, lo que significa que cada objeto creado a partir de una clase posee una copia única de esta variable. Esta característica permite almacenar información particular y diferenciada para cada instancia, reflejando las características individuales de cada objeto en el contexto de la programación.
Se definen generalmente dentro del constructor de la clase, y su valor puede variar dependiendo del objeto en el que se encuentren.
Ejemplo de Uso de Variables de Instancia
class Carro:
def __init__(self, marca, modelo):
# Variables de instancia
self.marca = marca
self.modelo = modelo
def mostrar_info(self):
print(f"Marca: {self.marca}, Modelo: {self.modelo}")
# Creando instancias de la clase Carro
carro1 = Carro("Toyota", "Corolla")
carro2 = Carro("Honda", "Civic")
# Accediendo a las variables de instancia
carro1.mostrar_info() # Imprime: Marca: Toyota, Modelo: Corolla
carro2.mostrar_info() # Imprime: Marca: Honda, Modelo: Civic
En este ejemplo:
-
marca
ymodelo
son variables de instancia, ya que se asignan a cada objeto creado de la clase Carro. -
carro1
ycarro2
son instancias de la clase, y cada una tiene sus propias versiones demarca
ymodelo
, con valores diferentes.
Uso de Variables Privadas
En Python, cuando se utilizan dos guiones bajos (__
) al inicio de una variable de instancia, se está aplicando un mecanismo llamado mangling de nombres. Este mecanismo cambia el nombre interno de la variable para evitar que sea sobrescrita o modificada accidentalmente desde fuera de la clase. Es una forma de hacer que la variable sea "privada" para la clase, aunque sigue siendo accesible internamente.
Ejemplo de Uso de Variables de Instancia con Dos Guiones Bajos
class Carro:
def __init__(self, marca, modelo):
# Variables de instancia con mangling (privadas)
self.__marca = marca
self.__modelo = modelo
def mostrar_info(self):
print(f"Marca: {self.__marca}, Modelo: {self.__modelo}")
def cambiar_marca(self, nueva_marca):
self.__marca = nueva_marca
# Creando instancias de la clase Carro
carro1 = Carro("Toyota", "Corolla")
carro1.mostrar_info() # Imprime: Marca: Toyota, Modelo: Corolla
# Intentando acceder a la variable de instancia directamente
# print(carro1.__marca) # Esto dará error: AttributeError
# Accediendo a través de un método
carro1.cambiar_marca("Honda")
carro1.mostrar_info() # Imprime: Marca: Honda, Modelo: Corolla
Acceso Interno
A pesar de que las variables son "privadas", Python no impide su acceso, sino que lo hace menos accesible al cambiar su nombre internamente. A través de la técnica de "name mangling", se pueden acceder de la siguiente manera:
print(carro1._Carro__marca) # Imprime: Honda
Sin embargo, no se recomienda acceder directamente a las variables privadas fuera de la clase. En lugar de eso, es preferible utilizar métodos para modificar o acceder a estos atributos.
Variables de Clase
Las variables de clase son aquellas que se definen dentro de la clase pero fuera de cualquier método. Estas variables son compartidas entre todas las instancias de la clase. Si se modifica una variable de clase, el cambio se reflejará en todas las instancias que no tengan su propia variable de instancia con el mismo nombre.
Características de las Variables de Clase
- Valor compartido: Todas las instancias de la clase tienen acceso al mismo valor para una variable de clase.
- Definición: Se define dentro de la clase, fuera de los métodos, con una sintaxis similar a la de cualquier otro atributo de clase.
- Acceso: Se puede acceder a ella mediante la clase o mediante una instancia de la clase, pero si se modifica desde una instancia, esa modificación no afectará a otras instancias.
Ejemplo en Python de Variables de Clase
class Carro:
# Variable de clase
ruedas = 4
def __init__(self, marca, modelo):
self.marca = marca
self.modelo = modelo
def mostrar_info(self):
print(f"{self.marca} {self.modelo} tiene {Carro.ruedas} ruedas.")
# Crear instancias de la clase Carro
carro1 = Carro("Toyota", "Corolla")
carro2 = Carro("Honda", "Civic")
# Acceder a la variable de clase
carro1.mostrar_info() # Toyota Corolla tiene 4 ruedas.
carro2.mostrar_info() # Honda Civic tiene 4 ruedas.
En este ejemplo, la variable ruedas
es una variable de clase, lo que significa que ambas instancias (carro1
y carro2
) comparten el valor de 4
para el número de ruedas. Si se cambiara el valor de ruedas a través de la clase, todas las instancias reflejarían ese cambio.
Cambio de Valor a Variable de Clase
Para cambiar el valor de una variable de clase en Python, se puede hacer de dos maneras:
Accediendo a través de la Clase
El valor de una variable de clase se puede modificar directamente utilizando el nombre de la clase. Esta modificación afectará a todas las instancias de la clase que no hayan sobrescrito esa variable.
class Carro:
# Variable de clase
ruedas = 4
# Cambiar el valor de la variable de clase
Carro.ruedas = 6
# Crear instancias de la clase Carro
carro1 = Carro()
carro2 = Carro()
# Ver el valor de la variable de clase
print(carro1.ruedas) # 6
print(carro2.ruedas) # 6
En este caso, la variable de clase ruedas se cambia a 6
a través de la clase Carro
. Ahora, ambas instancias (carro1
y carro2
) reflejan el nuevo valor de 6
.
Accediendo a través de una Instancia (No Recomendado)
También es posible cambiar una variable de clase a través de una instancia de la clase. Sin embargo, este cambio no afectará a las demás instancias, ya que en realidad se creará una nueva variable de instancia para esa instancia específica.
class Carro:
# Variable de clase
ruedas = 4
# Crear una instancia de la clase
carro1 = Carro()
# Cambiar la variable de clase a través de la instancia
carro1.ruedas = 6
# Crear otra instancia
carro2 = Carro()
# Ver el valor de la variable de clase
print(carro1.ruedas) # 6 (modificación a nivel de instancia)
print(carro2.ruedas) # 4 (variable de clase sin cambios)
En este caso, el valor de ruedas cambia a 6
para carro1
, pero la variable de clase ruedas
sigue siendo 4
para carro2. Esto sucede porque al acceder a la variable de clase a través de la instancia, Python crea una nueva variable de instancia local a esa instancia.
Diferencia con las Variables de Instancia
- Variables de instancia: Son atributos que pertenecen a un objeto específico. Cada instancia tiene su propio valor para esas variables.
- Variables de clase: Son compartidas por todas las instancias de una clase.
Comprobando la Existencia de un Atributo
En Python, se pueden usar varias técnicas para comprobar si un objeto o una clase tiene un atributo específico. Algunas de las formas más comunes de hacer esto son:
Usando hasattr()
La función hasattr()
permite verificar si un objeto o clase tiene un atributo determinado. Devuelve True si el atributo existe y False si no.
hasattr(objeto, "atributo")
Ejemplo:
class Carro:
def __init__(self, marca):
self.marca = marca
carro1 = Carro("Toyota")
# Comprobar si carro1 tiene el atributo 'marca'
print(hasattr(carro1, "marca")) # True
# Comprobar si carro1 tiene el atributo 'modelo'
print(hasattr(carro1, "modelo")) # False
En este caso, hasattr(carro1, "marca")
devuelve True
porque el objeto carro1
tiene el atributo marca
, mientras que hasattr(carro1, "modelo")
devuelve False
porque no tiene un atributo llamado modelo.
Usando getattr() con un valor por defecto
La función getattr()
se utiliza para obtener el valor de un atributo, y si el atributo no existe, puede devolver un valor por defecto en lugar de lanzar una excepción. Esto también permite comprobar si el atributo existe.
getattr(objeto, "atributo", valor_por_defecto)
Ejemplo:
class Carro:
def __init__(self, marca):
self.marca = marca
carro1 = Carro("Toyota")
# Usando getattr para comprobar si el atributo 'modelo' existe
modelo = getattr(carro1, "modelo", None)
# Si el atributo no existe, se devuelve 'None'
print(modelo) # None
En este caso, getattr(carro1, "modelo", None)
devuelve None
porque el atributo modelo
no existe en carro1
.
Usando __dict__
El atributo especial __dict__
de un objeto contiene todos los atributos de instancia del objeto. Puedes verificar si un atributo específico está presente en __dict__
.
Ejemplo:
class Carro:
def __init__(self, marca):
self.marca = marca
carro1 = Carro("Toyota")
# Comprobar si el atributo 'marca' existe en __dict__ de carro1
print("marca" in carro1.__dict__) # True
# Comprobar si el atributo 'modelo' existe en __dict__ de carro1
print("modelo" in carro1.__dict__) # False
En este ejemplo, se utiliza carro1.__dict__
para comprobar si los atributos marca
y modelo
están en el diccionario de atributos de la instancia.
Resumen
-
codehasattr()
: Comprueba si un objeto tiene un atributo determinado. -
getattr()
: Permite obtener un atributo y proporciona un valor por defecto si no existe. -
__dict__
: Proporciona un diccionario con los atributos de la instancia, que se puede usar para verificar si un atributo existe.