
Making a decorator is easy: def opt(**kw): def func(f): globals().update(dis.opmap) # Someone's going to kill me for this... code = list(f.__code__.co_code) offs = 0 varnames = list(f.__code__.co_varnames) nlocals = f.__code__.co_nlocals names = list(f.__code__.co_names) globls = f.__globals__ mapping = {} anon_count = 0 for k, v in kw.items(): if k in names: try: i = names.index(k) except ValueError: raise ValueError('variable %r must be a global' % k) from None anon_var = '$__varopt__%d$' % anon_count anon_count += 1 names[i] = anon_var globls[anon_var] = v assert k not in varnames, '%r is both global and local' % k varnames.append(k) nlocals += 1 mapping[i] = nlocals-1 code[:0] = [ LOAD_GLOBAL, i, 0, STORE_FAST, nlocals-1, 0, ] offs += 6 else: raise ValueError('variable %r is not a global' % k) i = offs while i < len(code): if code[i] in dis.hasjabs: code[i+1] += offs elif code[i] in (LOAD_GLOBAL, STORE_GLOBAL) and code[i+1] in mapping: code[i] = LOAD_FAST if code[i] == LOAD_GLOBAL else STORE_FAST code[i+1] = mapping[code[i+1]] i += 3 if code[i] > dis.HAVE_ARGUMENT else 1 rescode = types.CodeType(f.__code__.co_argcount, f.__code__.co_kwonlyargcount, nlocals, f.__code__.co_stacksize, f.__code__.co_flags, bytes(code), f.__code__.co_consts, tuple(names), tuple(varnames), f.__code__.co_filename, f.__code__.co_name, f.__code__.co_firstlineno, f.__code__.co_lnotab, f.__code__.co_freevars, f.__code__.co_cellvars) return types.FunctionType(rescode, globls, f.__name__, f.__defaults__, f.__closure__) return func On Tue, Oct 27, 2015 at 12:45 PM, Serhiy Storchaka <storchaka@gmail.com> wrote:
There is known trick to optimize a function:
def foo(x, y=0, len=len, pack=struct.pack, maxsize=1<<BPF): ...
It has a side effect: change function's signature. Would be nice to have a way to set function's local variables at creation time without affecting a signature.
Possible syntax (I'm not sure what is better):
1. Similar to "global" and "nonlocal" declarations with optional initializer.
def foo(x, y=0): const len const pack=struct.pack, maxsize=1<<BPF ...
2. Same as 1, but using "as" instead of "=".
def foo(x, y=0): uses len, struct.pack as pack uses 1<<BPF as maxsize ...
3. Declaration is moved to function header. The keyword "given" is inspired by PEP 3150.
def foo(x, y=0) given len=len, pack=struct.pack, maxsize=1<<BPF: ...
4. Declaration is moved out of the function. The advantage is that bound names can be used to evaluate default values for actual parameters (it is useful to implement sentinel default value), and all expression are evaluated in natural order.
using len, struct.pack as pack, 1<<BPF as maxsize: def foo(x, y=0): ...
5. The least wordy syntax. No new keyword needed.
def foo(x, y=0; len=len, pack=struct.pack, maxsize=1<<BPF): ...
All above examples would be roughly equivalent to the following code:
def create(len=len, pack=struct.pack, maxsize=1<<BPF): def foo(x, y=0): ... return foo tmp = create() def foo(x, y=0): pass update_wrapper(tmp, foo) foo = tmp del create, tmp
This feature is rather ideologically opposite to Victor's approach.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Ryan [ERROR]: Your autotools build scripts are 200 lines longer than your program. Something’s wrong. http://kirbyfan64.github.io/