Python default values for keyword arguments are evaluated only once and not on every function call. For example following function will not work as user may expect:
def printNow(l=[], now=datetime.now()):
l.append(len(l))
print('List:', l, ' id:', id(l))
print('Now:', now)
for i in range(3):
printNow()
print()
The "dynamic" decorator solves problem by evaluating callables, that are assigned to parameters using annotations syntax (see PEP 3107).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | from datetime import datetime
from functools import wraps
def dynamic(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
for key, value in fn.__annotations__.items():
try:
kwargs[key] = value()
except TypeError:
pass
return fn(*args, **kwargs)
return wrapper
# Example
@dynamic
def printNow(l:list, now:datetime.now):
l.append(len(l))
print('List:', l, ' id:', id(l))
print('Now:', now)
# Test
for i in range(3):
printNow()
print()
|
Tags: annotations, decorator