0% found this document useful (0 votes)
6 views7 pages

Lecture 8 Polymorphism, Access Modifier

Uploaded by

f.h.mahi333
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views7 pages

Lecture 8 Polymorphism, Access Modifier

Uploaded by

f.h.mahi333
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

Polymorphism

Polymorphism is a fundamental concept in object-oriented programming (OOP) that allows


objects of different classes to be treated as objects of a common base class. It enables a single
interface to be used for a general set of actions, providing flexibility and code reuse. There are
two types of polymorphism in Python: compile-time (or static) polymorphism and runtime (or
dynamic) polymorphism. I'll focus on runtime polymorphism, which is more commonly used in
Python.

1. Method Overriding:
Method overriding is a form of polymorphism where a subclass provides a specific
implementation of a method that is already defined in its superclass. This allows objects of
different classes to be treated interchangeably.

class Animal:
def speak(self):
return "Animal speaks"

class Dog(Animal):
def speak(self):
return "Dog barks"

class Cat(Animal):
def speak(self):
return "Cat meows"

# Using polymorphism
def animal_sound(animal):
return animal.speak()

# Creating instances of different classes


animal = Animal()
dog = Dog()
cat = Cat()

# Calling the method with different objects


print(animal_sound(animal)) # Output: Animal speaks
print(animal_sound(dog)) # Output: Dog barks
print(animal_sound(cat)) # Output: Cat meows

In this example, the speak method is overridden in the Dog and Cat classes, providing specific
implementations. The animal_sound function can take any object that has a speak method,
demonstrating polymorphism.
2. Duck Typing:
Duck typing is another form of polymorphism in Python, based on the principle "If it looks like a
duck, swims like a duck, and quacks like a duck, then it probably is a duck." In other words, the
type or class of an object is determined by its behavior, not by its explicit type.

class Duck:
def quack(self):
return "Duck quacks"

class Person:
def quack(self):
return "Person imitates a duck"

# Using duck typing


def duck_sound(entity):
return entity.quack()

# Creating instances of different classes


duck = Duck()
person = Person()

# Calling the method with different objects


print(duck_sound(duck)) # Output: Duck quacks
print(duck_sound(person)) # Output: Person imitates a duck

In this example, both the Duck and Person classes have a quack method, allowing them to be
used interchangeably in the duck_sound function.

Polymorphism enhances code flexibility and readability, making it easier to work with diverse
types of objects in a unified manner. It plays a crucial role in achieving abstraction and creating
modular, reusable code.

Is method overloading possible?


Unlike some other programming languages (e.g., Java or C++), Python does not support
traditional method overloading where you can define multiple methods with the same name but
different parameter lists in the same class. In Python, the most recently defined method with a
particular name will override any previously defined method with the same name.

However, Python supports a form of polymorphism that achieves a similar result through a
feature called default parameter values and variable-length argument lists. You can define a
function with default values for its parameters or use *args and **kwargs to accept variable
numbers of arguments.
Example using Default Parameter Values:
class Example:
def add(self, x, y=0):
return x + y

# Creating an instance of the class


obj = Example()

# Calling the method with different argument counts


print(obj.add(2, 3)) # Output: 5
print(obj.add(2)) # Output: 2

In this example, the add method has a default parameter y set to 0. If you provide both x and y,
it adds them together. If you only provide x, it assumes y is 0.

Example using *args:


class Example:
def add(self, *args):
return sum(args)

# Creating an instance of the class


obj = Example()

# Calling the method with different numbers of arguments


print(obj.add(2, 3, 5)) # Output: 10
print(obj.add(1, 2, 3, 4)) # Output: 10

In this example, the add method uses *args to accept any number of arguments. It then
calculates the sum of those arguments.

While Python doesn't have traditional method overloading, these techniques allow you to
achieve similar functionality by providing flexibility in the number and types of arguments a
method can accept.

Access Modifier
In Python, there are no strict access modifiers like private, protected, or public as in some
other object-oriented programming languages. However, Python uses a convention to indicate
the visibility of attributes and methods. The convention is based on the name of the attribute or
method:

1. Public: By default, all attributes and methods are public. This means they can be
accessed from outside the class.

class MyClass:
def __init__(self):
self.public_variable = 42

def public_method(self):
return "This is a public method"

You can access public_variable and public_method from outside the class.

2. Protected: Conventionally, attributes and methods intended to be protected are


