Why is the object name changed?

Here is my code:
class Individual:
@classmethod
def init(self, name):
self.character_name = name
def get_character_name(self):
return self.character_name
pass
individual1 = Individual(‘Buster’)
individual2 = Individual(‘Tobias’)
print(individual1.get_character_name())
print(individual2.get_character_name())

the output is:
Tobias
Tobias

Why the individual1’s name been changed after the individual is created?

Because __init__ should not be a class method. It is an ordinary
instance menthod called to initialise the new instance after it is made.

So, what happened above?

When you call a class method (normally via an instance), it is passed
the class itself as the first argument, not the instance.

So an ordinary method:

def m(self, x):
    self.x = x

and call it:

instance.m(3)

is passed the instance as the parameter self. When you set self.x
you’re setting the .x attribute on the instance.

However, if you make a class method, typically like this:

@classmethod
def m(cls, x):
    ... do something with the class and x ...

and call it via the instance like this:

instance.m(3)

it is not passed the instance as the first argument, it is passed the
class. You defined __init__ like this:

@classmethod
def __init__(self, name):
    self.character_name = name

When new instances are made, as you did here:

individual1 = Individual('Buster')

the new instance is initialised by calling:

individual1.__init__('Buster')

If __init__ were a normal method (and normally it is) that would end
up running:

Individual.__init__(individual1, 'Buster')

However, you made it a class method. So __init__ is called with the
class, not the instance, like this:

Individual.__init__(Individual, 'Buster')

even though you named the first parameter self. It still gets assigned
the class. So you’re setting the .character_name on the class, and
not on the instance.

Now, if you have an instance and you try to access some attribute .x,
and it has no .x attribute, Python will look on the class for a .x
attribute. (This is actually useful.)

Anyway, when you go:

print(individual1.get_character_name())

the instance individual1 has no .get_character_name attribute,
because your class method set it on the class. So Python looks for it on
the class and finds it.

So there’s one class, with its solitary .character_name attribute.
When you made the first instance it got set to 'Buster'. And when you
made the second instance the class attribute got set to 'Tobias'.
Neither instance has an attribute, only the class. So regardless of
which instance you access, you always find the single class attribute,
which is now 'Tobias'.

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like

Thank you so much!
I delete the @classmethod and the code words normally again.