I found some weird behaviour during the creation of classes and objects in python3.
I dislike typing every time "self" word and constructors during writing classes if my class is very simple so I made the class 'Foo' that copies static variables and turns them into the new object's attributes.
At the beginning I was making 'Foo' subclasses without methods and then everything worked fine - the objects were distinct. However, after adding a method to the subclass, I found out that the self value somehow points to wrong object.
Here is the code I made:
from copy import deepcopy
class Foo:
def __init__(self):
for i in filter(lambda x: "__" not in x, self.__dir__()):
self.__setattr__(i, deepcopy(self.__getattribute__(i)))
class Bar(Foo):
val = []
def func(self):
print("Self ID:", id(self))
print(self.val)
obj = Bar()
obj.val.append(2)
print("Object ID:", id(obj))
print(obj.val)
obj.func()
# Prints:
#
# Object ID: 2507794284496
# [2]
# Self ID: 2507794283248
# []
#
# While it should print same ID and [2] in both lists
I am sure that I forgot something important during creation of the Foo class because if I remove "(Foo)" part then IDs and the lists are the same.
Could someone explain me what is wrong? Thank you in advance for help! <3
CodePudding user response:
You're retrieving a self.func
method object, deep copying it, and assigning the result to self.func
.
The deep copy creates a method object bound to a new Bar
instance, which will have its own copies of any instance attributes created before the method was copied, and no instance attribute for any instance attributes that would have been created after the method was copied. Either way, it's the wrong instance with the wrong attributes.
CodePudding user response:
I disabled methods from copying and it seems working now. Here is the code:
from copy import deepcopy
class Foo:
def __init__(self):
for i in filter(lambda x: "__" not in x, self.__dir__()):
attr = self.__getattribute__(i)
if attr.__class__.__name__ != 'method':
self.__setattr__(i, deepcopy(attr))
class Bar(Foo):
val = []
def func(self):
print("Self ID:", id(self))
print(self.val)
obj = Bar()
obj.val.append(2)
print("Object ID:", id(obj))
print(obj.val)
obj.func()
# Object ID: 2785572945632
# [2]
# Self ID: 2785572945632
# [2]
I don't see any usecase where copying the method would be necessary so it's not an issue really for me.
Great thanks @user2357112 for explaining me what was not working <3
CodePudding user response:
try this
class Bar(Foo):
def __init__(self):
super().__init__(self)
self.val = []
def func(self):
print("Self ID:", id(self))
print(self.val)
should it works.
Object ID: 140516181578944
[2]
Self ID: 140516181578944
[2]