Home > Software engineering >  Weird issue during calling the object's method in python - 'self' pointing to the wro
Weird issue during calling the object's method in python - 'self' pointing to the wro

Time:11-11

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]
  • Related