Advanced Classes
Design Structure is the philosophy of creating a structure following the best design elements working cohesively to create a structurally sound system. This philosophy is borrowed from engineering disciples.
We all have witnessed numerous examples of structurally unstable bridges that seem to collapse during development or after launch. One of the primary reasons behind bridge collapse is design and structural deficiencies. On the other hand, well-constructed structures such as the Wall of Japan to protect from tsunamis demonstrate the gravity of following sound design principles.
Software engineering is considered to be a branch of engineering. Hence, thinking about structures and elements helps us engineer a cohesive product with all its components working together, resulting in a stable and robust end-product. Therefore, following a proper design structure is integral for the development of the highest quality of software.
Object-Oriented Programming or (OOP) for short, is a programming paradigm that follows the concept of objects. An object can store both the data and methods that can act upon it. For better understanding, let us take an example of a motorcycle.
In a motorcycle, there are different components such as:
There are, of course, a lot more components; I've mentioned just a few.
Let us segregate methods and attributes from the above information.
Attributes
Methods
In this example, the bike consists of various data points, such as the top speed and the accelerator, which we can use to reach our desired velocity. The top speed is our data, and using the accelerator is our method.
As the above example demonstrates, Object-Oriented programming allows for modeling our application based on real-world objects. It enables the developers to provide an abstraction to develop well-maintainable, robust software.
In Python, classes can be thought of as templates. Classes provide all the capabilities of the Object-Oriented programming paradigm, which stores both the code(methods) and the data(attributes/property). They allow for defining the methods(actions that can be performed) and the data(on whom the methods will operate on).
They are used to allow the programmer to develop the application using the Object-Oriented Programming Paradigm, resulting in a maintainable, small, clear, and concise codebase.
Let us write a simple program to display vehicle information, demonstrating the difference between Class and Non-Class Implementation.
We will be creating three vehicles named Ford Fiesta, Toyota Corolla, Honda Civic and store the following information and methods:
The above two examples perfectly demonstrate the power of object-oriented programming by providing very high levels of abstraction, resulting in a cleaner, manageable codebase.
The non-class implementation has many redundant statements, is challenging to maintain and understand, and spans 89 lines. It would be almost impossible to scale to hundreds or even thousands of vehicles without causing management and documentation issues.
However, the class-based implementation is concise, shorter, easier to understand and maintain, omits redundancy, and spans only 36 lines. It is also shorter by 60%.
The following section will discuss using the class keyword to declare a class in Python.
In Python, you can declare a class using the class keyword, followed by the class name. Below is an example.
class MyClass:
statement 1
statement 2
statement 3
statement ...
statement ...
statement N
According to Python's PEP-8(Style Guide for Python), you must start each word in the class name as a Capital letter and not use separate words with an underscore. This style is also known as the camel case.
Here are some examples of correct naming conventions:
Here are some examples of incorrect naming conventions or invalid syntax:
As stated, Object-Oriented Principles allow for storing both the methods(actions) and properties(data). You can define the following inside of a class:
Instance members are members that belong to a particular copy or instance of a class. Below is an example to help understand them:
| Mr. Neo, 40 |
| Mr. Anderson, 50 |
Let us go through every statement and understand the structure.
#1:
This statement informs the Python interpreter that a class is to be declared.
#2:
This statement defines an instance method of the class Person that takes three arguments:
#3:
These statements define the instance variable's name and age and assign the value passed using the method parameters name and age. It cannot be apparent to understand initially. But, please follow through.
In Python, we declare instance variables by using the self.<instance_variable_name> notation.
Therefore, to declare any instance variable, we have to refer to it using self.
#4:
These statements define the instance method get_info(). To declare an instance method, one must always pass self as the first argument. This function returns a formatted string containing the name and the age.
#5:
This statement defines neo as an instance of the class Person. Now, the values passed refer to the instance method __init__. As you can see below, __init__ method accepts name and age.
Python implicitly passes the self argument. Hence, when
#6:
This method calls the instance method get_info that returns the name and age of the instance neo.
Here name and age are instance variables, and get_info is the instance method .
To define an instance variable, refer to them using self. Here is an example:
To define an instance method, always accept the first argument self. Here is an example:
Class Members are like instance members, except they belong to the entire class. Below is an example:
In the above example:
#1:
This statement informs Python that a class is being declared named Constants.
#2:
These statements declare the class variables pi and speed_of_light.
#3:
@classmethod is a decorator. Decorators are used to pass additional information or metadata to Python. To inform Python that get_pi is a class method, we have to use the @classmethod decorator.
The get_pi method accepts a reference to the class itself using the cls parameter. It should always be the first argument and must always be defined as cls.
Finally, this method returns the value of the class variable pi using cls.<class_variable> notation.
We have discussed instance and class methods. However, Python allows for an additional method type: static method.
Static methods are methods that cannot have access to instance variables. However, it allows for indirect access to class members using the class name instead of cls. Below is an example:
3.14
According to PEP-8(Style Guide for Python), you must define all members in lowercase, with each word separated by an underscore. It applies to both variables and methods.
Below is an example of the correct convention:
name, my_bank_balance, my_age, pi, get_pi, get_name, get_bank_balance
Since Python is an interpreted language, it allows for runtime modification of code. One of the things Python allows is deleting members using the del keyword.
To delete a member, use the following syntax:
del <class_name>.<member_name>
Below is an example:
Hello, from class Person
type object 'Person' has no attribute 'msg'
Mr. X
'Person' object has no attribute 'name'
The Object-Oriented Programming Paradigm allows for limiting the accessibility of members. Python provides two access modifiers:
Public access means that the members are available outside the class they are part of. Below is an example of a public member.
Hello, World
Bye
The member say_bye and msg are public members.
By default, all members are public.
Private members are "visible" inside the class that defines them. Private members must begin with a double underscore(__).
Below is an example:
Secret message from Msg
In the previous section, we learned about the public and private access modifiers. However, in this section, we will discuss their difference in-depth as well as discuss their purpose.
The public access modifier is used when we want a method or a property/attribute to be accessible from outside the scope of the class. It is the default mode.
The private access modifier is used to protect the method/property/attribute from being accessible from outside the class's scope. The marked methods/property/attribute is only available from inside the scope of the class it is defined within.
We looked at the __init__ method to initialize out instances in the earlier section. Let us take an example to help understand constructors:
In the above example, during the instantiation, we are accepting the following:
However, what if we wanted to create a record for a new person in the country who does not have an address or sin_no. We would not be able to as address and sin_no are mandatory arguments and do not have a default value. To address such instances, Python allows for providing default values. Hence, we would define a constructor as such:
Complete Example
Mr. Bean, 50, +16578767651, 123 Lost Street, 786-897-657
Mr. Johnson, 45, N/A, Bulk Street, N/A
In the above sections, we have observed the power of abstraction that the Object-Oriented Programming paradigm(OOP) provides. It allows for re-using of code and achieving maintainable codebases. One of the highlights of OOP is that it allows for deriving of features and properties of one class into another. One of the most remarkable real-world examples is Evolution. It allows for the borrowing of elements from different categories of organisms.
In the above illustration, the Dog and the Cat borrow a standard set of features from the class Animal. It allows for inheriting all the features of the class Animal into the class Dog and Cat. This feature is called inheritance. In Python, you can only inherit a single class at once. However, subsequent inheritance of classes is allowed.
The class inheriting another class is referred to as the child class. The inherited class is referred to as the parent class.
To inherit a class, use the following syntax:
class ChildClass(<parent_class_name>):
statement 1
statement 2
statement 3
statement ...
statement ...
statement N
Below is an example:
Eating my Cookies!
Eating my Fish!
Woof Woof!
If you bark again, I'm going to slap you with my paws!
Let us break down each statement to help understand the anatomy of this program.
#1:
#2:
#3:
#4:
#5:
#6:
#7:
#8:
#9:
#10:
#11:
#12:
#13:
#14:
#15:
#16:
#17:
#18:
#19:
We have learned that the object-oriented paradigm allows for inheriting properties and methods from another class. However, there are certain instances where we might need to refer to the parent class and access its value. To refer to the parent class, Python provides the super keyword.
Below are some examples of using the super keyword:
To refer to the superclass method:
8
One thing to always remember is that super can only refer to instance members of the parent class.
In this chapter, we learned about the significance of real-world modeling of problems, object-oriented programming paradigm, the difference between class and non-class implementation, naming conventions, instance members, class members, class members, static method, deletion of members, access modifiers, and inheritance. OOP will help you write large, scalable, and maintainable software effortlessly.