es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿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

Tags:  , , ,

Answer

  1. Avatar for 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 un AttributeError si no existe.

    Aquí está el código actualizado:

    class State:
        """
        Entidad de estado proporcionada para uso del usuario;
    
        Para lograr el entrenamiento por puntos de interrupción, el usuario debe asegurarse de que la información guardada
        sea serializable;
    
        # TODO: Podría ser necesario proporcionar una función para guardar este estado, pero los usuarios pueden implementar
        su propia función de devolución de llamada, en este momento no nos ocuparemos de eso;
        """
    
        def __init__(self):
            self._value = dict()
    
        def __setattr__(self, key, value):
            if key in self._value:
                super().__setattr__(key, value)
            else:
                self._value[key] = value
    
        def __getattr__(self, item):
            if item in self._value:
                return self._value[item]
            else:
                raise AttributeError(f"{self.__class__.__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 cargar de nuevo un dictado de estado por razones como el entrenamiento por "
                                 "puntos de interrupción, este parámetro debe ser de tipo dict.")
            self._value = value
    

    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 un RecursionError. Al modificar __setattr__ para configurar solo nuevos atributos, podemos evitar este problema.

Comments are closed.