Comprobando la existencia de una propiedad
En Python, a diferencia de algunos lenguajes de programación, no todos los objetos de una misma clase tienen que tener los mismos atributos. Esto puede llevar a situaciones donde intentamos acceder a un atributo que no existe, lo que genera un error común llamado AttributeError.
Consideremos el siguiente ejemplo:
class ClaseEjemplo:
def __init__(self, val):
if val % 2 != 0:
self.a = 1
else:
self.b = 1
objeto = ClaseEjemplo(1)
print(objeto.a)
print(objeto.b)
En este caso, la clase ClaseEjemplo define dos atributos potenciales, a y b, que se asignan condicionalmente en función del valor pasado al constructor. Si el valor es impar, se asigna a, y si es par, se asigna b.
- Se instancia un objeto
objetocon el valor1, lo que provoca que se asigne el atributoa. - Al intentar imprimir
objeto.a, Python devuelve el valor1, lo que indica que el atributoaexiste. - Sin embargo, cuando se intenta acceder a
objeto.b, Python lanza un error:
Traceback (most recent call last):
File "main.py", line 11, in <module>
print(objeto.b)
AttributeError: 'ClaseEjemplo' object has no attribute 'b'
Este error ocurre porque el atributo b nunca fue definido en el objeto cuando el valor 1 fue pasado al constructor.
Manejando la excepción
Podemos evitar este error utilizando la instrucción try-except, veamos un ejemplo:
class ClaseEjemplo:
def __init__(self, val):
if val % 2 != 0:
self.a = 1
else:
self.b = 1
objeto = ClaseEjemplo(1)
# Intento de acceso a atributo inexistente con manejo de excepciones
try:
print(objeto.b)
except AttributeError:
print("El atributo 'b' no existe.")
La función hasattr()
Python nos ofrece una solución más clara y eficiente mediante la función incorporada hasattr(). Esta función recibe dos argumentos: el objeto o clase a verificar y el nombre del atributo (como una cadena de texto). Retorna True si el atributo existe, y False si no es así. Usarla evita depender de excepciones para controlar el flujo del programa.
Veamos el mismo ejemplo con hasattr():
class ClaseEjemplo:
def __init__(self, val):
if val % 2 != 0:
self.a = 1
else:
self.b = 1
objeto = ClaseEjemplo(1)
# Acceso seguro usando hasattr
print(objeto.a)
if hasattr(objeto, 'b'):
print(objeto.b)
else:
print("El atributo 'b' no existe.")
Uso de hasattr() con clases
Además de comprobar si un atributo existe en una instancia de clase, la función hasattr() también puede verificar si una clase en sí contiene un atributo de clase. Esta funcionalidad es útil para determinar la disponibilidad de variables o atributos a nivel de clase, sin instanciarla.
Veamos el siguiente ejemplo:
class ClaseEjemplo:
a = 1 # Atributo de clase
def __init__(self):
self.b = 2 # Atributo de instancia
objeto = ClaseEjemplo()
print(hasattr(objeto, 'b')) # Verifica si la instancia tiene el atributo 'b'
print(hasattr(objeto, 'a')) # Verifica si la instancia tiene acceso al atributo de clase 'a'
print(hasattr(ClaseEjemplo, 'b')) # Verifica si la clase tiene el atributo 'b'
print(hasattr(ClaseEjemplo, 'a')) # Verifica si la clase tiene el atributo de clase 'a'
print(hasattr(objeto, 'b')): Este atributo es definido dentro del constructor__init__como un atributo de instancia, por lo que el objetoobjetosí tiene el atributob. La salida seráTrue.print(hasattr(objeto, 'a')): Aunqueaes un atributo de clase y no un atributo de instancia, las instancias pueden acceder a los atributos de clase. Por lo tanto, este comando también devolveráTrue.print(hasattr(ClaseEjemplo, 'b')): Este atributo (b) solo existe en las instancias de la clase, no a nivel de clase. Por lo tanto, la claseClaseEjemplono tiene el atributob, y la salida seráFalse.print(hasattr(ClaseEjemplo, 'a')):aes un atributo de clase, por lo que la claseClaseEjemplotiene acceso directo a él, y la salida seráTrue.
Cuestionario
-
¿Cuáles de las propiedades de la clase Python son variables de instancia y cuáles son variables de clase? ¿Cuáles de ellos son privados?
class Python: population = 1 victims = 0 def __init__(self): self.length_ft = 3 self.__venomous = False -
Vas a negar la propiedad
__venomousdel objetoversion_2, ignorando el hecho de que la propiedad es privada. ¿Cómo vas a hacer esto?version_2 = Python() -
Escribe una expresión que compruebe si el objeto
version_2contiene una propiedad de instancia denominadaconstrictor(¡si,constrictor!).
Solución cuestionario
-
Ejercicio 1
populationyvictimsson variables de clase, mientras quelengthy__venomousson variables de instancia (esta última también es privada). -
Ejercicio 2
version_2._Python__venomous = not version_2._Python__venomous -
Ejercicio 3
hasattr(version_2, 'constrictor')