In Python function parameters can have default values. These default values are expressions which are executed when the function is defined, i.e. only once. The same default value will be used every time the function is called, thus modifying it will have an effect on every subsequent call. This can create some very confusing bugs.

It is also a bad idea to store mutable default value in another object (ex: as an attribute). Multiple instances will then share the same value and modifying one objet will modify all of them.

This rule raises an issue when:

Noncompliant Code Example

In the following example, the parameter "param" has list() as a default value. This list is created only once and then reused in every call. Thus when it appends 'a' to this list, the next call will have ['a'] as a default value.

def myfunction(param=list()):  # Noncompliant.
    param.append('a')  # modification of the default value.
    return param

print(myfunction()) # returns ['a']
print(myfunction()) # returns ['a', 'a']
print(myfunction()) # returns ['a', 'a', 'a']

In the following example the same list is used for multiple instances of MyClass.param.

class MyClass:
    def __init__(self, param=list()):  # Noncompliant.
        self.param = param  # The same list is used for every instance of MyClass

    def process(self, value):
        self.param.append(value)  # modifying the same list

a1, a2 = (MyClass(), MyClass())
a1.process("value")
print(a1.param)  # ['value']
print(a2.param)  # ['value']

Compliant Solution

def myfunction(param=None):
    if param is None:
        param = list()
    param.append('a')
    return param

print(myfunction()) # returns ['a']
print(myfunction()) # returns ['a']
print(myfunction()) # returns ['a']
class MyClass:
    def __init__(self, param=None):
        if param is None:
            self.param = list()
        else:
            self.param = param

    def process(self, value):
        self.param.append(value)

a1, a2 = (MyClass(), MyClass())
a1.process("value")
print(a1.param)  # ['value']
print(a2.param)  # []

Exceptions

In some very rare cases modifying a default value is ok. For example, default values can be used as a cache.

No issue will be raised when the parameter's name contains "cache" or "memo" (as in memoization).

See