08. Classes and Object

Class

A class Contains variable , constants , constructors , methods , inner classes. A class defines the state and behavior of an object. it describes how an object is created, what values are stored in an object and what operations are performed by an object. Class in nothing but defining the structure of an object. Each class should be an expert class that contains related attributes and methods and provides expert services.

For Example :
class Hello:
    pass

print(Hello())

Output:
<__main__.Hello object at 0x000000BA5881DFD0>

Or
class Hello:
    def __init__(self):
      print("Hello world")

h=Hello()
Output: Hello world

Attributes and Methods in class

A class by itself is of no use unless there is some functionality associated with it. Functionalities are defined by setting attributes, which act as containers for data and functions related to those attributes. Those functions are called methods

Attributes

You can define the following class with the name Shape. This class will have an attribute name.

For Example:
class Shape:
    name = "Circle" # set an attribute `name` of the class

You can assign the class to a variable. This is called object instantiation. You will then be able to access the attributes that are present inside the class using the dot(.)operator. For example, in the Shape example, you can access the attribute name of the class Shape.

# instantiate the class Shape and assign it to variable Shape
shape = Shape()

# access the class attribute name inside the class Shape.
print(shape.name)

Methods

Once there are attributes that “belong” to the class, you can define functions that will access the class attribute. These functions are called methods. When you define methods, you will need to always provide the first argument to the method with a self keyword.

For example, you can define a class Shape, which has one attribute name and one method change_name. The method change name will take in an argument new_name along with the keyword self.

class Shape:
     name = "circle"

     def change_name(self, new_name): # note that the first argument is
        self.name = new_name # access the class attribute with the self keyword

Now, you can instantiate this class Shape with a variable name and then change the name with the method change_name.

shape_obj = Shape() # instantiate the class
print(shape_obj .name) # print the current object name
shape_obj.change_name("Triangle") # change the name using the change_name method
print(shape_obj .name)

Output
circle
triangle

create First Program using class

  • The variable empCount is a class variable whose value is shared among all instances of this class. This can be accessed as Employee.empCount from inside the class or outside the class.
  • The first method __init__() is a special method, which is called class constructor or initialization method that Python calls when you create a new instance of this class.
  • You declare other class methods like normal functions with the exception that the first argument to each method is self. Python adds the self argument to the list for you; you do not need to include it when you call the methods.
For Example:

class Employee:
     'Common base class for all employees'

     empCount = 0

    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
        Employee.empCount += 1

    def displayCount(self):
        print("Total Employee %d = " % Employee.empCount)

    def displayEmployee(self):

        print("Name : ", self.name, "\nSalary: ", self.salary)


e=Employee("Ram",5000)
e.displayCount()
e.displayEmployee()

Output:

Total Employee = 1
Name e: Ram

Salary: 5000

The __init__() Function

The examples above are classes and objects in their simplest form, and are not really useful in real life applications.

To understand the meaning of classes we have to understand the built-in __init__() function.
All classes have a function called __init__(), which is always executed when the class is being initiated.
Use the __init__() function to assign values to object properties, or other operations that are necessary to do when the object is being created:

Create a class named Person, use the __init__() function to assign values for name and age:

For Example:

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

person_obj = Person("Ram", 36)
print(person_obj .name)
print(person_obj .age)

Output
Ram
36

Object Methods

Objects can also contain methods. Methods in objects are functions that belong to the object.

Let us create a method in the Person class

For Example:
class Person:
  def __init__(self, name, age):
    self.name = name
    self.age = age

  def display(self):
     print("Hello my name is " + self.name+" and my age is : ",self.age)

p1 = Person("Ram", 36)
p1.display()

Output:
Hello my name is Ram and my age is : 36


Note: The self parameter is a reference to the current instance of the class, and is used to access variables that belong to the class.

The self Parameter

The self parameter is a reference to the current instance of the class, and is used to access variables that belongs to the class.
It does not have to be named self , you can call it whatever you like, but it has to be the first parameter of any function in the class:
Use the words my_silly_object and abc instead of self:

For Example:
class Person:
     def __init__(my_silly_object , name, age):
        my_silly_object.name = name
        my_silly_object .age = age

     def myfunc(abc):
        print("Hello my name is " + abc.name)

p1 = Person("Ram", 36)
p1.myfunc()

Output
Hello my name is Ram

OOPS

Object Oriented programming  represents a programming methodology based on objects instead of just procedures and functions.

An object is an expert of relevant services that does not overlap responsibilities of other expert object. Responsibilities and structure of an object is defined by class.

