Tutorial básico de Python: atributos diferidos (inicialización diferida)

La inicialización diferida de un objeto Python significa que se inicializa cuando se crea por primera vez, o que se guarda el resultado de la primera creación, y luego el resultado se devuelve directamente cada vez que se llama. La inicialización retrasada se utiliza principalmente para mejorar el rendimiento, evitar el desperdicio de cálculos y reducir los requisitos de memoria del programa.

1. Revisar la propiedad

la propiedad puede convertir el acceso a los atributos en una llamada a un método

class Circle(object): 
  def __init__(self, radius): 
    self.radius = radius 
  
  @property
  def area(self): 
    return 3.14 * self.radius ** 2
  
c = Circle(4) 
print c.radius 
print c.area

Como puede ver, aunque area se define como un método, después de agregar @property, c.area se puede ejecutar directamente como un acceso de propiedad.

Ahora viene el problema, cada vez que se llama c.area, se calculará una vez, lo cual es un desperdicio de CPU ¿Cómo puedo calcularlo solo una vez?

Implementación de propiedad perezosa

Hay dos formas de implementar la inicialización diferida, una es usar descriptores de Python y la otra es usar el modificador @property

Método 1:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class lazy(object): 
  def __init__(self, func): 
    self.func = func 
  
  def __get__(self, instance, cls): 
    val = self.func(instance) 
    setattr(instance, self.func.__name__, val) 
    return val 
  
class Circle(object): 
  def __init__(self, radius): 
    self.radius = radius 
  
  @ lazy
  def area(self): 
    print 'evalute'
    return 3.14 * self.radius ** 2
  
c = Circle(4) 
print c.radius 
print c.area 
print c.area 
print c.area

Como resultado, 'evalute' se generó solo una vez. En la clase perezosa, definimos el __get__()método, por lo que es un descriptor. Cuando ejecutamos c.area por primera vez, el intérprete de Python comenzará c.__dict__en progreso para buscar, no encontrar, la Circle.__dict__búsqueda en este caso porque el área está definida como un descriptor, así que llame al __get__método.

En el __get__()método, llame al método area () de la instancia para calcular el resultado y agregue dinámicamente un área de atributo con el mismo nombre a la instancia, y luego asígnele el valor calculado, que es equivalente a la configuración c.__dict__['area']=val.

Cuando volvemos a llamar a c.area, directamente desde la c.__dict__búsqueda en, el valor calculado antes de que regrese directamente.

Método 2:

def lazy_property(func):
    attr_name = "_lazy_" + func.__name__
 
    @property
    def _lazy_property(self):
        if not hasattr(self, attr_name):
            setattr(self, attr_name, func(self))
        return getattr(self, attr_name)
 
    return _lazy_property
 
class Circle(object): 
  def __init__(self, radius): 
    self.radius = radius 
  
  @lazy_property
  def area(self): 
    print 'evalute'
    return 3.14 * self.radius ** 2

Esto es lo mismo que el método 1, agregar @lazy_property antes de area () equivale a ejecutar el siguiente código:

lazy_property(area)

lazy_property()El método regresa _lazy_propertyy se _lazy_propertyvuelve a llamar al _lazy_property()método, y las operaciones restantes son similares al método 1.

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
#性能差方法
class Circle(object): 
    def __init__(self, radius): 
        self.radius = radius 

    @property
    def area(self): 
        print("come in")
        return 3.14 * self.radius ** 2
  
c = Circle(4) 
print(c.radius) 
print(c.area) 
print(c.area) 

#方法1
class LazyProperty:
    def __init__(self, method):
        self.method = method
        
    def __get__(self, instance, cls):
        if not instance:
            return None
        value = self.method(instance)
        setattr(instance,self.method.__name__,value)
        return value
        
class Circle(object): 
    def __init__(self, radius): 
        self.radius = radius 

    @LazyProperty
    def area(self): 
        print("come in")
        return 3.14 * self.radius ** 2
        
c = Circle(4) 
print(c.radius) 
print(c.area) 
print(c.area)

#方法2
def LazyProperty(func):
    attr_name = "_lazy_" + func.__name__
 
    @property
    def wrap(self):
        if not hasattr(self, attr_name):
            setattr(self, attr_name, func(self))
        return getattr(self, attr_name)
    return wrap
    
class Circle(object): 
    def __init__(self, radius): 
        self.radius = radius 

    @LazyProperty
    def area(self): 
        print("come in")
        return 3.14 * self.radius ** 2
        
c = Circle(4) 
print(c.radius) 
print(c.area) 
print(c.area)

Supongo que te gusta

Origin blog.csdn.net/qdPython/article/details/112611339
Recomendado
Clasificación