@@ -1826,6 +1826,85 @@ For example, here is the implementation of
18261826 return True
18271827 return False
18281828
1829+ How do I cache method calls?
1830+ ----------------------------
1831+
1832+ The two principal tools for caching methods are
1833+ :func: `functools.cached_property ` and :func: `functools.lru_cache `. The
1834+ former stores results at the instance level and the latter at the class
1835+ level.
1836+
1837+ The *cached_property * approach only works with methods that do not take
1838+ any arguments. It does not create a reference to the instance. The
1839+ cached method result will be kept only as long as the instance is alive.
1840+
1841+ The advantage is that when an instance is not longer used, the cached
1842+ method result will be released right away. The disadvantage is that if
1843+ instances accumulate, so too will the accumulated method results. They
1844+ can grow without bound.
1845+
1846+ The *lru_cache * approach works with methods that have hashable
1847+ arguments. It creates a reference to the instance unless special
1848+ efforts are made to pass in weak references.
1849+
1850+ The advantage of the least recently used algorithm is that the cache is
1851+ bounded by the specified *maxsize *. The disadvantage is that instances
1852+ are kept alive until they age out of the cache or until the cache is
1853+ cleared.
1854+
1855+ This example shows the various techniques::
1856+
1857+ class Weather:
1858+ "Lookup weather information on a government website"
1859+
1860+ def __init__(self, station_id):
1861+ self._station_id = station_id
1862+ # The _station_id is private and immutable
1863+
1864+ def current_temperature(self):
1865+ "Latest hourly observation"
1866+ # Do not cache this because old results
1867+ # can be out of date.
1868+
1869+ @cached_property
1870+ def location(self):
1871+ "Return the longitude/latitude coordinates of the station"
1872+ # Result only depends on the station_id
1873+
1874+ @lru_cache(maxsize=20)
1875+ def historic_rainfall(self, date, units='mm'):
1876+ "Rainfall on a given date"
1877+ # Depends on the station_id, date, and units.
1878+
1879+ The above example assumes that the *station_id * never changes. If the
1880+ relevant instance attributes are mutable, the *cached_property * approach
1881+ can't be made to work because it cannot detect changes to the
1882+ attributes.
1883+
1884+ The *lru_cache * approach can be made to work, but the class needs to define the
1885+ *__eq__ * and *__hash__ * methods so the cache can detect relevant attribute
1886+ updates::
1887+
1888+ class Weather:
1889+ "Example with a mutable station identifier"
1890+
1891+ def __init__(self, station_id):
1892+ self.station_id = station_id
1893+
1894+ def change_station(self, station_id):
1895+ self.station_id = station_id
1896+
1897+ def __eq__(self, other):
1898+ return self.station_id == other.station_id
1899+
1900+ def __hash__(self):
1901+ return hash(self.station_id)
1902+
1903+ @lru_cache(maxsize=20)
1904+ def historic_rainfall(self, date, units='cm'):
1905+ 'Rainfall on a given date'
1906+ # Depends on the station_id, date, and units.
1907+
18291908
18301909Modules
18311910=======
0 commit comments