Lecture 8
Lecture 8
Lecture 8
Omar Yahya
Lecture 8
Abstract Methods
Abstract methods are methods that are declared in a base class but not defined (contain no
implementation). They act as placeholders that must be overridden by subclasses that inherit from
the base class. Abstract methods enforce a consistent interface for subclasses and ensure that they
provide their own implementation of the method.
A class that contains one or more abstract methods is called an abstract class. We use an abstract
class while we are designing large functional units or when we want to provide a common interface
for different implementations of a component.
To create an abstract method in Python, you need to import the abstract base class (ABC) module
and use the @abstractmethod decorator.
Abstract methods in object-oriented programming (OOP) have great benefits, especially when
working on large and complex projects.
class Polygon(ABC):
1
OOP in Python Eng. Omar Yahya
@abstractmethod
def no_of_sides(self):
pass
class Triangle(Polygon):
class Pentagon(Polygon):
class Hexagon(Polygon):
class Quadrilateral(Polygon):
# Driver code
R = Triangle()
R.no_of_sides() # Output=> I have 3 sides
K = Quadrilateral()
K.no_of_sides() # Output=> I have 4 sides
2
OOP in Python Eng. Omar Yahya
R = Pentagon()
R.no_of_sides() # Output=> I have 5 sides
K = Hexagon()
K.no_of_sides() # Output=> I have 6 sides
This code defines an abstract base class called “Polygon” using the ABC (Abstract Base Class)
module in Python. The “Polygon” class has an abstract method called “no_of_sides” that
needs to be implemented by its subclasses.
There are four subclasses of “Polygon” defined: “Triangle,” “Pentagon,” “Hexagon,” and
“Quadrilateral.” Each of these subclasses overrides the “no_of_sides” method and provides
its own implementation by printing the number of sides it has.
In the driver code, instances of each subclass are created, and the “no_of_sides” method is
called on each instance to display the number of sides specific to that shape.
3. Encouraging Scalability
In large systems, you need to create a system that can be easily expanded. By using abstract classes
and abstract methods, you can design a flexible system that can be expanded by adding more
subclasses later without having to significantly modify the existing code.
3
OOP in Python Eng. Omar Yahya
Benefit: Makes it easier to add new features or new types of objects in the future without affecting
the existing system.
4. Enhance Reusability
Abstract classes can be used as a basis for designing multiple objects that share some basic
behavior but differ in detail. This enhances code reusability and allows new solutions to be created
based on old abstract classes.
Benefit: Reduce code duplication and increase maintenance and development efficiency.
7. Improved Maintainability
By unifying and separating design and implementation, it is easier for programmers to understand
how the system works and maintain it. Any change to the system can be made more organized and
without having to examine every piece of code.
Benefit: Reduced errors in future modifications and improved maintenance efficiency.
8. Flexibility
Abstract methods provide a great deal of flexibility to developers, as they can focus on the overall
structure and think about the design of the abstract class first, and then leave the implementation
to the details of each subclass. This makes the system more dynamic and adaptable to new
requirements.
Benefit: Enables modification and addition to the system without disrupting the underlying
structures.
4
OOP in Python Eng. Omar Yahya
9. Facilitating Teamwork
In large programming teams, where multiple programmers work on different parts of a project,
abstract methods set clear standards that everyone can follow. This allows developers to work on
implementing different parts of the program without having to know the intricacies of other parts.
Benefit: Facilitating collaboration between team members and ensuring that the resulting code is
compatible and consistent.
2. Plugin Architecture
Abstract methods are useful when creating a plugin architecture where plugins need to implement
a specific interface.
3. Domain Modeling
Abstract methods are useful when modeling complex domains and ensuring that certain methods
are implemented by all classes in the domain.
5
OOP in Python Eng. Omar Yahya
These systems are used to manage all aspects of business operations in large companies such as
finance, human resources, manufacturing, and sales. Due to the complexity and multi-functionality
of these systems, abstract classes are used to organize and implement the different modules in a
uniform manner.
2. E-commerce Platforms
Examples: Amazon, eBay, Alibaba
These systems require a complex architecture to handle millions of users and sellers, as well as
purchase orders and shipments. Abstract classes are used to organize processes such as order
processing, payment, inventory management, and customer service.
5. Banking Systems
Examples: Bank account management systems, credit cards, money transfers
These systems need to handle sensitive data and provide complex services in a uniform and secure
manner. Abstract classes are used to ensure that different banking operations such as payment
processing, account management, and identity verification follow the same structural principles.
6
OOP in Python Eng. Omar Yahya
__name__ Variable
__name__ in Python is a special magic variable that is automatically defined when a Python file
is executed. This variable depends on the context in which the file is being run, and determines
how the program will behave. If the file is run directly as a standalone program, __name__ will
take the value "__main__". However, if this file is imported into another program as a module, the
value of __name__ will be the name of the imported file or module, without the .py extension.
This behavior allows programmers to control the execution of code based on how the file is called.
When writing a Python file, the intent may be to run it directly to execute a specific program, or
to use it as part of another program. This is where __name__ comes in, which serves as a clue to
the context in which the code is being run. Using the conditional statement if __name__ ==
"__main__", a programmer can write specific code that will only execute when the file is run as
the main program, and not when it is imported into another file. This gives programmers the ability
to have their files contain multiple functions; it could be a file that is run directly, or a module that
can be imported and its components used elsewhere without having to execute code that is of no
use when the file is imported.
How is it used?
__name__ is mainly used in Python files to check whether the file is being run as the main program
or imported as part of another program.
if __name__ == "__main__":
# Code that only runs if the file is run
directly.
A. When running the file directly:
If you run a Python file directly from the command line or the development environment, Python
will assign the variable __name__ the value "__main__". This way, the file can determine
whether some code (such as main functions or performing some action) should be run or not.
B. When importing the file as part of a module:
If you import the file in another file using import, Python will not assign the variable __name__
the value "__main__", but will give it the file name without the .py extension. This allows you
to write reusable modules without running special code on import.
7
OOP in Python Eng. Omar Yahya
Let's take an example to illustrate this. Let's say you have a file that contains functions that perform
certain tasks, such as calculations or data manipulation. In this case, you may need to write some
code to test these functions when developing the file, but you don't want this code to be executed
when the file is imported as a module into another program. This is where __name__ comes in.
You can put these test or executable codes under the conditional statement if __name__ ==
"__main__", which ensures that they will only be executed if the file is run directly.
The biggest advantage of this approach is that it separates the execution logic from the module
logic. The file can be an independent module that can be imported and reused in many other
projects without running code that is not necessary when it is imported. It also allows programmers
to avoid problems that may occur when trying to run unnecessary or test code inside a file that is
imported as a module.
For example, if you have a file that contains a function to greet the user, and you want this function
to greet the user only when the file is run directly and not when it is imported, you can use
__name__ to control the behavior of the program. When the file is run directly, the code is
executed, but when it is imported, the underlying code for the greeting is not executed, and the file
is only available for use as part of a larger program. In this way, __name__ is a powerful and
flexible tool that helps Python programmers organize their code and ensure that unnecessary code
is not executed when importing files as modules, while at the same time enabling them to execute
necessary code when running the file as a standalone program.
Main Function
In Python, there is no built-in main() function like in some other programming languages like
C++ or Java, where there is a fixed starting point for the program. However, in Python, you can
define a function called main() and use it as the starting point for your program when needed,
along with the conditional statement if __name__ == "__main__".
if __name__ == "__main__":
main()
Why do we use main() with if __name__ == "__main__"?
The reason for using this approach is:
• Code organization: Putting the main code in the main() function makes the code more
organized and easier to understand.
8
OOP in Python Eng. Omar Yahya
• Reuse: If you import the file into another program, the code inside if __name__ ==
"__main__" will not be executed. Thus, you ensure that the main() function is executed
only when the file is run directly.
• Maintenance improvement: When you need to modify the code, you will find that
separating the functions inside the main() function makes the program easier to work with.
Example 2:
def main():
print("Hello, this is the main function.")
# Put here any code you want to run when the program
starts.
if __name__ == "__main__":
main()
When is using main() useful?
• When writing large programs: If you are working on a large project with a lot of code,
breaking the program into multiple functions including a main() function helps organize
the program and makes it easier to maintain.
• When writing importable modules: If you intend to use the same file as a standalone
program and also as an import module, using main() you can control whether the code is
executed when it is imported.
Programmers who use the main() function in Python, with the statement if __name__ ==
"__main__", benefit from the code organization and pattern similar to traditional languages like
Java and C++, where the main() function is the fixed starting point of the program.
9
OOP in Python Eng. Omar Yahya
Example 3:
class MenuValidator:
def __init__(self, valid_options):
# Store the valid options (e.g., 'A', 'B', 'C', 'D')
self.valid_options = valid_options
# Example usage
def main():
# Create an instance of the MenuValidator class with valid
options
validator = MenuValidator(valid_options=['A', 'B', 'C',
'D'])
10
OOP in Python Eng. Omar Yahya
else:
print(f"Invalid option: {user_input}. Please try
again.")
if __name__ == "__main__":
main()
# ↓↓-Output-↓↓
# Please select an option (A, B, C, D): a
# Valid option selected: A
11