prefixed with a single underscore _. This signals to other developers that the
attribute or method should not be accessed from outside the class, but it does not
prevent it.

class MyClass:
def __init__(self):
self._protected_variable = 42

def _protected_method(self):
return "This is a protected method"

It's a convention, and other developers should treat _protected_variable and


_protected_method as if they are non-public. However, Python does not enforce
this.

3. Private: Conventionally, attributes and methods intended to be private are prefixed


with double underscores __. This signals that the attribute or method should not be
accessed directly from outside the class.

class MyClass:
def __init__(self):
self.__private_variable = 42

def __private_method(self):
return "This is a private method"

Again, it's a convention, and Python does not enforce the privacy of
__private_variable and __private_method. However, it performs name
mangling, making it more difficult (but not impossible) to access these attributes
and methods from outside the class.
In summary, while Python does not have explicit access modifiers, it relies on naming
conventions to indicate the intended visibility of attributes and methods. Developers are
expected to follow these conventions, but ultimately, it's up to them to respect or violate these
conventions. The philosophy is often summarized as "We are all consenting adults here,"
trusting developers to follow conventions and not deliberately misuse or break encapsulation.
Example
Let's create a class with public, protected, and private variables, and demonstrate how they can
be accessed or restricted outside the class:

class ExampleClass:
def __init__(self):
# Public variable
self.public_variable = "I am public"

# Protected variable (convention with a single leading


underscore)
self._protected_variable = "I am protected"

# Private variable (convention with a double leading


underscore)
self.__private_variable = "I am private"

def get_public_variable(self):
return self.public_variable

def get_protected_variable(self):
return self._protected_variable

def get_private_variable(self):
return self.__private_variable

# Outside the class


obj = ExampleClass()

# Accessing public variable


print(obj.get_public_variable()) # Accessing using a public method
print(obj.public_variable) # Accessing directly is allowed

# Accessing protected variable


print(obj.get_protected_variable()) # Accessing using a public method
# Accessing directly is allowed but not recommended
print(obj._protected_variable)

# Attempting to access private variable directly would result in an


AttributeError
# Uncommenting the following line will result in an AttributeError
# print(obj.__private_variable)

# Accessing private variable using a public method


print(obj.get_private_variable())

In this example:
• public_variable is a public variable, and it can be accessed both directly and
through a public method.

• _protected_variable is a protected variable, and while it can be accessed


directly, it is recommended to use a public method for access.

• __private_variable is a private variable, and attempting to access it directly


outside the class will result in an AttributeError. Accessing it using a public
method within the class is the recommended way.
Remember that these are conventions and not strict rules enforced by the language. The use of a
single leading underscore or double leading underscore is a way to indicate the intended
visibility, but it doesn't prevent access if someone intentionally chooses to ignore the
convention. Developers are expected to follow these conventions for maintaining code
readability and integrity.

How it works anyaway


Certainly! Let's demonstrate the point that the single leading underscore and double leading
underscore are conventions, not strict rules enforced by the language.

class ExampleClass:
def __init__(self):
# Public variable
self.public_variable = "I am public"

# Protected variable (convention with a single leading


underscore)
self._protected_variable = "I am protected"

# Private variable (convention with a double leading


underscore)
self.__private_variable = "I am private"

def get_public_variable(self):
return self.public_variable

def get_protected_variable(self):
return self._protected_variable

def get_private_variable(self):
return self.__private_variable

# Outside the class


obj = ExampleClass()

# Accessing private variable directly (ignoring the convention)


print(obj._ExampleClass__private_variable) # This will work, but it's
not recommended
# Attempting to access private variable directly without name mangling
will result in an AttributeError
# Uncommenting the following line will result in an AttributeError
# print(obj.__private_variable)

In this example:

• The convention for private variables is to use a double leading underscore, but
Python does not enforce strict visibility control.

• In Python, the double leading underscore is subject to name mangling. It means the
variable name is modified to include the class name, making it less accessible from
outside the class.

• Despite the double leading underscore, it is still possible to access the private
variable by using the mangled name, which consists of
_ClassName__private_variable. However, doing so is not recommended, as it
goes against the intended encapsulation.
So, the point is that while conventions provide a guideline for developers, they are not strict
rules enforced by the language. Developers are expected to follow these conventions to
maintain code readability and integrity. However, if someone intentionally chooses to ignore the
convention, it is still technically possible to access the variables.

You might also like