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.

Conflicto de función entre __get__ y __getattribute__

Estoy escribiendo código en Python 3.9 y recientemente descubrí los descriptores.

He creado una clase que se ve así:

import threading

class OuterClass():
    class DecoratorTest():
        def __init__(self, fget, fset=None) -> None:
            self.fget = fget
            self.fset = fset
            self.event = threading.Event()

        def __getattribute__(self, name: str):
            return object.__getattribute__(self, name)

        def __get__(self, obj, objtype=None):
            return self.fget(obj)

        def __set__(self, obj, value):
            self.fset(obj, value)
            self.event.set()
            self.event.clear()

        def setter(self, fset):
            return type(self)(self.fget, fset)

def __init__(self):
    self.random_value = 10

@DecoratorTest
def test_property(self):
    return self.random_value * 2

@test_property.setter
def test_property(self, value):
    self.random_value = value

Mi intención es tener un decorador que agregue un evento a la propiedad decorada, de modo que cuando se cambie la propiedad, se establezca el evento. Este es un ejemplo de cómo lo usaría:

class_iteration = OuterClass()

def test_funct():
    while True:
        class_iteration.test_property.event.wait()
        print("¡Cambió!")

threading.Thread(target=test_funct).start()

class_iteration.test_property = 100

El problema es que cuando intento obtener el evento, considera que class_iteration.test_property es un objeto int, por lo que arroja un error. Me pregunto si hay alguna manera de evitar el __get__ cuando se usa __getattribute__, para poder acceder a la variable event, o si necesito cambiar completamente mi enfoque.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Como experto en IT especializado en Python, sugeriría que el problema aquí radica en la implementación de __getattribute__ en la clase DecoratorTest. Tal y como está escrito el código en este momento, __getattribute__ siempre pasará por alto el método __get__ reemplazado cuando se llame en una instancia de la clase DecoratorTest, y en su lugar retornará directamente el atributo solicitado desde el atributo __dict__ del objeto.

    Para solucionar este problema, podrías modificar el método __getattribute__ para llamar explícitamente al método __get__ del descriptor del objeto si existe, antes de recurrir al comportamiento por defecto de retornar el atributo directamente desde el atributo __dict__ del objeto. Aquí tienes una implementación modificada de DecoratorTest que debería lograr el comportamiento deseado:

    class DecoratorTest():
        def __init__(self, fget, fset=None):
            self.fget = fget
            self.fset = fset
            self.event = threading.Event()
    
        def __getattribute__(self, name):
            obj = object.__getattribute__(self, "__obj")
            if obj is not None and hasattr(obj, name):
                attr = getattr(obj, name)
                if hasattr(attr, "__get__"):
                    return attr.__get__(obj, obj.__class__)
            return object.__getattribute__(self, name)
    
        def __get__(self, obj, objtype=None):
            self.__obj = obj
            return self.fget(obj)
    
        def __set__(self, obj, value):
            self.fset(obj, value)
            self.event.set()
            self.event.clear()
    
        def setter(self, fset):
            return type(self)(self.fget, fset)
    

    Con esta implementación actualizada de DecoratorTest, los métodos __get__ y __set__ deberían ser llamados correctamente al acceder a la propiedad decorada, y se debería poder acceder al atributo event como se espera.

Comments are closed.