
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 -- 闇に隠れた黒い力 弱い心を操る