Object-Oriented Programming in Python : Part-1
Tags: python, oop, programming, codenewbie
Published: 2022-04-15 19:16:26

> Python is a fantastic programming language that allows you to use both functional and object-oriented programming paradigms.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nsreapfywdhmo5n1avnj.jpg)

Python programmers should be able to use fundamental object-oriented programming concepts, whether they are software developers, machine learning engineers, or something else.

All four core aspects of a generic OOP framework are supported by Python's object-oriented programming system:

1. Encapsulation 
2. Abstraction
3. Inheritance
4. Polymorphism

In this tutorial, we'll take a quick look at these features and get some practice with them.

## Object-Oriented Programming Concepts in Python

**What are Classes and Objects?**

Python, like every other object-oriented language, allows you to define classes to create objects. In-built Python classes are the most common data types in Python, such as strings, lists, dictionaries, and so on.

A class is a collection of instance variables and related methods that define a particular object type. You can think of a class as an object's blueprint or template. Attributes are the names given to the variables that make up a class.

A class instance with a defined set of properties is called an object. As a result, the same class can be used to construct as many objects as needed.

Let’s define a class named Book for a bookseller’s sales software.

```
class Book:
    def __init__(self, title, quantity, author, price):
        self.title = title
        self.quantity = quantity
        self.author = author
        self.price = price
```

The __init__ special method, also known as a Constructor, is used to initialize the Book class with attributes such as title, quantity, author, and price.

In Python, built-in classes are named in lower case, but user-defined classes are named in Camel or Snake case, with the first letter capitalized.

This class can be instantiated to any number of objects. Three books are instantiated in the following example code:

```
book1 = Book('Book 1', 12, 'Author 1', 120)
book2 = Book('Book 2', 18, 'Author 2', 220)
book3 = Book('Book 3', 28, 'Author 3', 320)
```

book1, book2 and book3 are distinct objects of the class Book. The term self in the attributes refers to the corresponding instances (objects).

```
 print(book1)
 print(book2)
 print(book3)
```

**Output:**

```
<__main__.Book object at 0x00000156EE59A9D0>
<__main__.Book object at 0x00000156EE59A8B0>
<__main__.Book object at 0x00000156EE59ADF0>
```

The class and memory location of the objects are printed when they are printed. We can't expect them to provide specific information on the qualities, such as the title, author name, and so on. But we can use a specific method called __repr__ to do this.

In Python, a special method is a defined function that starts and ends with two underscores and is invoked automatically when certain conditions are met.


```
class Book:
    def __init__(self, title, quantity, author, price):
        self.title = title
        self.quantity = quantity
        self.author = author
        self.price = price

    def __repr__(self):
        return f"Book: {self.title}, Quantity: {self.quantity}, Author: {self.author}, Price: {self.price}"


book1 = Book('Book 1', 12, 'Author 1', 120)
book2 = Book('Book 2', 18, 'Author 2', 220)
book3 = Book('Book 3', 28, 'Author 3', 320)

print(book1)
print(book2)
print(book3)
```

**Output:**

```
Book: Book 1, Quantity: 12, Author: Author 1, Price: 120
Book: Book 2, Quantity: 18, Author: Author 2, Price: 220
Book: Book 3, Quantity: 28, Author: Author 3, Price: 320
```

**1. Encapsulation**

Encapsulation is the process of preventing clients from accessing certain properties, which can only be accessed through specific methods.

Private attributes are inaccessible attributes, and information hiding is the process of making particular attributes private. You use two underscores to declare private characteristics.

Let's introduce a private attribute called __discount in the Book class.

```
class Book:
    def __init__(self, title, quantity, author, price):
        self.title = title
        self.quantity = quantity
        self.author = author
        self.price = price
        self.__discount = 0.10

    def __repr__(self):
        return f"Book: {self.title}, Quantity: {self.quantity}, Author: {self.author}, Price: {self.price}"


book1 = Book('Book 1', 12, 'Author 1', 120)

print(book1.title)
print(book1.quantity)
print(book1.author)
print(book1.price)
print(book1.__discount)
```

**Output:**

```
Book 1
12
Author 1
120
Traceback (most recent call last):
  File "C:\Users\ashut\Desktop\Test\hello\test.py", line 19, in <module>
    print(book1.__discount)
AttributeError: 'Book' object has no attribute '__discount'
```

We can see that all the attributes are printed except the private attribute __discount. You use getter and setter methods to access private attributes.

We make the price property private in the following code example, and we use a setter method to assign the discount attribute and a getter function to get the price attribute.


```
class Book:
    def __init__(self, title, quantity, author, price):
        self.title = title
        self.quantity = quantity
        self.author = author
        self.__price = price
        self.__discount = None

    def set_discount(self, discount):
        self.__discount = discount

    def get_price(self):
        if self.__discount:
            return self.__price * (1-self.__discount)
        return self.__price

    def __repr__(self):
        return f"Book: {self.title}, Quantity: {self.quantity}, Author: {self.author}, Price: {self.get_price()}"
```

This time we'll create two objects, one for the purchase of single book and another for the purchase of books in bulk quantity. While purchasing books in bulk quantity, we get a discount of 20%, so we'll use the set_discount() method to set the discount to 20% in that case.


```
single_book = Book('Two States', 1, 'Chetan Bhagat', 200)

bulk_books = Book('Two States', 25, 'Chetan Bhagat', 200)
bulk_books.set_discount(0.20)

print(single_book.get_price())
print(bulk_books.get_price())
print(single_book)
print(bulk_books)
```

**Output:**

```
200
160.0
Book: Two States, Quantity: 1, Author: Chetan Bhagat, Price: 200
Book: Two States, Quantity: 25, Author: Chetan Bhagat, Price: 160.0
```

**2. Inheritance**

Inheritance is regarded as the most significant characteristics of OOP. A class's ability to inherit methods and/or characteristics from another class is known as inheritance.

The subclass or child class is the class that inherits. The superclass or parent class is the class from which methods and/or attributes are inherited.

Two new classes have been added to our bookseller's sales software: a Novel class and Academic class.

We can see that regardless of whether a book is classified as novel or academic, it may have some similar attributes like title and author, as well as common methods like get_price() and set_discount(). Rewriting all that code for each new class is a waste of time, effort, and memory.

```
class Book:
    def __init__(self, title, quantity, author, price):
        self.title = title
        self.quantity = quantity
        self.author = author
        self.__price = price
        self.__discount = None

    def set_discount(self, discount):
        self.__discount = discount

    def get_price(self):
        if self.__discount:
            return self.__price * (1-self.__discount)
        return self.__price

    def __repr__(self):
        return f"Book: {self.title}, Quantity: {self.quantity}, Author: {self.author}, Price: {self.get_price()}"


class Novel(Book):
    def __init__(self, title, quantity, author, price, pages):
        super().__init__(title, quantity, author, price)
        self.pages = pages


class Academic(Book):
    def __init__(self, title, quantity, author, price, branch):
        super().__init__(title, quantity, author, price)
        self.branch = branch
```

Let's create objects for these classes to visualize them.

```
novel1 = Novel('Two States', 20, 'Chetan Bhagat', 200, 187)
novel1.set_discount(0.20)

academic1 = Academic('Python Foundations', 12, 'PSF', 655, 'IT')

print(novel1)
print(academic1)
```

**Output:**

```
Book: Two States, Quantity: 20, Author: Chetan Bhagat, Price: 160.0
Book: Python Foundations, Quantity: 12, Author: PSF, Price: 655
```


[Object-Oriented Programming in Python : Part-2](https://dev.to/sandeepk27/object-oriented-programming-in-python-part-2-5c1j)

[Top Websites to learn Python](https://dev.to/sandeepk27/top-websites-to-learn-python-for-free-1j1l)

[How to install python in windows 10](https://dev.to/sandeepk27/how-to-install-python-310-2dik)

[Python cheat sheet](https://dev.to/sandeepk27/python-cheat-sheet-for-beginners-part-1-5baj)

[Best IDE's for Python](https://dev.to/sandeepk27/best-ides-for-python-362k)