Search code examples
pythonclassooppython-class

I am have trouble understanding which parameters to include in which methods


I'm working through a chapter on classes and I'm having trouble understanding which parameters to include in which methods. For example in this code:

class Employee:
    '''A simple class to describe an employee.'''

    def __init__(self, first_name, last_name, salary, sal_raise=5000):
        '''Initialize first name, last name, salary, and maybe raise?'''
        self.first_name = first_name
        self.last_name = last_name
        self.salary = salary
        self.sal_raise = sal_raise

    def give_raise(self):
        self.salary += self.sal_raise
        print(f'''You've given {self.first_name} a ${self.sal_raise} raise!''')

sal_raise is currently a parameter in the __init__() method. Is this the only way to do it? Is it not possible instead initialize sal_raise in the give_raise method? Something like this:

def give_raise(self):
    self.sal_raise = 5000
    self.salary += self.sal_raise

Solution

  • Do you know what is the difference between __init__() method and other methods defined inside the class ? Nothing ! the only difference is __init__() "automatically" gets called when the class is instantiated.

    What is the benefit ? image you don't have __init__(), in order do set some initial value for your instance you have to call a method explicitly:

    class Person:
    
        def initialize_my_class(self, name):
            self.name = name
            self.age = 10
            self.height = 100
    
    p1 = Person()
    
    print(p1.name)    #  AttributeError: 'Person' object has no attribute 'name'
    print(p1.age)     #  AttributeError: 'Person' object has no attribute 'age'
    print(p1.height)  #  AttributeError: 'Person' object has no attribute 'height'
    

    Why ? because python doesn't automatically run my initialize_my_class method. If I want this to work, I have to call it myself :

    class Person:
    
        def initialize_my_class(self, name):
            self.name = name
            self.age = 10
            self.height = 100
    
    p1 = Person()
    
    p1.initialize_my_class('Soroush')  # <---------- Here
    
    print(p1.name)
    print(p1.age)
    print(p1.height)
    

    __init__() just does this automatically. Imagine you have tens of methods inside your class, without __init__() you have to call each of them one after the other... But instead we just do everything we want for initialization inside __init__().

    Now your sal_raise : Generally, If this is something that you need it in initialization part, define it inside __init__(). But sometimes we want our instance to have an attribute "whenever" we want ! not at the initialization phase. why ?

    Sometimes we have to calculate something that is heavy enough or time consuming(not just storing a number), we set that attribute to our instance in a separate method and we call it when is necessary! maybe when a program reaches to a certain condition. So just let __init__ to include other initializations that is necessary for us in instantiating phase :

    class Person:
    
        def __init__(self, name):
            self.name = name
            self.age = 10
            self.height = 100
            
        def time_consuming_method(self):
            # This 'foo' is the result of heavy calculation here
            self.new_var = 'foo'
    
    p1 = Person('soroush')
    
    # special condition is true...
    # Now it's time to call 'time_consuming_method':
    p1.time_consuming_method()
    

    Hope that makes sense.