I don't see any questions on SO regarding this, so I would like to ask how a Python class object instance is passed into a function and how it behaves within the function. I have some suspicions from the behaviour I got from running this snippet:
(Note: I know there are better ways to achieve the same behaviour for this example. My actual use case involves a bit more complicated manouevers :-).
class Animal:
def __init__(self, name, sound):
self.name = name
self.sound = sound
def change_animal(animal_1, animal_2):
animal_1 = None
animal_1 = animal_2
# or better yet,
# animal_1 = copy.deepcopy(animal_2)
# main
animal_1 = Animal('dog', 'bark')
animal_2 = Animal('duck', 'quack')
change_animal(animal_1, animal_2)
print(animal_1.name)
Prints dog
. I always thought it would change the instance and print duck
.
Whereas using this:
def change_animal(animal_1, animal_2):
animal_1.name = animal_2.name
animal_1.sound = animal_2.sound
Prints duck
showing that the instance has been changed?
I wanted to avoid writing anything that requires me to reassign each attribute individually because there is a high likelihood of someone missing a variable and erroneously having a combination of updated and old values.
CodePudding user response:
In python you need to return the value. When calling the function python is making a copy of your animal_1 object and destroying it after the function ends. If you want to change animal_1 you need to return it as the function result.
class Animal:
def __init__(self, name, sound):
self.name = name
self.sound = sound
def change_animal(animal_1, animal_2):
animal_1 = deepcopy(animal_2)
return animal_1
# main
animal_1 = Animal('dog', 'bark')
animal_2 = Animal('duck', 'quack')
animal_1 = change_animal(animal_1, animal_2)
The other option is to create the function inside the Animal class.
class Animal:
def __init__(self, name, sound):
self.name = name
self.sound = sound
def change_animal(self, animal_2):
self.name = animal_2.name
self.sound = animal_2.sound
animal_1 = Animal('dog', 'bark')
animal_2 = Animal('duck', 'quack')
animal_1.change_animal(animal_2)
CodePudding user response:
The reason that in the first example the name doesn't change to duck
is because of something referred to as scope of a variable. You can read up more on formalities there, so lets keep it simple here:
Put informally, your first function change_animal
creates a new variable inside it called animal_1
. This variable is not visible outside of change_animal
, and is lost when the function ends.
Your second function change_animal
indeed takes the animals by reference, and manipulates the objects animal_1 which is visible in the scope of your script.
If you would want (for any reason) to somehow keep the style of your first change_animal
function, the example with minimal modifications could look like this:
class Animal:
def __init__(self, name, sound):
self.name = name
self.sound = sound
def change_animal(animal_1, animal_2):
animal_1 = None
animal_1 = animal_2
return animal_1
# or better yet,
# animal_1 = copy.deepcopy(animal_2)
# main
animal_1 = Animal('dog', 'bark')
animal_2 = Animal('duck', 'quack')
animal_1 = change_animal(animal_1, animal_2)
print(animal_1.name)