def lazy(a=None): if a is None: a = random.random() return a x = lazy() y = lazy() assert x != y Extent Generally a default argument will behave identically to an argument passed by parameter or a local variable declared at the start of the function, and have the same scope and extent (lifetime) as a parameter or other local variable, namely an automatic variable which is deallocated on function termination. In other cases a default argument may instead be statically allocated. If the variable is mutable, it will then retain its value across function calls, as with a static variable. This behavior is found in Python for mutable types, such as lists. As with evaluation, in order to ensure the same extent as a local variable, one can use a sentinel value: def eager(a=[]): return a x = eager() x += [1] assert eager() == [1] def lazy(a=None): if a is None: a = [] return a x = lazy() x += [1] assert lazy() == [] References Articles with example C++ code Articles with example Python (programming language) code C++ Subroutines