[Python-ideas] Specifying constants for functions

Ryan Gonzalez rymg19 at gmail.com
Tue Oct 27 16:15:24 EDT 2015


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 at 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 at 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/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20151027/4a089f05/attachment.html>


More information about the Python-ideas mailing list