Basic OOPS and Advanced Concepts
Contents
Basic OOPS and Advanced Concepts#
[1]:
class Employee:
number_of_leaves = 8
def __init__(self,name,salary,role):
self.name = name
self.salary = salary
self.role = role
def print_details(self):
print(f"""
NAME :{self.name}
SALARY :{self.salary}
ROLE :{self.role}
""")
@classmethod
def change_leaves(cls,new_leaves):
cls.number_of_leaves = new_leaves
@classmethod
def instance_with_dash(cls,params_dash):
return cls(*params_dash.split("-"))
@staticmethod
def print_good_string(string):
print(f"this is a good string : {string}")
e1 = Employee("E1",45000,"t1")
e2 = Employee.instance_with_dash("E2-50000-t2")
e1.print_details()
e2.print_details()
print(e1.number_of_leaves, e2.number_of_leaves)
e1.number_of_leaves = 10
print(e1.number_of_leaves)
Employee.number_of_leaves = 20
print(e1.number_of_leaves, e2.number_of_leaves)
e2.number_of_leaves = 10
print(Employee.number_of_leaves, e2.number_of_leaves)
e1.print_good_string("good1")
Employee.print_good_string("good2")
NAME :E1
SALARY :45000
ROLE :t1
NAME :E2
SALARY :50000
ROLE :t2
8 8
10
10 20
20 10
this is a good string : good1
this is a good string : good2
Single Inheritance#
[2]:
class Player:
def __init__(self,name,sports):
self.name = name
self.sports = sports
def print_details(self):
print(f"""
NAME :{self.name}
SPORTS :{self.sports}
""")
without super()#
[3]:
class Programmer(Employee,Player):
language ="C++"
def print_language(self):
print(self.language)
p1 = Programmer("e1",35000,"P1")
p1.print_details()
p1.print_language()
NAME :e1
SALARY :35000
ROLE :P1
C++
[4]:
# sequence matters
## this will throw error
class Programmer(Player,Employee):
language ="C++"
def print_language(self):
print(self.language)
p1 = Programmer("e1",35000,"P1")
p1.print_details()
p1.print_language()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-a25debaa34a6> in <module>
9 print(self.language)
10
---> 11 p1 = Programmer("e1",35000,"P1")
12 p1.print_details()
13 p1.print_language()
TypeError: __init__() takes 3 positional arguments but 4 were given
[5]:
class Programmer(Player,Employee):
language ="C++"
def print_language(self):
print(self.language)
p1 = Programmer("e1",["tennis","cricket"])
p1.print_details()
p1.print_language()
NAME :e1
SPORTS :['tennis', 'cricket']
C++
Heirarchy in descending order#
instance variable child > child class variable > parent instance variable > parent class variable
[6]:
class A:
classvar1 = "this is a class vairable in class A"
def __init__(self):
self.classvar1 = "this is a instance variable in class A"
class B(A):
classvar1 = "this is a class variable in class B"
def __init__(self):
self.classvar1 = "this is a instance variable in class B"
b = B()
b.classvar1
[6]:
'this is a instance variable in class B'
[7]:
class A:
classvar1 = "this is a class vairable in class A"
def __init__(self):
self.classvar1 = "this is a instance variable in class A"
class B(A):
classvar1 = "this is a class variable in class B"
# def __init__(self):
# self.classvar1 = "this is a instance variable in class B"
b = B()
b.classvar1
[7]:
'this is a instance variable in class A'
[8]:
class A:
classvar1 = "this is a class vairable in class A"
# def __init__(self):
# self.classvar1 = "this is a instance variable in class A"
class B(A):
classvar1 = "this is a class variable in class B"
# def __init__(self):
# self.classvar1 = "this is a instance variable in class B"
b = B()
b.classvar1
[8]:
'this is a class variable in class B'
[9]:
class A:
classvar1 = "this is a class vairable in class A"
# def __init__(self):
# self.classvar1 = "this is a instance variable in class A"
class B(A):
pass
# classvar1 = "this is a class variable in class B"
# def __init__(self):
# self.classvar1 = "this is a instance variable in class B"
b = B()
b.classvar1
[9]:
'this is a class vairable in class A'
super()#
[10]:
class A:
classvar1 = "this is a class vairable in class A"
def __init__(self):
self.var1 = "this is a instance variable in class A"
class B(A):
classvar1 = "this is a class variable in class B"
def __init__(self):
super().__init__()
self.var1 = "this is a instance variable in class B" ## overridden by child
b = B()
b.var1
[10]:
'this is a instance variable in class B'
[11]:
class A:
classvar1 = "this is a class vairable in class A"
def __init__(self):
self.var1 = "this is a instance variable in class A"
class B(A):
classvar1 = "this is a class variable in class B"
def __init__(self):
self.var1 = "this is a instance variable in class B"
super().__init__() ## overridden by parent
b = B()
b.var1
[11]:
'this is a instance variable in class A'
Diamond shape problem#
-----------> A <-----------
| |
| |
| |
B C
^ ^
| |
| |
| |
------------`D`------------
[12]:
class A:
def func(self):
print("CLASS A")
class B(A):
def func(self):
print("CLASS B")
class C(A):
def func(self):
print("CLASS C")
class D(B,C):
pass
a = A()
b = B()
c = C()
d = D()
d.func()
CLASS B
[13]:
class A:
def func(self):
print("CLASS A")
class B(A):
def func(self):
print("CLASS B")
class C(A):
def func(self):
print("CLASS C")
class D(C,B):
pass
a = A()
b = B()
c = C()
d = D()
d.func()
CLASS C
Operator overloading and dunder methods(underscore methods)#
https://docs.python.org/3/library/operator.html
[14]:
class Employee:
number_of_leaves = 8
def __init__(self,name,salary,role):
self.name = name
self.salary = salary
self.role = role
def print_details(self):
print(f"""
NAME :{self.name}
SALARY :{self.salary}
ROLE :{self.role}
""")
@classmethod
def change_leaves(cls,new_leaves):
cls.number_of_leaves = new_leaves
@classmethod
def instance_with_dash(cls,params_dash):
return cls(*params_dash.split("-"))
@staticmethod
def print_good_string(string):
print(f"this is a good string : {string}")
e1 = Employee("E1",45000,"SDE1")
e2 = Employee("E2",40000,"SDE1")
print(e1+e2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-14-42bd4dc47e1e> in <module>
30 e2 = Employee("E2",40000,"SDE1")
31
---> 32 print(e1+e2)
TypeError: unsupported operand type(s) for +: 'Employee' and 'Employee'
[15]:
class Employee:
number_of_leaves = 8
def __init__(self,name,salary,role):
self.name = name
self.salary = salary
self.role = role
def print_details(self):
print(f"""
NAME :{self.name}
SALARY :{self.salary}
ROLE :{self.role}
""")
@classmethod
def change_leaves(cls,new_leaves):
cls.number_of_leaves = new_leaves
@classmethod
def instance_with_dash(cls,params_dash):
return cls(*params_dash.split("-"))
@staticmethod
def print_good_string(string):
print(f"this is a good string : {string}")
## create a dunder method to work on add operation
def __add__(self,other):
return self.salary + other.salary
def __truediv__(self,other):
return self.salary / other.salary
e1 = Employee("E1",45000,"SDE1")
e2 = Employee("E2",40000,"SDE1")
print(e1+e2)
print(e1/e2)
85000
1.125
[16]:
dir(Employee)
[16]:
['__add__',
'__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__truediv__',
'__weakref__',
'change_leaves',
'instance_with_dash',
'number_of_leaves',
'print_details',
'print_good_string']
[17]:
e1 ## here it is showing default
[17]:
<__main__.Employee at 0x7f747cba7370>
[18]:
class Employee:
number_of_leaves = 8
def __init__(self,name,salary,role):
self.name = name
self.salary = salary
self.role = role
def print_details(self):
print(f"""
NAME :{self.name}
SALARY :{self.salary}
ROLE :{self.role}
""")
@classmethod
def change_leaves(cls,new_leaves):
cls.number_of_leaves = new_leaves
@classmethod
def instance_with_dash(cls,params_dash):
return cls(*params_dash.split("-"))
@staticmethod
def print_good_string(string):
print(f"this is a good string : {string}")
## create a dunder method to work on add operation
def __add__(self,other):
return self.salary + other.salary
def __truediv__(self,other):
return self.salary / other.salary
def __repr__(self):
return f"""Employee('{self.name}',{self.salary},'{self.role}')"""
e1 = Employee("E1",45000,"SDE1")
e2 = Employee("E2",40000,"SDE1")
print(e1)
print(repr(e1)) ##overridden repr
Employee('E1',45000,'SDE1')
Employee('E1',45000,'SDE1')
[19]:
class Employee:
number_of_leaves = 8
def __init__(self,name,salary,role):
self.name = name
self.salary = salary
self.role = role
def print_details(self):
print(f"""
NAME :{self.name}
SALARY :{self.salary}
ROLE :{self.role}
""")
@classmethod
def change_leaves(cls,new_leaves):
cls.number_of_leaves = new_leaves
@classmethod
def instance_with_dash(cls,params_dash):
return cls(*params_dash.split("-"))
@staticmethod
def print_good_string(string):
print(f"this is a good string : {string}")
## create a dunder method to work on add operation
def __add__(self,other):
return self.salary + other.salary
def __truediv__(self,other):
return self.salary / other.salary
def __repr__(self):
return f"""Employee('{self.name}',{self.salary},'{self.role}')"""
def __str__(self):
return f"""
NAME :{self.name}
SALARY :{self.salary}
ROLE :{self.role}
"""
e1 = Employee("E1",45000,"SDE1")
e2 = Employee("E2",40000,"SDE1")
print(e1) ##overridden repr with str
print(str(e1))
print(repr(e1))
NAME :E1
SALARY :45000
ROLE :SDE1
NAME :E1
SALARY :45000
ROLE :SDE1
Employee('E1',45000,'SDE1')
Abstract Base Class#
[20]:
from abc import ABC,abstractmethod
class Shape(ABC):
@abstractmethod
def print_area(self):
pass
[21]:
class Square(Shape):
def __init__(self,side):
self.side = side
s = Square(10)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-21-1c588ec6d471> in <module>
5
6
----> 7 s = Square(10)
TypeError: Can't instantiate abstract class Square with abstract methods print_area
[22]:
class Square(Shape):
def __init__(self,side):
self.side = side
def print_area(self):
print(self.side**2)
s = Square(10)
s.print_area()
100
[23]:
Shape() # cant create
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-23-c85743fd6946> in <module>
----> 1 Shape() # cant create
TypeError: Can't instantiate abstract class Shape with abstract methods print_area
setter and property decorator#
[24]:
class Subscriber:
def __init__(self,fname,lname):
self.fname = fname
self.lname = lname
self._email = f"{self.fname}.{self.lname}@faloola.com"
def name(self):
return f"{self.fname} {self.lname}"
def email(self):
return self._email
s = Subscriber("Nishant","Maheshwari")
print(s.name())
print(s.email())
s.lname = "Baheti"
print(s.name())
print(s.email()) ## email will not change
Nishant Maheshwari
Nishant.Maheshwari@faloola.com
Nishant Baheti
Nishant.Maheshwari@faloola.com
[25]:
class Subscriber:
def __init__(self,fname,lname):
self.fname = fname
self.lname = lname
# self.email = f"{self.fname}.{self.lname}@faloola.com"
def name(self):
return f"{self.fname} {self.lname}"
@property
def email(self):
return f"{self.fname}.{self.lname}@faloola.com"
s = Subscriber("Nishant","Maheshwari")
print(s.name())
print(s.email())
s.lname = "Baheti"
print(s.name())
print(s.email()) ## email changed but set as property which is not callable
Nishant Maheshwari
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-25-8f6b2bf645ba> in <module>
15 s = Subscriber("Nishant","Maheshwari")
16 print(s.name())
---> 17 print(s.email())
18
19 s.lname = "Baheti"
TypeError: 'str' object is not callable
[26]:
class Subscriber:
def __init__(self,fname,lname):
self.fname = fname
self.lname = lname
# self.email = f"{self.fname}.{self.lname}@faloola.com"
def name(self):
return f"{self.fname} {self.lname}"
@property
def email(self):
return f"{self.fname}.{self.lname}@faloola.com"
s = Subscriber("Nishant","Maheshwari")
print(s.name())
print(s.email)
s.lname = "Baheti"
print(s.name())
print(s.email) ## email changed
Nishant Maheshwari
Nishant.Maheshwari@faloola.com
Nishant Baheti
Nishant.Baheti@faloola.com
[27]:
class Subscriber:
def __init__(self,fname,lname):
self.fname = fname
self.lname = lname
# self.email = f"{self.fname}.{self.lname}@faloola.com"
def name(self):
return f"{self.fname} {self.lname}"
@property
def email(self):
return f"{self.fname}.{self.lname}@faloola.com"
s = Subscriber("Nishant","Maheshwari")
print(s.name())
print(s.email)
s.lname = "Baheti"
print(s.name())
print(s.email) ## email changed
s.email = "foo.bar@faloola.com"
Nishant Maheshwari
Nishant.Maheshwari@faloola.com
Nishant Baheti
Nishant.Baheti@faloola.com
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-27-efecc42b7d81> in <module>
21 print(s.email) ## email changed
22
---> 23 s.email = "foo.bar@faloola.com"
AttributeError: can't set attribute
[28]:
class Subscriber:
def __init__(self,fname,lname):
self.fname = fname
self.lname = lname
def name(self):
return f"{self.fname} {self.lname}"
@property
def email(self):
return f"{self.fname}.{self.lname}@faloola.com"
@email.setter
def email(self,new_email):
name = new_email.split("@")[0]
name_l = name.split(".")
self.fname = name_l[0]
self.lname = name_l[1]
s = Subscriber("Nishant","Maheshwari")
print(s.name())
print(s.email)
s.lname = "Baheti"
print(s.name())
print(s.email) ## email changed
s.email = "foo.bar@faloola.com"
print(s.name())
print(s.email)
Nishant Maheshwari
Nishant.Maheshwari@faloola.com
Nishant Baheti
Nishant.Baheti@faloola.com
foo bar
foo.bar@faloola.com
[29]:
class Subscriber:
def __init__(self,fname,lname):
self.fname = fname
self.lname = lname
def name(self):
return f"{self.fname} {self.lname}"
@property
def email(self):
if self.fname is None or self.lname is None:
return "Email is not set"
return f"{self.fname}.{self.lname}@faloola.com"
@email.setter
def email(self,new_email):
name = new_email.split("@")[0]
name_l = name.split(".")
self.fname = name_l[0]
self.lname = name_l[1]
@email.deleter
def email(self):
self.fname = None
self.lname = None
s = Subscriber("Nishant","Maheshwari")
print(s.name())
print(s.email)
s.lname = "Baheti"
print(s.name())
print(s.email) ## email changed
s.email = "foo.bar@faloola.com"
print(s.name())
print(s.email)
del s.email
print(s.email)
Nishant Maheshwari
Nishant.Maheshwari@faloola.com
Nishant Baheti
Nishant.Baheti@faloola.com
foo bar
foo.bar@faloola.com
Email is not set
Object instrospection#
[30]:
type("hello")
[30]:
str
[32]:
id("hello")
[32]:
140138285539376
[33]:
dir("hello")
[33]:
['__add__',
'__class__',
'__contains__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__getnewargs__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mod__',
'__mul__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__rmod__',
'__rmul__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'capitalize',
'casefold',
'center',
'count',
'encode',
'endswith',
'expandtabs',
'find',
'format',
'format_map',
'index',
'isalnum',
'isalpha',
'isascii',
'isdecimal',
'isdigit',
'isidentifier',
'islower',
'isnumeric',
'isprintable',
'isspace',
'istitle',
'isupper',
'join',
'ljust',
'lower',
'lstrip',
'maketrans',
'partition',
'replace',
'rfind',
'rindex',
'rjust',
'rpartition',
'rsplit',
'rstrip',
'split',
'splitlines',
'startswith',
'strip',
'swapcase',
'title',
'translate',
'upper',
'zfill']
[35]:
import inspect
print(inspect.getmembers("Hello"))
[('__add__', <method-wrapper '__add__' of str object at 0x7f747d454270>), ('__class__', <class 'str'>), ('__contains__', <method-wrapper '__contains__' of str object at 0x7f747d454270>), ('__delattr__', <method-wrapper '__delattr__' of str object at 0x7f747d454270>), ('__dir__', <built-in method __dir__ of str object at 0x7f747d454270>), ('__doc__', "str(object='') -> str\nstr(bytes_or_buffer[, encoding[, errors]]) -> str\n\nCreate a new string object from the given object. If encoding or\nerrors is specified, then the object must expose a data buffer\nthat will be decoded using the given encoding and error handler.\nOtherwise, returns the result of object.__str__() (if defined)\nor repr(object).\nencoding defaults to sys.getdefaultencoding().\nerrors defaults to 'strict'."), ('__eq__', <method-wrapper '__eq__' of str object at 0x7f747d454270>), ('__format__', <built-in method __format__ of str object at 0x7f747d454270>), ('__ge__', <method-wrapper '__ge__' of str object at 0x7f747d454270>), ('__getattribute__', <method-wrapper '__getattribute__' of str object at 0x7f747d454270>), ('__getitem__', <method-wrapper '__getitem__' of str object at 0x7f747d454270>), ('__getnewargs__', <built-in method __getnewargs__ of str object at 0x7f747d454270>), ('__gt__', <method-wrapper '__gt__' of str object at 0x7f747d454270>), ('__hash__', <method-wrapper '__hash__' of str object at 0x7f747d454270>), ('__init__', <method-wrapper '__init__' of str object at 0x7f747d454270>), ('__init_subclass__', <built-in method __init_subclass__ of type object at 0x557127ed5780>), ('__iter__', <method-wrapper '__iter__' of str object at 0x7f747d454270>), ('__le__', <method-wrapper '__le__' of str object at 0x7f747d454270>), ('__len__', <method-wrapper '__len__' of str object at 0x7f747d454270>), ('__lt__', <method-wrapper '__lt__' of str object at 0x7f747d454270>), ('__mod__', <method-wrapper '__mod__' of str object at 0x7f747d454270>), ('__mul__', <method-wrapper '__mul__' of str object at 0x7f747d454270>), ('__ne__', <method-wrapper '__ne__' of str object at 0x7f747d454270>), ('__new__', <built-in method __new__ of type object at 0x557127ed5780>), ('__reduce__', <built-in method __reduce__ of str object at 0x7f747d454270>), ('__reduce_ex__', <built-in method __reduce_ex__ of str object at 0x7f747d454270>), ('__repr__', <method-wrapper '__repr__' of str object at 0x7f747d454270>), ('__rmod__', <method-wrapper '__rmod__' of str object at 0x7f747d454270>), ('__rmul__', <method-wrapper '__rmul__' of str object at 0x7f747d454270>), ('__setattr__', <method-wrapper '__setattr__' of str object at 0x7f747d454270>), ('__sizeof__', <built-in method __sizeof__ of str object at 0x7f747d454270>), ('__str__', <method-wrapper '__str__' of str object at 0x7f747d454270>), ('__subclasshook__', <built-in method __subclasshook__ of type object at 0x557127ed5780>), ('capitalize', <built-in method capitalize of str object at 0x7f747d454270>), ('casefold', <built-in method casefold of str object at 0x7f747d454270>), ('center', <built-in method center of str object at 0x7f747d454270>), ('count', <built-in method count of str object at 0x7f747d454270>), ('encode', <built-in method encode of str object at 0x7f747d454270>), ('endswith', <built-in method endswith of str object at 0x7f747d454270>), ('expandtabs', <built-in method expandtabs of str object at 0x7f747d454270>), ('find', <built-in method find of str object at 0x7f747d454270>), ('format', <built-in method format of str object at 0x7f747d454270>), ('format_map', <built-in method format_map of str object at 0x7f747d454270>), ('index', <built-in method index of str object at 0x7f747d454270>), ('isalnum', <built-in method isalnum of str object at 0x7f747d454270>), ('isalpha', <built-in method isalpha of str object at 0x7f747d454270>), ('isascii', <built-in method isascii of str object at 0x7f747d454270>), ('isdecimal', <built-in method isdecimal of str object at 0x7f747d454270>), ('isdigit', <built-in method isdigit of str object at 0x7f747d454270>), ('isidentifier', <built-in method isidentifier of str object at 0x7f747d454270>), ('islower', <built-in method islower of str object at 0x7f747d454270>), ('isnumeric', <built-in method isnumeric of str object at 0x7f747d454270>), ('isprintable', <built-in method isprintable of str object at 0x7f747d454270>), ('isspace', <built-in method isspace of str object at 0x7f747d454270>), ('istitle', <built-in method istitle of str object at 0x7f747d454270>), ('isupper', <built-in method isupper of str object at 0x7f747d454270>), ('join', <built-in method join of str object at 0x7f747d454270>), ('ljust', <built-in method ljust of str object at 0x7f747d454270>), ('lower', <built-in method lower of str object at 0x7f747d454270>), ('lstrip', <built-in method lstrip of str object at 0x7f747d454270>), ('maketrans', <built-in method maketrans of type object at 0x557127ed5780>), ('partition', <built-in method partition of str object at 0x7f747d454270>), ('replace', <built-in method replace of str object at 0x7f747d454270>), ('rfind', <built-in method rfind of str object at 0x7f747d454270>), ('rindex', <built-in method rindex of str object at 0x7f747d454270>), ('rjust', <built-in method rjust of str object at 0x7f747d454270>), ('rpartition', <built-in method rpartition of str object at 0x7f747d454270>), ('rsplit', <built-in method rsplit of str object at 0x7f747d454270>), ('rstrip', <built-in method rstrip of str object at 0x7f747d454270>), ('split', <built-in method split of str object at 0x7f747d454270>), ('splitlines', <built-in method splitlines of str object at 0x7f747d454270>), ('startswith', <built-in method startswith of str object at 0x7f747d454270>), ('strip', <built-in method strip of str object at 0x7f747d454270>), ('swapcase', <built-in method swapcase of str object at 0x7f747d454270>), ('title', <built-in method title of str object at 0x7f747d454270>), ('translate', <built-in method translate of str object at 0x7f747d454270>), ('upper', <built-in method upper of str object at 0x7f747d454270>), ('zfill', <built-in method zfill of str object at 0x7f747d454270>)]
[ ]: