Home > OS >  Updating an instance of an object with the __init__ method
Updating an instance of an object with the __init__ method

Time:02-06

Reusing the __init__ method to change attributes' values

Python 3.10 on Windows 64bit

Let's say I have a class that has an update method which calls the __init__ method. The update method is created to avoid multiple line assignments of the attributes.

class Person:
     def __init__(self, name: str, age: int):
         self.name = name
         self.age = age

     def update(self, **attributes):
         self.__init__(**attributes)

Object instantiation:

p = Person(name="Alex", age=32)
print(p.name, p.age)

>> Alex 32

Object reference before:

print(p)

>> <__main__.Person object at 0x0000028B4ED949A0>

Calling for the update method:

p.update(name="Sam", age=80)
print(p.name, p.age)

>> Sam 80

Object reference after:

print(p)

>> <__main__.Person object at 0x0000028B4ED949A0>

Clearly, the reference hasn't changed!

Is this safe? Is there a chance where the object reference in memory gets changed?

Obviously the actual use of this is for large objects that has multiple parameters and get frequently modified at once as internal reactions. Some parameters are optional and don't get modified.

If I don't do it like this, I would have to write a cascade of if-else statements which I don't want to. :)

CodePudding user response:

__init__, unlike __new__, doesn't deal with memory references at all. self is already a valid object produced by __new__ which __init__ initializes.

You can do it the other way round for clarity:

class Person:
     def __init__(self, name: str, age: int):
         # Signal to whoever will read your code
         # that the class is supposed to have these attributes
         self.name = None
         self.age = None
         self.update(name=name, age=age)

     def update(self, name: str, age: int):
         self.name = name
         self.age = age

Now __init__ isn't called by other methods, so no confusion arises.

CodePudding user response:

in addition to ForceBru's answer if wanted

class Person:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age

    def update(self, **attributes):
        for attribute, value in attributes.items():
            if hasattr(self,attribute):
                setattr(x, attribute, value)
            else:
                raise AttributeError(f'{self.__name__} has no attribute: {attribute}')
        
x = Person(name='Henry',age=12)
print(f'name={x.name}, age={x.age}')
x.update(name='Joe')
print(f'name={x.name}, age={x.age}')
x.update(name='Kyle',age=20)
print(f'name={x.name}, age={x.age}')

gives output

name=Henry, age=12
name=Joe, age=12
name=Kyle, age=20

this is just template (you may have other specific behavior that want for example dont want users to overwrite attributes start with _, etc).

I will see ultimately ForceBru's is nice in terms of linters, intellisense, etc, so can use what works for you

  •  Tags:  
  • Related