[Python-ideas] 'Injecting' objects as function-local constants
Steven D'Aprano
steve at pearwood.info
Thu Jun 16 02:46:51 CEST 2011
Jan Kaliszewski wrote:
> 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?
"owns"? I don't see how that testing for ownership describes what the
function does.
Likewise for "within", which sounds like it should be a synonym for the
"in" operator: "if value within range" sort of thing.
> 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
Making locals unrebindable is a change of semantics that is far beyond
anything I've been discussed here. This will be a big enough change
without overloading it with changes that will be even more controversial!
(I actually do like the idea of having unrebindable names, but that
should be kept as a separate issue and not grafted on to this proposal.)
> 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]
There shouldn't even be a question about that. Decorator syntax is sugar
for func = decorator(func). Introducing magic syntax that is recognised
by the compiler but otherwise is not usable as a function is completely
unacceptable.
If func is a pre-existing function:
def func(a, b, c):
pass
then:
new_func = functools.inject(x=1, y=2)(func)
should be the same as:
def new_func(a, b, c):
# inject locals into the body of the function
x = 1
y = 2
# followed by the body of the original
pass
except that new_func.__name__ may still reflect the old name "func".
* If the original function previously referenced global or nonlocal x
and y, the new function must now treat them as local;
* Bindings to x and y should occur once, at function definition time,
similar to the way default arguments occur once;
* The original function (before the decorator applies) must be untouched
rather than modified in place.
This implies to me that inject must copy the original function and make
modifications to the code object. This sounds to me that a
proof-of-concept implementation would be doable using a byte-code hack.
--
Steven
More information about the Python-ideas
mailing list