[Python-ideas] A "local" pseudo-function

Steven D'Aprano steve at pearwood.info
Tue May 1 11:23:16 EDT 2018


On Mon, Apr 30, 2018 at 08:52:13PM -0500, Tim Peters wrote:

> > Would/should it be possible to inject a name into a local scope? You can't
> > inject into a function scope, and names in a function scope can be
> > determined statically (they are allocated slots), so could the same kind of
> > thing be done for names in a local scope?
> 
> Sorry, I'm unclear on what "inject a name into a local scope" means.
> Do you mean at runtime?

I don't know what MRAB means by "inject", but I know what *I* mean, and 
I have a real use-case for it.

There is a long-running micro-optimization, often championed by Raymond, 
for avoiding slow global lookups (and even slower builtin lookups, since 
they require a global lookup to fail first) by turning them in local 
lookups at function-definition time. E.g. some methods from the 
random.Random class:

        def randrange(self, start, stop=None, step=1, _int=int):
            ...
        def _randbelow(self, n, int=int, maxsize=1<<BPF, type=type,
                       Method=_MethodType, BuiltinMethod=_BuiltinMethodType):
            ...

(copied from 3.5, I don't know what the most recent version looks like)


That's a nice way to make the binding:

    _int = int

occur once only, instead of putting it inside the function body which 
then needs to be executed on ever call. Effectively it's a static 
variable for the method, one which persists from one call to the next 
without requiring re-initialisation.

But it's ugly :-(

The function signature is full of *implementation details* instead of 
the parameters needed for the method's interface. Look at _randbelow 
which takes one actual parameter, n, plus FIVE fake parameters, int, 
maxsize, type, Method and BuiltinMethod, none of which should ever be 
passed arguments.

So when I talk about injecting values into a function, that is the sort 
of thing I'm referring to: at function definition time, push or inject a 
reference to a known value (say, the builtin int) into something which 
behaves as a static variable.

It would be nice if we could do that without polluting the function 
signature. I'll admit that the name "inject" came to me when I was 
thinking of some hypothetical decorator:

    @inject(int=int, maxsize=1<<BPF, type=type, ...)
    def _randbelow(self, n):
        ...


that somehow pushed, or *injected*, those bindings into the function, 
turning them into locals, but in an alternative universe where Guido 
loved making new keywords, I'd use a static initialisation block and 
stick it inside the def:

    def _randbelow(self, n):
        static:
            # this gets executed once only, at function definition time
            int=int
            maxsize=1<<BPF
            type=type
        # body of _randbelow        
        ...



-- 
Steve


More information about the Python-ideas mailing list