¿Por qué no pude usar ‘__getattr__’ así en Python?
El código es así, quiero usar __getattr__
para hacer que la clase State sea útil y poder asignarle algunas propiedades, de modo que podamos usarlas más adelante, por ejemplo:
state = State()
state.name1 = 1
print(state.name1)
El código completo es así:
class State:
"""
Proporciona un estado utilizable para el usuario;
Para lograr un entrenamiento con punto de interrupción, el usuario debe asegurarse de que la información guardada sea serializable;
# TODO: Tal vez sea necesario proporcionar una función para guardar este estado, pero los usuarios pueden implementarla en el callback, por ahora no nos preocupamos por eso;
"""
def __init__(self):
self._value = dict()
def __setattr__(self, key, value):
self._value[key] = value
def __getattr__(self, item):
if item in self._value:
return self._value[item]
else:
raise AttributeError(f"{self.__name__} no tiene el atributo {item}.")
def state_dict(self):
return self._value
def load_state_dict(self, value: dict):
if not isinstance(value, dict):
raise ValueError("Si desea volver a cargar un state dict por razones como el entrenamiento con punto de interrupción, este parámetro value debe ser de tipo dict.")
self._value = value
Y el rastreo de error es así:
Traceback (most recent call last):
File "state.py", line 165, in <module>
a = State()
File "state.py", line 52, in __init__
self._value = dict()
File "state.py", line 55, in __setattr__
self._value[key] = value
File "state.py", line 58, in __getattr__
if item in self._value:
File "state.py", line 58, in __getattr__
if item in self._value:
File "state.py", line 58, in __getattr__
if item in self._value:
[Línea anterior repetida 993 veces]
RecursionError: se superó la profundidad máxima de recursión
davy.ai
Para hacer que la clase State sea útil para montar propiedades en ella usando
__getattr__
, podemos modificar el método__setattr__
para permitir la configuración de atributos solo si no existen ya en_value
. Luego, podemos usar__getattr__
para devolver el atributo solicitado si existe en_value
, o generar unAttributeError
si no existe.Aquí está el código actualizado:
El problema con el código original era que el método
__setattr__
permitía configurar cualquier atributo, incluidos los que ya existían en_value
. Esto provocaba un bucle infinito en el que_value
se volvía a acceder en__getattr__
, lo que resultaba en unRecursionError
. Al modificar__setattr__
para configurar solo nuevos atributos, podemos evitar este problema.