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_property
y se _lazy_property
vuelve 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)