[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