Skip to content

Instantly share code, notes, and snippets.

@shreve
Created June 6, 2023 21:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shreve/fdc1a3f90dee8b2c130748fc98b26f32 to your computer and use it in GitHub Desktop.
Save shreve/fdc1a3f90dee8b2c130748fc98b26f32 to your computer and use it in GitHub Desktop.
Lazy evaluation wrapper for python
from typing import Callable, Generic, TypeVar, Any
Type = TypeVar("Type")
class Lazy(Generic[Type]):
"""
Define a lazily-evaluated value. The function will only be called once, and the
container will invisibly act like the value.
"""
def __init__(self, func: Callable[[], Type]):
self.__func__ = func
def __repr__(self):
return self.__value__.__repr__()
def __getattribute__(self, name: str) -> Any:
try:
# First, try to get the attribute from the container itself.
return super(Lazy, self).__getattribute__(name)
except AttributeError:
# If that fails, try to get it from the value.
if "__value__" not in self.__dict__:
self.__value__ = self.__func__()
del self.__func__
# In the case where lazy.value is the attribute which triggers eval, we
# need to return the value itself rather than get the attribute from it.
if name == "__value__":
return self.__value__
# Otherwise, send every other request to the value.
return self.__value__.__getattribute__(name)
from .lazy import Lazy
def approximate_pi(n: int) -> float:
"""Approximate pi using the Gregory-Leibniz series."""
return 4 * sum(
(-1) ** k / (2 * k + 1) for k in range(n)
)
# Completes instantly
pi = Lazy(lambda: approximate_pi(10_000_000))
# First access takes several seconds
pi
# Second access is instant
pi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment