Objects and Object-Oriented Programming - Python
Tags: oops, python, class
Published: 2023-02-16 06:35:05

An object is an instance of a class in python. A class is like a blueprint for the instances. Objects have member variables and member functions which are known as attributes and methods in python. The main aim of OOP is the encapsulation of data and functions that work on those data. 

```python
class ClassNameCamelCase(AnotherClass):
    # class def
```

There are two main relationships in OOP, they are composition and inheritance. Composition is where an object contains another object and inheritance is where one class builds on top of another class.

## Constructors, Initializer, and Finalizer

A class has a built-in initializer `__init__()` method to define the initial values of the instance attributes and it should not have a return in it.

The constructor in python can be defined by using `__new__()`. The constructor allocates memory for objects and is the only function called before creating the instance. For the constructor, the class is passed as an argument instead of the self like other class functions. In most cases, constructors are not defined.

The finalizer `__del__()` is called when the instance is at the end of the scope and its lifetime is complete. The garbage collector is run when the finalizer is run. Post-processing on instances depends upon the python implementation and instance attributes may not be available inside the finalizer at all times.

## Attributes - Python

There are no private or public labels in python to control the access of the instance attributes. A normal attribute has no preceding underscores and it is meant to be accessed using the instance name and dot operator.

The attributes that are not meant to be accessed by the public are preceded with an underscore like `_random_name`. Even though they can be accessed by using the dot operator, it is there to say that they should not be accessed.

Using name mangling for an attribute or member function can prevent it from being used by a dot operator. It can still be accessed using a class name surrounded by an underscore like `obj_instance._ClassName___mangledname`.

Class attributes are attributes that are available to all instances. It exists for the class and not for every instance. It is usually defined before all member functions inside the class definition.

## Methods - Python

Instance methods are methods that can access the instance attributes and class attributes. These are normal functions that work on instance attributes.

Class methods are methods that only work on class attributes and are declared as such using the `@classmethod` decorator on top of the function. This can be called from both the class and instance.

Static methods are methods that can't access both instance and class attributes. A static method is there to add any function or business logic such as an algorithm that is being used by an instance of a class.

Property methods are methods to provide neat getters and setters in Python. A property method for the attribute members can be defined by using the below code.

```python
property(fget=None, fset=None, fdel=None, doc=None)
```

fget argument is for the function that returns the attribute value, fset is for the function assigning the value, fdel is for the function that runs when an instance is deleted, and the doc is for docstring. Property methods can also be set using decorators as below.

```python
random_name = property()

@random_name.getter
def randon_fn(self):

@random_name.setter
def randon_fn(self):

@random_name.deleter
def randon_fn(self):
```

Special methods or dunder(double underscore) methods add special functionality such as `__str__()` is used when the object is converted to a string. There are many different dunder methods in python each having its use case.

## Inheritance

Inheritance is a concept that allows the creation of a class that shares a common code with another class. In an inherited class some of the attributes and methods are overridden and additional attributes and methods are added.

```python
class InheritedClass(ParentClass):
    #class definition
```

A class can also inherit from multiple class but, resolution for functions must be made whenever there is conflicting functions or attributes are there in parent classes. By default, python uses C3 Method Resolution Order to resolve attribute and method lookup conflicts when a class has multiple inheritance or multilevel inheritance. If a class has a local attribute or method it comes first. In other cases, the order is followed as per the inheritance graph.

Mixin is a class that is inherited by different unrelated classes that requires common functionality.

## Abstract class and Virtual subclasses

An abstract class is a class that only has methods without any definition. Any class that inherits an abstract class needs to implement all the methods in the abstract base class. It helps to provide a structure for all inheriting classes to conform to a structure.

Virtual subclasses are classes that implement the interface defined by the abstract base class without explicitly inheriting it. It is mainly used to decouple the interface from the class hierarchy and make it easier to extend. To register a class as a virtual subclass of an abstract class register method is used.

```python
RandAbstractClass.register(VirtualSubClass)
```