Python Data Persistence object-oriented programming

Python Data Persistence – OOP

The object-oriented programming paradigm has emerged as a cornerstone of modern software development. Python too is a predominantly object-oriented language, although it supports classical procedural approach also. Python’s implementation of OOP is a little different from that of C++ and Java, and is in keeping with ‘Simple is better than Complex’ – one of the design principles of Python. Let us not go into much of the theory of object-oriented programming methodology and its advantages. Instead, let us dive straight into Python’s brand of OOP!

Everything in Python is an object. This statement has appeared more than once in previous chapters. What is an object though? Simply put, object is a piece of data that has a tangible representation in computer’s memory. Each object is characterized by attributes and behaviour as stipulated in a template definition called class. In Python, each instance of any data type is an object representing a certain class. Python’s built-in type ( ) function tells you to which class an object belongs to. (figure 4.1)

>>> num=1234
>>> type(num)
<class 'int'>
>>> complexnum=2+3j
>>> type(complexnum)
<class 'complex'>
>>> prices={ 'pen' :50, 'book' :200}
>>> type(prices)
<class 'diet'>
>>>

Each Python object also possesses an attribute__class__that returns class. (figure 4.2)

>>> num.__class__
<class 'int'>
>>> complexnum.__class__
<class 'complex'>
>>> prices.__class__
<class 'diet'>
>>>

Hence, it is clear that num is an object of int class, a complexion is an object of the complex class, and so on. As mentioned above, an object possesses attributes (also called data descriptors) and methods as defined in its respective class. For example, the complex class defines real and image attributes that return the real and imaginary parts of a complex number object. It also has conjugate () method returning a complex number with the imaginary part of the opposite sign, (figure 4.3)

>>> complexnum=2+3j
>>> #attr.ibutes
. . .
>>> complexnum.real
2.0
>>> complexnum.imag
3.0
>>> #method
. . .
>>> complexnum.conjugate()
(2-3j )

In the above example, real and imag are the instance attributes as their values will be different for each object of the complex class. Also, the conjugate 0 method is an instance method. A class can also have class-level attributes and methods which are shared by all objects. We shall soon come across their examples in this chapter.

Built-in data types in Python represent classes defined in the builtins module. This module gets loaded automatically every time when the interpreter starts. The class hierarchy starts with object class. The builtins module also defines Exception and built-in functions (many of which we have come across in previous chapters).

The following diagram rightly suggests that built-in classes (int, float, complex, bool, list, tuple, and diet) are inherited from the object class. Inheritance incidentally is one of the characteristic features of Object-Oriented Programming Methodology. The base attribute of each of these classes will confirm this.

Python’s built-in function library also has issubclass ( ) function to test if a certain class is inherited from another. We can use this function and confirm that all built-in classes are sub-classes of the object classes. Interestingly, class is also an object in Python. Another built-in function is±nstance() returns True if the first argument is an object of the second argument which has to be a class. By the way, type ( ) of any built-in class returns type which happens to be a metaclass of which all classes are objects, is itself a subclass of the object as its base class, (figure 4.4)

Python Data Presistence - OOP chapter 4 img 1

Following interpreter, activity shows that bool class is derived from int class, which is a subclass of object class and also an object of object class!

Example

>>> isinstance(int, object)
True
>>> issubclass(bool, int)
True
>>> int. bases
(<class 'object'>,)
>>> isinstance(int, object)
True

Each class also has access to another attribute__mro__(method resolution order) which can show the class hierarchy of inheritance. The bool class is inherited from int and int from the object.

Example

>>> bool.__mro__
(<class 'boo'>, <class 'int'>, <class 'object'>)

As mentioned above, type () on any built-in class returns type class which in turn is both a subclass and instance of the object class.

Example

>>> type(bool)
<class 'type'>
>>> type.__bases__
(<class 'object'>,)
>>> isinstance(type, object)
True
>>> issubclass(type, object)
True

Other important constituents of Python program such as functions or modules are also objects, as the following interpreter activity demonstrates:

Example

>>> #function from a module
. . .
>>> import math
>>> type(math.sqrt)
<class 'builtin_function_or_method'>
>>> #built-in function
. . .
>>> type(id)
cclass 'builtin_function_or_method'>
>>> #user defined function
. . .
>>> def hello( ):
... print ('Hello World')
. . .
>>> type(hello)
<class 'function'>
>>> #module is also an object
. . .
>>> type(math)
<class 'module'>

We have used the range ( ) function in connection with for loop. It actually returns a range object which belongs to the range class.

Example

>>> #range is also an object
. . .
>>> obj=range(10)
>>>type(obj)
<class 'range'>
>>> >>> range._bases__
(<class 'object'>,)