Lazy loading
Lazy loading is an programming implementation paradigm which delays the evaluation of an expression until its value is needed and which also avoids repeated evaluations.
Lazy evaluation is the preferred implementation when the operation is expensive, requiring either extensive processing time or memory. For example, in Python, one of the best-known techniques involving lazy evaluation is generators. Instead of creating whole sequences for the iteration, which can consume lots of memory, generators lazily evaluate the current need and yield one element at a time when requested.
Other example are attributes that take long to compute:
class Person:
def __init__(self, name, occupation):
self.name = name
self.occupation = occupation
self.relatives = self._get_all_relatives()
def _get_all_relatives():
...
# This is an expensive operation
This approach may cause initialization to take unnecessarily long, especially when you don't always need to access Person.relatives
.
A better strategy would be to get relatives when it's needed.
class Person:
def __init__(self, name, occupation):
self.name = name
self.occupation = occupation
self._relatives = None
@property
def relatives(self):
if self._relatives is None:
self._relatives = ... # Get all relatives
return self._relatives
In this case, the list of relatives is computed the first time Person.relatives
is accessed. After that, it's stored in Person._relatives
to prevent repeated evaluations.
A perhaps more Pythonic approach would be to use a decorator that makes a property lazy-evaluated.
def lazy_property(fn):
'''Decorator that makes a property lazy-evaluated.
'''
attr_name = '_lazy_' + fn.__name__
@property
def _lazy_property(self):
if not hasattr(self, attr_name):
setattr(self, attr_name, fn(self))
return getattr(self, attr_name)
return _lazy_property
class Person:
def __init__(self, name, occupation):
self.name = name
self.occupation = occupation
@lazy_property
def relatives(self):
# Get all relatives
relatives = ...
return relatives
This removes a lot of boilerplate, especially when an object has many lazily-evaluated properties.
Another approach is to use the getattr special method.