This rule raises an issue when a mutable object is used as the default value in dict.fromkeys() or
contextvars.ContextVar().
In Python, when you pass a mutable object as a default value to certain constructs, all instances share the same object reference rather than getting independent copies. This creates unintended shared state that leads to subtle mutation bugs.
Python evaluates the default value expression once when the code is defined, not each time it is used. The same object instance is then reused across all keys or contexts. This is different from creating new instances for each use.
This issue is related to, but distinct from, the more commonly known problem of mutable default arguments in function definitions (e.g., def
func(items=[])), which has the same underlying cause.
dict.fromkeys()The dict.fromkeys(keys, value) method creates a dictionary with all specified keys pointing to the same
value object. When this value is mutable (like a list or dictionary), all keys share the same object reference:
keys = ['a', 'b', 'c']
my_dict = dict.fromkeys(keys, [])
my_dict['a'].append(1)
print(my_dict) # {'a': [1], 'b': [1], 'c': [1]}
Modifying the list through one key affects all other keys because they all reference the same list object in memory.
ContextVar()Similarly, when you create a ContextVar with a mutable default value, that same object is shared across all contexts:
from contextvars import ContextVar
my_var = ContextVar('my_var', default=[])
my_var.get().append(1) # Modifies the shared default
This is particularly problematic in concurrent code where different contexts should have independent state.
Using mutable default values in these contexts can cause serious bugs:
ContextVar, shared mutable defaults can cause race conditions and data
corruption in concurrent codeFor dict.fromkeys(), replace it with a dictionary comprehension that creates a new instance of the mutable object for each key. For
ContextVar(), use a factory pattern or set the default in context initialization rather than passing a mutable default directly.
keys = ['a', 'b', 'c'] my_dict = dict.fromkeys(keys, []) # Noncompliant
keys = ['a', 'b', 'c']
my_dict = {key: [] for key in keys}
from contextvars import ContextVar
my_var = ContextVar('my_var', default=[]) # Noncompliant
from contextvars import ContextVar
my_var: ContextVar[list] = ContextVar('my_var')
def get_my_var() -> list:
try:
return my_var.get()
except LookupError:
value: list = []
my_var.set(value)
return value
dict.fromkeys() methodcontextvars.ContextVar