Object containing related attributes and method is called "Expert Object". An application is  made of multiple expert objects.

 



There are three key concepts of oop.
  1. Encapsulation: creates expert classes
  2. Inheritance: creates  specialized classes
  3. Polymorphism: provide dynamic behavior

Encapsulation

Gathering all related methods and attributes in a  class is called encapsulation.in other words binding related data members and methods in a class, is called encapsulation.Encapsulated class is also called Expert class  because it binds only related attributes and methods. You can say after encapsulation you get an expert class.

For example:

class Person:
    __name=""

    def setName(self,name):
        self.__name=name
        
    def getName(self):
        return self.__name

p1 = Person()
p1.setName("Rays")
print("Name is ",p1.getName())

Output:
Name is : Rays

Inheritance

Inheritance is a mechanism where a new class is derived from an exiting class. A class may inherit or resue the properties and methods of other class. A class derived from another class is called a subclass or child class. whereas the class from which a subclass is derived is called a super class or parent class.

Inheritance is a compile - time mechanism and shows static relationship between classes. A superclass can have any number of sub classes and  subclasses also have multiple parent classes. 

Type of Inheritance:

1. Single Inheritance
2. Multiple Inheritance
3. MultiLevel Inheritance
4. Hierarchical Inheritance
5. hybrid inheritance

Single Inheritance :

Single inheritance is contain single parent class and single child class.

For Example :

class Parent:
     def __init__(self):
        print("Hi i am parent class")

class Child(Parent):
    pass

c = Child()

Output:
Hi i am parent class

Multiple Inheritance :

Multiple Inheritance contain two parent class and one child class.

class P1:
    def m1(self):
      print("P1 Method")

class P2:
    def m1(self):
      print("P2 Method")

class C(P1,P2):
    pass

c=C()
c.m1()

Output:
P1 Method

MultiLevel Inheritance:

Multilevel Inheritance contain single parent class but the have multiple child class at same level

class P:
     def m1(self):
        print("Parent Method")

class C(P):
     def m2(self):
        print("Child Method")

class CC(C):
     def m3(self):
        print("Sub Child Method")

c=CC()
c.m1()
c.m2()
c.m3()

Output:
Parent Method
Child Method
Sub Child Method

Hierarchical Inheritance

Hierarchical Inheritance contain single parent class and the have two child class.

class P:
     def m1(self):
        print("Parent Method")

class C1(P):
    def m2(self):
        print("Child1 Method")

class C2(P):
    def m3(self):
        print("Child2 Method")

c1=C1()
c1.m1()
c1.m2()

c2=C2()
c2.m1()
c2.m3()

Output:
Parent Method
Child 1 Method


Parent Method
Child 2 Method

hybrid inheritance :

hybrid inheritance is combination of two inheritance.

class P:
    def __init__(self):
         print('P1 Parent')

class C1(P):
    def __init__(self):
        print('C1 Child')

class C2(P):
     def __init__(self):
        print('C2 Child')

class D(C1,C2):

    pass

d=D()

Output:
C1 Child

Polymorphism :

Polymorphism is the ability of an object to behave differently in different states. it is usually referred by "one message and different behavior " that means one method call may execute different implementation at run time  decide.

class Country:

    def capital(self):
        pass


    def language(self):
        
pass

    def type(self):
        pass

class India(
Country):
    def capital(self):
        print("New Delhi is the capital of India.")

    def language(self):
        
print("Hindi the primary language of India.")

    def type(self):
        print("India is a developing country.")

class USA(
Country):
    def capital(self):
        print("Washington, D.C. is the capital of the USA.")

    def language(self):
        print("English is the primary language of the USA.")

    def type(self):
        print("USA is a developed country.")

obj_ind = India()

obj_usa = USA()

for country in (obj_ind, obj_usa):

    country.capital()
    country.language()
Output:
New Delhi is the capital of India.
Hindi the primary language of India.
Washington, D.C. is the capital of the USA.
English is the primary language of the USA.

Abstraction :

Data abstraction and encapsulation are synonymous as data abstraction is achieved through encapsulation.

Abstraction is used to hide internal details and show only functionalities. Abstracting something means to give names to things, so that the name captures the basic idea of what a function or a whole program does.

For Example:

from abc import ABC, abstractmethod
class Shape(ABC):

    @abstractmethod
    def area(self):
        pass

class Circle(Shape):
    radius=2

    def area(self):
        return 3.14*self.radius*self.radius

obj = Circle()
print("Area of Circle = ",obj.area())

Output:
Area of Circle =12.56