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
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.