Background: I came across PEP 736 (which I haven’t finished reading it yet) and I was messing around trying to “reproduce” the effect.
I have defined a function lazyArg() as follows:
def lazyArg(func):
# Assuming Ellipsis will never be an argument of `func`
def new_func(*args, **kwargs):
for k, v in kwargs.items():
if isinstance(v, type(Ellipsis)):
kwargs[k] = globals()[k]
func(*args, **kwargs)
return new_func
such that I can do things like this:
@lazyArg
def say(name, msg, target=None):
if target is None:
print(f"{name} says: {msg}")
else:
print(f"{name} says to {target}: {msg}")
name = 'Foo'
msg = 'Hello World!'
target = 'Bar'
say(
name=...,
msg=...,
target=...,
) # Foo says to Bar: Hello World!
Of course, as I used globals() in lazyArg(), this won’t work:
To let f() replace the Ellipsis argument with 1, f() would need to access all variables under main(). globals() can’t do that, neither can locals(), so I am looking for some way to do that, something like a nonlocals()
Oh, wow, that’s right, this does exactly what OP wants.
def lazyArg(func):
import sys
# Assuming Ellipsis will never be an argument of `func`
def new_func(*args, **kwargs):
for k, v in kwargs.items():
if isinstance(v, type(Ellipsis)):
kwargs[k] = sys._getframe(1).f_locals[k] # <<--
func(*args, **kwargs)
return new_func
Just be aware, sys._getframe has an underscore for a reason. It is internal details, and can change at any time; it’s only in CPython, not part of other Python implementations (or if it is, it can be completely different); and anything you do that depends on it could break at any time.
But, with all those caveats said: Go have fun with it!