Reputation: 51
I have
import copy
class A:
_member_a: dict[str, str]
_member_b: Callable
def set_b(self, func):
self._member_b = func
def deep_copy(self):
return copy.deepcopy(self)
I can set the value of _member_b
with something like:
a = A()
a.set_b(some_actual_function_in_other_files)
and in another file, I have:
def some_actual_function_in_other_files(self):
# Implementation
def some_actual_function_in_other_files_2(self):
# Implementation
so in my test, I wrote:
def test(self):
a = A()
a._member_a = {"test", "test"}
a.set_b(some_actual_function_in_other_files)
copy = a.deep_copy()
self.assertIsNot(a._member_a, copy._member_a) # pass, because dictionary is mutable and deepcopy is not using the same reference
self.assertIsNot(a._member_b, copy._member_b) # fail, which means `a._member_b` and `copy._member_b` shares the same reference
I understand in copy.deepcopy(), if the object is immutable, Python just use copy the reference(e.g., integers). So in this case, is _member_b
immutable?
I believe so, because later I updated the copy._member_b
and I found a._member_b
still has the original value which means it's not affected by the change of the copy. Is it true?
Upvotes: 2
Views: 111
Reputation: 782105
Functions are mutable. You can see this in the following:
def foo():
pass
foo.x = 1
Assigning to foo.x
modifies the function object.
But copy.deepcopy()
doesn't make a copy of functions.
bar = copy.deepcopy(foo)
print(id(foo) == id(bar)) # prints True
It's a simplification to say that deepcopy()
makes a copy of all mutable objects. It's true for container types, but not for various system types.
While functions are mutable, we rarely use them as mutable containers. If you need to associate data with a function, you normally use a class; the data goes in instance variables, and the function can access them using self.attribute
. Then you make a copy of the instance to get independent objects.
Upvotes: 3
Reputation: 225125
Normal functions are mutable in Python, but copy.deepcopy
doesn’t copy them anyway:
This module does not copy types like module, method, stack trace, stack frame, file, socket, window, or any similar types. It does “copy” functions and classes (shallow and deeply), by returning the original object unchanged; this is compatible with the way these are treated by the pickle module.
import copy
def func():
pass
func2 = copy.deepcopy(func)
func.is_mutable = True # no error
print(func2.is_mutable) # True, not copied
print(func is func2) # True, not copied
Upvotes: 5