Skip to content

Commit dad0627

Browse files
committed
examples/value_capture_all.py: Test all value capture cases
Signed-off-by: Tzanko Matev <[email protected]>
1 parent 1964a5b commit dad0627

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed
File renamed without changes.

examples/value_capture_all.py

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
"""Single example exercising many variable-visibility scenarios for value capture.
2+
3+
Covers:
4+
- Simple function locals/params
5+
- Nested functions, nonlocal (closures)
6+
- Globals read/write
7+
- Class body scope and metaclass
8+
- Lambdas and all comprehensions
9+
- Generators and async coroutines
10+
- try/except/else/finally and with
11+
- Decorators and wrappers
12+
- eval/exec dynamic names
13+
- Imports at module and function scope
14+
- Builtins usage
15+
"""
16+
17+
from __future__ import annotations
18+
19+
#import asyncio
20+
import math
21+
22+
# 1. Simple function: params and locals
23+
def simple_function(x: int):
24+
a = 1
25+
b = a + x
26+
return a, b
27+
28+
# Globals
29+
GLOBAL_VAL = 10
30+
counter = 0
31+
setting = "Hello"
32+
CONSTANT = 42
33+
34+
35+
# 8. Decorator and wrapper (captures free var `setting`)
36+
def my_decorator(func):
37+
def wrapper(*args, **kwargs):
38+
# variables visible here: args, kwargs, setting, func (closed over)
39+
return func(*args, **kwargs)
40+
return wrapper
41+
42+
43+
@my_decorator
44+
def greet(name: str) -> str:
45+
message = f"Hi, {name}"
46+
return message
47+
48+
49+
50+
51+
# 2. Nested functions and nonlocal
52+
def outer_func(x: int):
53+
y = 1
54+
55+
def inner_func(z: int):
56+
nonlocal y
57+
w = x + y + z
58+
y = w
59+
return w
60+
61+
total = inner_func(5)
62+
return y, total
63+
64+
65+
# 3. Globals
66+
def global_test():
67+
local_copy = GLOBAL_VAL
68+
global counter
69+
counter += 1
70+
return local_copy, counter
71+
72+
73+
# 4. Class scope and metaclass
74+
class MetaCounter(type):
75+
count = 0
76+
77+
def __init__(cls, name, bases, attrs):
78+
MetaCounter.count += 1
79+
super().__init__(name, bases, attrs)
80+
81+
82+
class Sample(metaclass=MetaCounter):
83+
a = 10
84+
b = a + 5
85+
c = a + b + CONSTANT
86+
87+
def method(self):
88+
return self.a + self.b
89+
90+
91+
# 6. Generators and async coroutines
92+
def counter_gen(n: int):
93+
total = 0
94+
for i in range(n):
95+
total += i
96+
yield total
97+
return total
98+
99+
100+
# async def async_sum(data: list[int]) -> int:
101+
# total = 0
102+
# for x in data:
103+
# total += x
104+
# await asyncio.sleep(0)
105+
# return total
106+
107+
108+
# async def agen(n: int):
109+
# for i in range(n):
110+
# yield i + 1
111+
112+
113+
# 7. try/except/finally and with
114+
def exception_and_with_demo(x: int):
115+
try:
116+
inv = 10 / x
117+
except ZeroDivisionError as e:
118+
error_msg = f"Error: {e}"
119+
else:
120+
inv += 1
121+
finally:
122+
final_flag = True
123+
124+
with open(__file__, "r") as f:
125+
first_line = f.readline()
126+
return locals()
127+
128+
129+
# 9. eval/exec
130+
def eval_test():
131+
value = 10
132+
formula = "value * 2"
133+
result = eval(formula)
134+
return result
135+
136+
137+
# 10. Imports and visibility
138+
def import_test():
139+
import os
140+
constant = math.pi
141+
cwd = os.getcwd()
142+
return constant, cwd
143+
144+
145+
# 11. Builtins
146+
def builtins_test(seq):
147+
n = len(seq)
148+
m = max(seq)
149+
return n, m
150+
151+
152+
def main() -> None:
153+
1
154+
res1 = simple_function(5)
155+
156+
# 2
157+
res2 = outer_func(2)
158+
159+
# 3
160+
before = counter
161+
_local_copy, _ctr = global_test()
162+
after = counter
163+
164+
# 5. Lambdas and comprehensions
165+
factor = 2
166+
double = lambda y: y * factor # noqa: E731
167+
squares = [n ** 2 for n in range(3)]
168+
scaled_set = {n * factor for n in range(3)}
169+
mapping = {n: n * factor for n in range(3)}
170+
gen_exp = (n * factor for n in range(3))
171+
result_list = list(gen_exp)
172+
173+
# 6. Generators and async coroutines
174+
gen = counter_gen(3)
175+
gen_results = list(gen)
176+
# coroutine_result = asyncio.run(async_sum([1, 2, 3]))
177+
178+
# async def consume() -> int:
179+
# acc = 0
180+
# async for x in agen(3):
181+
# acc += x
182+
# return acc
183+
184+
# async_acc = asyncio.run(consume())
185+
186+
# 7. try/except/finally and with
187+
r1 = exception_and_with_demo(0)
188+
r2 = exception_and_with_demo(5)
189+
has_e = "error_msg" in r1
190+
has_inv = "inv" in r2
191+
has_final_flag = r1.get("final_flag", False) and r2.get("final_flag", False)
192+
193+
# 8. Decorator and wrapper
194+
output = greet("World")
195+
196+
# 9. eval/exec
197+
expr_code = "dynamic_var = 99"
198+
exec(expr_code, globals())
199+
dynamic_var = globals()["dynamic_var"]
200+
check = dynamic_var + 1
201+
out = eval_test()
202+
203+
# 10. import visibility
204+
constant, cwd = import_test()
205+
206+
# 11. builtins
207+
built_n, built_m = builtins_test([5, 3, 7])
208+
209+
#Aggregate a compact, deterministic summary
210+
print(
211+
"ok",
212+
res1[0] + res1[1], # simple_function sum
213+
sum(res2), # outer_func sum
214+
after - before, # global counter increment
215+
MetaCounter.count, # metaclass incremented classes
216+
sum(squares), len(scaled_set), len(mapping), sum(result_list),
217+
sum(gen_results), # generator totals
218+
#coroutine_result, async_acc, # async results
219+
has_e, has_inv, has_final_flag, # exception/with signals
220+
len(output), # decorator + greet result length
221+
dynamic_var, check, out, # eval/exec values
222+
f"{constant:.3f}", # math.pi to 3 decimals
223+
bool(len(cwd)), # cwd non-empty is True
224+
built_n, built_m, # builtins result
225+
double(7), # lambda capture
226+
Sample.c, # class body computed constant
227+
)
228+
229+
230+
if __name__ == "__main__":
231+
main()

0 commit comments

Comments
 (0)