https://realpython.com/python-mutable-vs-immutable-types/

Mutable objects are those that allow you to change their value or data in place without affecting the object’s identity (symbolic name).

Mutable types include:

In the context of 01. Namespaces main file, mutable types can be used to create objects that can be modified inside of functions while making the changes persist.

# option 1 is better
def modify_mutable_option1(dummyClass):
    dummyClass.counter += 1

dummyClass1 = DummyClass()
modify_mutable_option1(dummyClass1)

# option 2
def modify_mutable_option2(dummyClass):
    dummyClass.counter += 1
    return dummyClass

dummyClass2 = DummyClass()
dummyClass2 = modify_mutable_option2(dummyClass2)
Just use option 1, its faster, shorter and better.

Strange behaviour resulting from this

  1. Avoid mutable default arguments: Using a mutable type as a default argument in functions can lead to unexpected behavior because the default value is shared across all calls to the function.
Mutable default arguments are bad, my_list is defined on a global level and shared across all times the function is called.
def append_to_list(value, my_list=[]): 
	my_list.append(value) 
	return my_list
# Good practice 
def append_to_list(value, my_list=None): 
	if my_list is None: 
		my_list = [] 
	my_list.append(value) 
	return my_list
  1. Copying objects is not as simple as it looks like:
    Shallow vs. Deep Copy: When copying mutable objects, be aware that a shallow copy creates a new object but inserts references into it. A deep copy creates a new object and recursively copies all objects found.
import copy

original = [[1, 2, 3], [4, 5, 6]]

shallow_copy = copy.copy(original) # bad
deep_copy = copy.deepcopy(original) # this works