Object Oriented Programming
Chapter 2 - Concept of Object Oriented Programming
Object oriented programming – As the name suggests uses objects in programming. Object oriented programming aims to implement real world entities like inheritance, hiding, polymorphism etc in programming. The main aim of OOP is to bind together the data and the functions that operates on them so that no other part of code can access this data except that function.
Let us learn about different characteristics of an Object Oriented Programming language: 1. Objects 2. Classes 3. Encapsulation 4. Abstraction 5. Polymorphism 6. Inheritance
Object
Object is an entity that has state and behavior. It may be anything. It may be physical and logical. For example: mouse, keyboard, chair, table, pen etc.
Everything in Python is an object, and almost everything has attributes and methods. All functions have a built-in attribute
__doc__
, which returns the doc string defined in the function source code.
Class
Class can be defined as a collection of objects. It is a logical entity that has some specific attributes and methods. For example: if you have an employee class then it should contain an attribute and method i.e. an email id, name, age, salary etc.
Namespace
In Python, the namespace is a fundamental idea to structure and organize the code, especially more useful in large projects.
Before getting on to namespaces, first, let’s understand what Python means by a name.
A name in Python is just a way to access a variable like in any other languages. However, Python is more flexible when it comes to the variable declaration. You can declare a variable by just assigning a name to it.
You can use names to reference values.
We can get the address (in RAM) of some object through the built-in function, id()
You can also assign a name and then reuse it. Check the below example; it is alright for a name to point to different values.
A namespace is a simple system to control the names in a program . It ensures that names are unique and won’t lead to any conflict.
Also, add to your knowledge that Python implements namespaces in the form of dictionaries. It maintains a name-to-object mapping where names act as keys and the objects as values. Multiple namespaces may have the same name but pointing to a different variable.
There are different tyes of namespaces:
Local namespace
Global namespace
Built-In namespaces
Local Namespace
This namespace covers the local names inside a function. Python creates this namespace for every function called in a program. It remains active until the function returns.
Global Namespace
This namespace covers the names from various imported modules used in a project. Python creates this namespace for every module included in your program. It’ll last until the program ends.
Built-in Namespace
This namespace covers the built-in functions and built-in exception names. Python creates it as the interpreter starts and keeps it until you exit.
Scope in Functions
Namespaces make our programs immune from name conflicts. However, it doesn’t give us a free ride to use a variable name anywhere we want. Python restricts names to be bound by specific rules known as a scope. The scope determines the parts of the program where you could use that name without any prefix
Scope is the portion of the program from where a namespace can be accessed directly without any prefix.
At any given moment, there are at least three nested scopes.
Scope of the current function which has local names
Scope of the module which has global names
Outermost scope which has built-in names
Here, the variable a is in the global namespace. Variable b is in the local namespace of outer_function() and c is in the nested local namespace of inner_function().
When we are in inner_function(), c is local to us, b is nonlocal and a is global. We can read as well as assign new values to c but can only read b and a from inner_function()
In this program, three different variables a are defined in separate namespaces and accessed accordingly.
Here, all reference and assignment are to the global a due to the use of keyword global.
LEGB Rule
In Python, the LEGB rule is used to decide the order in which the namespaces are to be searched for scope resolution. The scopes are listed below in terms of hierarchy(highest to lowest/narrowest to broadest):
Local(L): Defined inside function/class
Enclosed(E): Defined inside enclosing functions(Nested function concept)
Global(G): Defined at the uppermost level
Built-in(B): Reserved names in Python builtin modules
Local Scope: Local scope refers to variables defined in current function.Always, a function will first look up for a variable name in its local scope. Only if it does not find it there, the outer scopes are checked.
On running the above program, the execution of the inner function prints the value of its local(highest priority in LEGB rule) variable pi because it is defined and available in the local scope.
Local and Global Scopes : If a variable is not defined in local scope, then, it is checked for in the higher scope, in this case, the global scope.
Local, Enclosed and Global Scopes :
For the enclosed scope, we need to define an outer function enclosing the inner function, comment out the local pi variable of inner function and refer to pi using the nonlocal keyword.
When outer() is executed, inner() and consequently the print functions are executed, which print the value the enclosed pi variable. The statement in line 10 looks for variable in local scope of inner, but does not find it there. Since pi is referred with the nonlocal keyword, it means that pi needs to be accessed from the outer function(i.e the outer scope).
Local,Enclosed,Global and Built-in Scopes : The final check can be done by importing pi from math module and commenting the global, enclosed and local pi variables as shown below:
Since, pi is not defined in either local, enclosed or global scope, the built-in scope is looked up i.e the pi value imported from math module. Since the program is able to find the value of pi in the outermost scope, the following output is obtained.
Classes and Objects
2.1 Class
Class can be defined as a collection of objects. It is a logical entity that has some specific attributes and methods. For example: if you have an employee class then it should contain an attribute and method i.e. an email id, name, age, salary etc.
2.2 Object
Object is an entity that has state and behavior. It may be anything. It may be physical and logical. For example: mouse, keyboard, chair, table, pen etc.
Everything in Python is an object, and almost everything has attributes and methods. All functions have a built-in attribute
__doc__
, which returns the doc string defined in the function source code.
Creating an Object
We saw that the class object could be used to access different attributes.
It can also be used to create new object instances (instantiation) of that class. The procedure to create an object is similar to a function call.
Accessing Object Variables
To access the variable inside of the newly created object "myobjectx" you would do the following:
Accessing Objects methods
Objects can also contain methods. Methods in objects are functions that belongs to the object.
Let us create a method in the Person class:
Delete Objects
You can delete objects by using the del keyword:
Delete Object properties
Delete the age property from the p1 object:
2.3 Defining a class
Like function definitions begin with the keyword def, in Python, we define a class using the keyword class.
The first string is called docstring and has a brief description about the class. Although not mandatory, this is recommended.
Here is a simple class definition.
A class creates a new local namespace where all its attributes are defined. Attributes may be data or functions.
As soon as we define a class, a new class object is created with the same name. This class object allows us to access the different attributes as well as to instantiate new objects of that class.
2.4 Constructors in Python using _init_
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.
The _init_() function is called automatically every time the class is being used to create a new object.
Use the _init_() function to assign values to object properties, or other operations that are necessary to do when the object is being created:
self
So we've come across the term 'self' in our function parameters inside classes in the previous cells.
The self parameter is a reference to the class itself, 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:
2.5 Class attributes vs Instance attributes
Class attributes, as the name suggests, belong to the class itself. These attributes will be shared by all the instances. Such attributes are defined in the class body part, usually at the top, for legibility.
Class variables are variables that are being shared with all instances (objects) which were created using that particular class. So when accessed a class variable from any instance, the value will be same.
Instance variables on the other hand are variables, which all instances keep for themselves (i.e a particular object owns its instance variables). So typically values of instance variables differ from instance to instance.
Class variables allow us to define variables upon constructing the class. These variables and their associated values are then accessible to each instance of the class.
The output we receive is made up of the values of the variables that we initialized for the object instance of new_shark.
Here, we have made use of both class and instance variables in two objects of the Shark class, sammy and stevie.
2.6 Adding methods dynamically in Python
Given the dynamic nature of Python you can do many things in runtime, like add methods dynamically to an object or class.
Here is the simplest way, adding a method to and object:
Note that play is just a function, it doesn't receive self. There is no way to p knows that it's a method.
2.7 Built-in attributes
Every Python class keeps the following built-in attributes and they can be accessed using dot operator like any other attribute:
_dict_ : It gives the dictionary containing the class's namespace.
_doc_ : It returns the class's documentation string(also called docstring) and if no docstring is defined for a class this built in attribute returns None
_name_: It gives the class name.
_module: It specifies the module name in which the class is defined. This attribute is called "\main_" in interactive mode.
_bases_ : It gives a possibly empty tuple containing the base classes, in the order of their occurrence in the base class list.
2.8 Static Methods
Static methods in Python are extremely similar to python class level methods, the difference being that a static method is bound to a class rather than the objects for that class.
This means that a static method can be called without an object for that class. This also means that static methods cannot modify the state of an object as they are not bound to it. Let’s see how we can create static methods in Python.
We can create a static method using the @staticmethod keyword
2.9 Garbage Collection
Python automatically allocates and de-allocates memory. The user does not have to preallocate or deallocate memory by hand as one has to when using dynamic memory allocation in languages such as C or C++. Python uses two strategies for memory allocation-reference counting and automatic garbage collection.
1. Reference Counting
Prior to Python version 2.0, the Python interpreter only used reference counting for memory managementReference counting works by counting the number of times an object is referenced by other objects in the system. Python's garbage collector runs during program execution and is triggered when an object's reference count reaches zero.
2. Automatic Garbage Collection
In this case garbage collection is a scheduled activity. Python schedules garbage collection based upon a threshold of object allocations and object de-allocations. Python deletes the objects which are not required, may it be built-in types or class instances, through the process named garbage collection. When the number of allocations minus the number of de-allocations are greater than the threshold number, the garbage collector is run and the unused block of memory is reclaimed. One can inspect the threshold for new objects by loading the gc module and asking for garbage collection thresholds. Automatic garbage collection will not run if your Python device is running out of memory. In such case, your application will throw exceptions, which must be handled otherwise your application will crash. Also, the automatic garbage collection occurs more for the number of free objects than the size of objects.
2.10 Some other object oriented programming concepts
Data Abstraction
Data abstraction and encapsulation both are often used as synonyms. Both are nearly synonym because 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 core of what a function or a whole program does.
Polymorphism
Polymorphism is made by two words "poly" and "morphs". Poly means many and Morphs means form, shape. It defines that one task can be performed in different ways. For example: You have a class animal and all animals talk. But they talk differently. Here, the "talk" behavior is polymorphic in the sense and totally depends on the animal. So, the abstract "animal" concept does not actually "talk", but specific animals (like dogs and cats) have a concrete implementation of the action "talk".
Last updated