
Steven D'Aprano dixit (2011-06-15, 21:35):
This is another reason why function parameters should not be used for something that is not a function parameter!
+1 on the ability to inject locals into a function namespace.
-1 on having the syntax for that masquerade as function arguments.
OK, so the decorator or decorator-like syntax (using 'inject', 'within', 'owns' or other decorator name...) seems to be the most promising alternative. If so, next question is: which variant? 1. Decorator function with closure-like injecting (possibly could be implemented using closures): @functools.owns(cache=dict(), MAX_CACHE_LEN=100) def calculate(a, b): result = cache[(a, b)] if result is not None: return result ... # 'cache' identifier cannot be rebound to another object # because it was already used above in the function body # to refer to the injected object functools.owns() would be a real decorator function -- to apply either with @-syntax or dynamically, e.g.: decorated = [functools.owns(func) for func in functions] One question is whether it is technically possible to avoid introducing a new keyword (e.g. staticlocal) explicitly marking injected locals. Using such a keyword would be redundant from user point of view and non-DRY: @functools.owns(cache=dict(), MAX_CACHE_LEN=100) def calculate(a, b): staticlocal cache, MAX_CACHE_LEN # <- redundant and non-DRY :-( result = cache[(a, b)] if result is not None: return result ... 2. Decorator function with argument-like injecting. @functools.owns(cache=dict(), MAX_CACHE_LEN=100) def calculate(a, b): result = cache[(a, b)] if result is not None: return result ... # 'cache' identifier *can* be rebound to another object # than the injected object -- in the same way arguments can functools.owns() would be a real decorator function -- to apply either with @-syntax or dynamically, e.g.: decorated = [functools.owns(func) for func in functions] To implement such variant -- a new function constructor argument(s) and/or function/function code attribute(s) (read-only or writable?) most probably would have to be introduced... 3. Decorator-like language syntax construct: @in(cache=dict(), MAX_CACHE_LEN=100) # or 'owns' or 'inject' or... def calculate(a, b): result = cache[(a, b)] if result is not None: return result ... # 'cache' identifier *can* be rebound to another object # than the injected object -- in the same way arguments can It would not be a real decorator function -- so it would be applicable only using this syntax, and not dynamically, not after function creation. Which do you prefer? (or any other?) Regards. *j