Package: default-mutable
Default MutablePrevent mutable default value behaviorDefault Mutable is a Python decorator that overrides default mutable values and prevents object mutation from one call to another. More info onhttps://docs.python-guide.org/writing/gotchas/FeaturesEasy to usePreset default valueAdvantagesHighly flexibleLightweight and independentOpen-sourceReal use casesSupport & documentationAuthorsRudy FernandezInstallThe easiest way to install default_mutable using pip:pip install default_mutableExamplesPython’s default arguments are evaluated once when the function is defined, not each time the function is called (like it is in say, Ruby). This means that if you use a mutable default argument and mutate it, you will and have mutated that object for all future calls to the function as well.deffunction1(idx,dict1={},list1=[],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function1:')function1(idx=1)# 1 {'a1': 'a1'} ['a']function1(idx=2)# 2 {'a1': 'a1', 'a2': 'a2'} ['a', 'a']Setting all the arguments with mutable default arguments to anEMPTYdictionary or listfromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutabledeffunction2(idx,dict1={},list1=[],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function2:')function2(1)# 1 {'a1': 'a1'} ['a']function2(2)# 2 {'a2': 'a2'} ['a']Setting all the arguments with mutable default arguments to anEMPTYdictionary or listfromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutabledeffunction2_2(idx,dict1={},list1=['list_init'],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function2_2:')function2_2(1)# 1 {'a1': 'a1'} ['a']function2_2(2)# 2 {'a2': 'a2'} ['a']When the decorator is executed with not arguments, we get the default behavior (same as "function1")fromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutable()deffunction3(idx,dict1={},list1=[],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function3:')function3(idx=1)# 1 {'a1': 'a1'} ['a']function3(idx=2)# 2 {'a1': 'a1', 'a2': 'a2'} ['a', 'a']As no value is passed, the decorator set the default value for "dict1" and "list1" an empty dictionary and empty listfromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutable('dict1','list1')deffunction4(idx,dict1={},list1=[],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function4:')function4(idx=1)# 1 {'a1': 'a1'} ['a']function4(idx=2)# 2 {'a2': 'a2'} ['a']As no value is passed, the decorator set the default value for "dict1" and "list1" an empty dictionary and empty listfromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutable('dict1','list1')deffunction4_2(idx,dict1={},list1=['init'],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function4_2:')function4_2(idx=1)# 1 {'a1': 'a1'} ['a']function4_2(idx=2)# 2 {'a2': 'a2'} ['a']As no value is passed, the decorator set the default value for "list1" an empty list. "dict1" has the default behaviorfromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutable('list1')deffunction4_3(idx,dict1={},list1=[],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function4_3:')function4_3(idx=1)# 1 {'a1': 'a1'} ['a']function4_3(idx=2)# 2 {'a1': 'a1', 'a2': 'a2'} ['a']The default values are mutable and "list1" get incremented from one function to the otherdeffunction5(idx,dict1={},list1=['init'],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function5:')function5(idx=1)# 1 {'a1': 'a1'} ['init', 'a']function5(idx=2)# 2 {'a1': 'a1', 'a2': 'a2'} ['init', 'a', 'a']Default value for "list1" is not an empty listfromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutable('dict1',list1=['init'])deffunction6(idx,dict1={},list1=['init'],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function6:')function6(idx=1)# 1 {'a1': 'a1'} ['init', 'a']function6(idx=2)# 2 {'a2': 'a2'} ['init', 'a']Default value for "list1" is not an empty listfromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutable('dict1',list1=['init'])deffunction7(idx,dict1={},list1=[],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function7:')function7(idx=1)# 1 {'a1': 'a1'} ['init', 'a']function7(idx=2)# 2 {'a2': 'a2'} ['init', 'a']Default value are empty dictionary and empty listfromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutable('dict1',list1=[])deffunction7_2(idx,dict1={},list1=['init'],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function7_2:')function7_2(idx=1)# 1 {'a1': 'a1'} ['a']function7_2(idx=2)# 2 {'a2': 'a2'} ['a']Default value are empty dictionary and empty listfromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutable('dict1','list1')deffunction7_3(idx,dict1={},list1=['init'],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function7_3:')function7_3(idx=1)# 1 {'a1': 'a1'} ['a']function7_3(idx=2)# 2 {'a2': 'a2'} ['a']Default value for "dict1" and "list1" are presetfromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutable(dict1={'dict_init':'dict_init'},list1=['init'])deffunction8(idx,dict1={},list1=[],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function8:')function8(idx=1)# 1 {'dict_init': 'dict_init', 'a1': 'a1'} ['init', 'a']function8(idx=2)# 2 {'dict_init': 'dict_init', 'a2': 'a2'} ['init', 'a']Passed values are not overriddenfromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutable(dict1={'dict_init':'dict_init'},list1=['init'])deffunction9(idx,dict1={},list1=[],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function9:')function9(idx=1,dict1={'dict_value':'dict_value'},list1=['list_value'])# 1 {'dict_value': 'dict_value', 'a1': 'a1'} ['list_value', 'a']function9(idx=2,dict1={'dict_value':'dict_value'},list1=['list_value'])# 2 {'dict_value': 'dict_value', 'a2': 'a2'} ['list_value', 'a']Passed values are not overriddenfromdefault_mutable.DefaultMutableimportdefaultMutable@defaultMutable(dict1={'dict_init':'dict_init'},list1=['init'])deffunction10(idx,dict1={},list1=[],element='a'):list1.append(element)dict1[f'{element}{idx}']=f'{element}{idx}'print('',idx,dict1,list1)print('')print('function10:')function10(1,{'dict_value':'dict_value'},['list_value'])# 1 {'dict_value': 'dict_value', 'a1': 'a1'} ['list_value', 'a']function10(2,{'dict_value':'dict_value'},['list_value'])# 2 {'dict_value': 'dict_value', 'a2': 'a2'} ['list_value', 'a']