[Python-ideas] Mutable default arguments - another approach

Piotr Duda duda.piotr at gmail.com
Tue Jan 30 18:05:40 CET 2007


I think that this problem can be solved by the following change of
default argument behavior:
default arguments are evaluated in definition time (like in current
implementation), but right after being evaluated, result object is
checked if it's mutable (for example by checking of presence __copy__
special method or being instance of built in (sub)class
list/dict/set), if object is mutable, argument is marked by
COPY_DEF_ARG flag.
There are two reasons for this check being  done there:
1. performance
2. it can be controlled by "from __future__ import ..." statement in
per-file manner

Then if default argument is needed in function call, first
COPY_DEF_ARG flag is checked if not set, default argument behaves
exactly like in current implementation, if the flag is set, it's
shallow copy is used instead.

Adding following classes/functions to stdlib allow reproduce old
behavior as well as add some new.

class IterateDefaultArg(object):
	def __init__(self, iterator):
		self.__iterator = iterator
	def __copy__(self):
		return self.__iterator.next()

class DefaultArgWrapper(object):
	def __init__(self, generatorfunc):
		self.__generatorfunc = generatorfunc
	def __call__(self, *args, **kwargs):
		return DefaultArgObject(self.__generatorfunc(*args, **kwargs))

@DefaultArgWrapper
def nocopyarg(obj):
	while 1:
		yield obj

With this current definition like:

def foo(cache = {}):
  ...

need to be replaced by:

def foo(cache = nocopyarg({})):
  ...

If one want to use deep copy instead copy, it might be done like this:

@DefaultArgWrapper
def deepcopyarg(obj):
        from copy import deepcopy
        while 1:
                yield deepcopy(obj)

def foo(x = deepcopyarg(<some expression>)):
  ...


P.S. sorry for my bad English

-- 
闇に隠れた黒い力
弱い心を操る


More information about the Python-ideas mailing list