Python chose to follow the design decision which evaluates the function's signature only once. So this code:
def test(x=[]):
x.append(5)
return x
print(test())
print(test())
Prints:
[5]
[5, 5]
I know it is possible to use None
as a default value, and to change the parameter value inside the function if it is None.
How can I write some code that change the behavior of test
, in a way that the default parameter would be reevaluated every time I call the function? The solution can include decorators and use classes as the default value.
We can use the function's __default__
property to "freeze" defaults (and __kwargs__
to "freeze" default keyword arguments):
def freeze_defaults(func):
defaults = func.__defaults__
kwdefaults = func.__kwdefaults__
@functools.wraps(func)
def wrapper(*args, **kwargs):
func.__defaults__ = copy.deepcopy(defaults)
func.__kwdefaults__ = copy.deepcopy(kwdefaults)
return func(*args, **kwargs)
return wrapper
Now:
@freeze_defaults
def test(x=[]):
x.append(5)
return x
print(test())
print(test())
Prints:
[5]
[5]
And even:
@freeze_defaults
def test(x=['hello!']):
x.append(5)
return x
print(test())
print(test())
Prints:
['hello!', 5]
['hello!', 5]