Skip to content

Commit f4c90a7

Browse files
committed
Updated docs.
1 parent 4d184fe commit f4c90a7

5 files changed

Lines changed: 324 additions & 0 deletions

File tree

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
---
2+
file: creational/lazy_evaluation.py
3+
chunk: creational_lazy_evaluation.md
4+
---
5+
6+
```python
7+
"""
8+
lazy_evaluation.py
9+
10+
Demonstrates the Lazy Evaluation pattern in Python using a custom @lazy_property decorator.
11+
This pattern is useful when you want to delay the evaluation of a resource-intensive
12+
property until it is actually accessed.
13+
14+
"""
15+
16+
import time
17+
from functools import wraps
18+
19+
def lazy_property(func):
20+
"""
21+
A decorator that converts a method into a lazily evaluated property.
22+
The result is cached after the first computation.
23+
24+
Usage:
25+
@lazy_property
26+
def expensive_computation(self): ...
27+
"""
28+
attr_name = f"_lazy_{func.__name__}"
29+
30+
@property
31+
@wraps(func)
32+
def wrapper(self):
33+
if not hasattr(self, attr_name):
34+
print(f"🔄 Computing '{func.__name__}'...")
35+
setattr(self, attr_name, func(self))
36+
return getattr(self, attr_name)
37+
38+
return wrapper
39+
40+
41+
# ============================
42+
# Lazy Evaluation Example Class
43+
# ============================
44+
45+
class ReportGenerator:
46+
"""
47+
Simulates a class that generates an expensive report.
48+
Lazy evaluation is used so the report is not computed until needed.
49+
"""
50+
51+
def __init__(self, data: list):
52+
self.data = data
53+
54+
@lazy_property
55+
def summary(self):
56+
"""
57+
Simulates a time-consuming operation.
58+
"""
59+
time.sleep(2) # Simulate heavy computation
60+
return {
61+
"total": len(self.data),
62+
"min": min(self.data),
63+
"max": max(self.data),
64+
"average": sum(self.data) / len(self.data)
65+
}
66+
67+
def show_summary(self):
68+
"""Displays the report summary."""
69+
print("📊 Report Summary:")
70+
for key, value in self.summary.items():
71+
print(f" - {key.capitalize()}: {value}")
72+
73+
74+
# ============================
75+
# Demonstration
76+
# ============================
77+
78+
def main():
79+
print("🐢 Lazy Evaluation Pattern Demo 🐢\n")
80+
81+
numbers = list(range(1, 1_000_001)) # Large dataset
82+
report = ReportGenerator(numbers)
83+
84+
print("Step 1: Object created, report not yet generated.")
85+
time.sleep(1)
86+
87+
print("\nStep 2: Accessing the summary for the first time (will compute)...")
88+
report.show_summary()
89+
90+
print("\nStep 3: Accessing the summary again (should be cached)...")
91+
report.show_summary()
92+
93+
94+
if __name__ == "__main__":
95+
main()
96+
97+
98+
# 🐢 Lazy Evaluation Pattern Sample Output 🐢
99+
100+
# Step 1: Object created, report not yet generated.
101+
102+
# Step 2: Accessing the summary for the first time (will compute)...
103+
# 🔄 Computing 'summary'...
104+
# 📊 Report Summary:
105+
# - Total: 1000000
106+
# - Min: 1
107+
# - Max: 1000000
108+
# - Average: 500000.5
109+
110+
# Step 3: Accessing the summary again (should be cached)...
111+
# 📊 Report Summary:
112+
# - Total: 1000000
113+
# - Min: 1
114+
# - Max: 1000000
115+
# - Average: 500000.5
116+
117+
```
118+
119+
## Summary
120+
Demonstrates the Lazy Evaluation pattern in Python using a custom @lazy_property decorator. This pattern delays the evaluation of a resource-intensive property until it is accessed, thus optimizing performance.
121+
122+
## Docstrings
123+
- A decorator that converts a method into a lazily evaluated property. The result is cached after the first computation.
124+
- Simulates a time-consuming operation. Delays the computation of the report summary until it is accessed.
125+
- Displays the report summary.
126+

