[Python-ideas] proto-PEP: Fixing Non-constant Default Arguments
George Sakkis
gsakkis at rutgers.edu
Tue Jan 30 05:16:50 CET 2007
> Chris Rebert wrote:
>
> >The following is a proto-PEP based on the discussion in the thread
> >"fixing mutable default argument values". Comments would be greatly
> >appreciated.
As I see it, the main objection to this is the inversal of the current
default semantics: every default argument is treated as if it were
mutable, or re-evaluatable more generally. Although mutable default
arguments are useful some times and would be nice to have, they are
most likely less common than the immutable ones, so the latter should
be the default. I'm sure that the python-devs and the BDFL would have
thought about it quite a bit when the current semantics were decided,
and it's unlikely they'll change their mind now without very good
reasons.
OTOH, a proposal that leaves the current semantics as is and adds a
mechanism to specify default arguments to be evaluated at call-time
rather than definition-time would have more chances. Here's a
proof-of-concept solution that specifies explicitly the re-evaluatable
default expressions as "deferred":
import inspect
class Deferred(object):
def __init__(self, expr):
self.expr = expr
def eval_deferreds(func):
varnames,_,_,defaults = inspect.getargspec(func)
num_varnames = len(varnames); num_defaults = len(defaults)
def wrapper(*args, **kwds):
if len(args) >= num_varnames: # defaults not used here
return func(*args,**kwds)
f_locals = dict(zip(varnames,args))
used_defaults = min(num_defaults, num_varnames-len(args))
for var,default in zip(varnames[-used_defaults:],
defaults[-used_defaults:]):
if var in kwds: # passed as keyword argument; don't use the default
value = kwds[var]
elif not isinstance(default, Deferred): # non re-evaluatable default
value = default
else: # evaluatable default in f_locals
value = eval(default.expr, func.func_globals, f_locals)
f_locals[var] = value
f_locals.update(kwds) # add any extra keyword arguments
return func(**f_locals)
return wrapper
#======= example ==============================
W = 1 # some global
@eval_deferreds
def f(x, y=Deferred('x**2+W'), z=Deferred('[]')):
z.append(x)
z.append(y)
return z
from collections import deque
print f(3) # [3,10]
W=3; print f(4) # [4,19]
print f(4,5) # [4,5]
print f(-1, z=deque()) # deque([-1,4])
Regards,
George
More information about the Python-ideas
mailing list