docs/creational_lazy_evaluation.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# The Lazy Evaluation Pattern (Creational)
2+
3+
## Purpose
4+
5+
The Lazy Evaluation pattern delays computing a value until it's actually needed. This is useful when the computation is resource-heavy or time-consuming, like generating a detailed report or performing complex calculations.
6+
7+
## The Problem It Solves
8+
9+
Often, programs compute values upfront—even when those values may never be used. This wastes resources. Lazy Evaluation fixes that by waiting to compute a value until it’s actually requested, which can make programs faster and more efficient.
10+
11+
## When to Use It
12+
13+
Use this pattern when:
14+
15+
* A computation might not always be needed.
16+
* The calculation takes a lot of time or memory.
17+
* You want to improve the performance of your program by avoiding unnecessary work.
18+
19+
An example might be generating a report only when a user opens it—not when the report object is first created.
20+
21+
## When NOT to Use It
22+
23+
Avoid this pattern if:
24+
25+
1. The value is always needed right away.
26+
2. The calculation is simple and quick, and delaying it adds unnecessary complexity.
27+
3. Your application requires thread safety—this basic version of Lazy Evaluation isn’t thread-safe.
28+
29+
## How It Works
30+
31+
The key part is a `@lazy_property` decorator. This turns a method into a property that’s calculated only the first time it’s accessed. After that, the result is stored and reused.
32+
33+
## Real-World Analogy
34+
35+
Imagine reading a book where each chapter appears only when you open it. Instead of loading the whole book at once, each part is created on demand—saving time and effort if you don’t read every chapter.
36+
37+
## Simplified Example
38+
39+
Here’s a basic example with a class that creates a report from a dataset:
40+
41+
```python
42+
import time
43+
44+
def lazy_property(func):
45+
attr = f"_lazy_{func.__name__}"
46+
47+
@property
48+
def wrapper(self):
49+
if not hasattr(self, attr):
50+
print(f"Computing '{func.__name__}'...")
51+
setattr(self, attr, func(self))
52+
return getattr(self, attr)
53+
54+
return wrapper
55+
56+
class ReportGenerator:
57+
def __init__(self, data):
58+
self.data = data
59+
60+
@lazy_property
61+
def summary(self):
62+
time.sleep(2) # Simulates a slow computation
63+
return {
64+
"total": len(self.data),
65+
"min": min(self.data),
66+
"max": max(self.data),
67+
"average": sum(self.data) / len(self.data)
68+
}
69+
70+
# Demonstration
71+
report = ReportGenerator([1, 2, 3, 4, 5])
72+
print("First access:")
73+
print(report.summary) # Triggers computation
74+
print("\nSecond access:")
75+
print(report.summary) # Uses cached result
76+
```
77+
78+
The first time `report.summary` is accessed, it runs the computation and prints the result. The second time, it just returns the stored value—no waiting.
79+
80+
## Learn More
81+
82+
For the full example, see the [lazy_evaluation.py](https://github.com/taggedzi/python-design-pattern-rag/blob/main/patterns/creational/lazy_evaluation.py) file in the repository.

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- [Creational Borg](creational_borg.md)
1515
- [Creational Builder](creational_builder.md)
1616
- [Creational Factory](creational_factory.md)
17+
- [Creational Lazy Evaluation](creational_lazy_evaluation.md)
1718
- [Creational Prototype](creational_prototype.md)
1819
- [Creational Singleton](creational_singleton.md)
1920
- [Structural Adapter](structural_adapter.md)
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""
2+
lazy_evaluation.py
3+
4+
Demonstrates the Lazy Evaluation pattern in Python using a custom @lazy_property decorator.
5+
This pattern is useful when you want to delay the evaluation of a resource-intensive
6+
property until it is actually accessed.
7+
8+
"""
9+
10+
import time
11+
from functools import wraps
12+
13+
def lazy_property(func):
14+
"""
15+
A decorator that converts a method into a lazily evaluated property.
16+
The result is cached after the first computation.
17+
18+
Usage:
19+
@lazy_property
20+
def expensive_computation(self): ...
21+
"""
22+
attr_name = f"_lazy_{func.__name__}"
23+
24+
@property
25+
@wraps(func)
26+
def wrapper(self):
27+
if not hasattr(self, attr_name):
28+
print(f"🔄 Computing '{func.__name__}'...")
29+
setattr(self, attr_name, func(self))
30+
return getattr(self, attr_name)
31+
32+
return wrapper
33+
34+
35+
# ============================
36+
# Lazy Evaluation Example Class
37+
# ============================
38+
39+
class ReportGenerator:
40+
"""
41+
Simulates a class that generates an expensive report.
42+
Lazy evaluation is used so the report is not computed until needed.
43+
"""
44+
45+
def __init__(self, data: list):
46+
self.data = data
47+
48+
@lazy_property
49+
def summary(self):
50+
"""
51+
Simulates a time-consuming operation.
52+
"""
53+
time.sleep(2) # Simulate heavy computation
54+
return {
55+
"total": len(self.data),
56+
"min": min(self.data),
57+
"max": max(self.data),
58+
"average": sum(self.data) / len(self.data)
59+
}
60+
61+
def show_summary(self):
62+
"""Displays the report summary."""
63+
print("📊 Report Summary:")
64+
for key, value in self.summary.items():
65+
print(f" - {key.capitalize()}: {value}")
66+
67+
68+
# ============================
69+
# Demonstration
70+
# ============================
71+
72+
def main():
73+
print("🐢 Lazy Evaluation Pattern Demo 🐢\n")
74+
75+
numbers = list(range(1, 1_000_001)) # Large dataset
76+
report = ReportGenerator(numbers)
77+
78+
print("Step 1: Object created, report not yet generated.")
79+
time.sleep(1)
80+
81+
print("\nStep 2: Accessing the summary for the first time (will compute)...")
82+
report.show_summary()
83+
84+
print("\nStep 3: Accessing the summary again (should be cached)...")
85+
report.show_summary()
86+
87+
88+
if __name__ == "__main__":
89+
main()
90+
91+
92+
# 🐢 Lazy Evaluation Pattern Sample Output 🐢
93+
94+
# Step 1: Object created, report not yet generated.
95+
96+
# Step 2: Accessing the summary for the first time (will compute)...
97+
# 🔄 Computing 'summary'...
98+
# 📊 Report Summary:
99+
# - Total: 1000000
100+
# - Min: 1
101+
# - Max: 1000000
102+
# - Average: 500000.5
103+
104+
# Step 3: Accessing the summary again (should be cached)...
105+
# 📊 Report Summary:
106+
# - Total: 1000000
107+
# - Min: 1
108+
# - Max: 1000000
109+
# - Average: 500000.5

summary_index.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@
8383
"pattern": "Factory",
8484
"summary": "Implementation of the Factory Method design pattern in Python."
8585
},
86+
{
87+
"file": "creational/lazy_evaluation.py",
88+
"chunk": "creational_lazy_evaluation.md",
89+
"pattern": "Lazy Evaluation",
90+
"summary": "Demonstrates the Lazy Evaluation pattern in Python using a custom @lazy_property decorator. This pattern delays the evaluation of a resource-intensive property until it is accessed, thus optimizing performance."
91+
},
8692
{
8793
"file": "creational/prototype.py",
8894
"chunk": "creational_prototype.md",

0 commit comments

Comments
 (0)