January 29, 2021

Name Mangling in Python With Examples

If you are writing a class in Python and want to follow Encapsulation OOPS concept in Python then how will you stop outside access to the variables as there are no explicit access modifiers like public, private, protected in Python and all the variables are public by default. In Python there is limited support for making class member private and that process is known as name mangling in Python.

Python name mangling mechanism

In name mangling mechanism any identifier with at least two leading underscores, at most one trailing underscore is textually replaced with _classname__identifier where classname is the current class name. For example if there is a variable __test in the class then it is replaced with _classname__test.

Since the name is changed internally by the interpreter so you can’t access the variable using its original name that’s how you get data hiding in Python.

Name mangling is helpful for letting subclasses override methods without breaking intraclass method calls.

Name mangling Python example

class User:
  def __init__(self, name, age):
    self.name = name
    self.__age = age

  def display_user(self):
    print('User Name:', self.name)
    print('User Age:', self.__age)


user = User('Mike Dallas', 34)
# calling class method
user.display_user()
# Accessing variables directly
print(user.name)
print(user.__age)
Output
User Name: Mike Dallas
User Age: 34
Mike Dallas
Traceback (most recent call last):
  File "F:/knpcode/Python/Programs/NameMangling.py", line 16, in 
    print(user.__age)
AttributeError: 'User' object has no attribute '__age'

In the class User there is a field __age (declared with double underscores) when it is accessed using the class method that is OK but trying to access it directly results in an error as its name is changed to (_User__age) by the name mangling mechanism.

You can check the name change by using the dir() function which returns a list of valid attributes for the passed object.

class User:
  def __init__(self, name, age):
    self.name = name
    self.__age = age

  def display_user(self):
    print('User Name:', self.name)
    print('User Age:', self.__age)


user = User('Mike Dallas', 34)
print(dir(user))
Output
['_User__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
 '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__',
 '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
 '__subclasshook__', '__weakref__', 'display_user', 'name']

Here you can see that __age is changed to _User__age.

Name mangling with method names

Since any class member with at least two leading underscores, at most one trailing underscore is textually replaced with _classname__identifier so name mangling is applied to the method name too.

class User:
  def __init__(self, name, age):
    self.name = name
    self.__age = age

  def __display_user(self):
    print('User Name:', self.name)
    print('User Age:', self.__age)


user = User('Mike Dallas', 34)
user.__display_user()
Output
Traceback (most recent call last):
  File "F:/knpcode/Python/Programs/NameMangling.py", line 12, in 
    user.__display_user()
AttributeError: 'User' object has no attribute '__display_user'

How to access name mangled variable

In name mangling process name is replaced with _classname__membername so you can still access the member name by using the mangled name. That’s why Python states that there is only limited support for making class member private.

class User:
  def __init__(self, name, age):
    self.name = name
    self.__age = age

  def display_user(self):
    print('User Name:', self.name)
    print('User Age:', self.__age)


user = User('Mike Dallas', 34)
# calling class method
user.display_user()
# Accessing variables directly
print(user.name)
# Accessing using the mangled name
print(user._User__age)
Output
User Name: Mike Dallas
User Age: 34
Mike Dallas
34

Python name mangling with method overriding

Name mangling is also helpful in method overriding in Python. It lets subclasses override methods without breaking intraclass method calls. Consider following example where class B extends class A and overrides parent class test method. In the init() of class A there is also a call to test method.

class A:
  def __init__(self):
    print('in init')
    self.test()

  def test(self):
    print('In test method of class A')


class B(A):
  def test(self):
    print('In test method of class B')


obj = B()
obj.test()
Output
in init
In test method of class B
In test method of class B

As you can see test() method of class B is getting called both of the times as the reference is of class B. But what you intended was to call test() method of class A when doing self.test(). To avoid breaking intraclass method calls in such scenario you can create a private copy of the original method.

class A:
  def __init__(self):
    print('in init')
    self.__test()

  def test(self):
    print('In test method of class A')
      
  # private copy
  __test = test

class B(A):
  def test(self):
    print('In test method of class B')


obj = B()
obj.test()
Output
in init
In test method of class A
In test method of class B

That's all for the topic Name Mangling in Python With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

January 20, 2021

Polymorphism in Python With Examples

In this post we’ll see the usage of OOPS concept Polymorphism in Python.

What is Polymorphism

Polymorphism is a Greek word where poly means “many” and morph means "change from one form to another". In object oriented terms it relates to the same object reference taking many forms (assigned different types), a method with the same name having more than one implementations, an operator behaving differently for different operands.

Polymorphism in Python

In an object oriented language you may see use of Polymorphism in one of the following ways

  • Method overloading, also known as compile time Polymorphism
  • Method overriding, also known as run time Polymorphism
  • Operator overloading

In Python you will find support for Polymorphism through Method overriding and Operator overloading. Python doesn't support method overloading in its traditional sense though. Also when discussing Polymorphism in Python you should also get to know about duck typing in Python. So let’s see some examples.

Compile time polymorphism (Method Overloading)

Method overloading means having multiple methods with the same name in a class. These overloaded methods differ in types or number of arguments passed.

Python doesn’t support compile time polymorphism or method overloading. If there are multiple methods with the same name in a class only the last defined method is recognized. Calling any other overloaded method results in an error.

Read more about Method Overloading in Python in this post- Method Overloading in Python With Examples

Runtime polymorphism (Method Overriding)

In case of inheritance child class inherits all the properties and methods of parent class. If there is a method in a child class that has the same name and same number of arguments as in parent class then this process is called method overriding where the child class method is said to be overriding the parent class method.

Read more about Method Overriding in Python in this post- Method Overriding in Python With Examples

When you call the overridden method with parent class object, method of the parent class is executed. When same method is called with child class object, method of the child class is executed. So the appropriate overridden method is called based on the object type, which is an example of run time polymorphism.

Consider the following class hierarchy where super class Animal has two methods info() and make_sound(). There are two child classes Duck and Dog overriding both of the methods.

class Animal:
  def info(self):
    print('I am an animal')

  def make_sound(self):
    pass


class Duck(Animal):
  def info(self):
    print('I am a Duck')

  def make_sound(self):
    print('Quack Quack')


class Dog(Animal):
  def info(self):
    print('I am a Dog')

  def make_sound(self):
    print('Bow Wow')


d = Duck()
d.info()
d.make_sound()
d = Dog()
d.info()
d.make_sound()
Output
I am a Duck
Quack Quack
I am a Dog
Bow Wow

When d refers to an object of Duck it calls the method of Duck class, when d refers to an object of Dog class it calls the method of that class.

Polymorphism in Python through operator overloading

Operator overloading is also an example of polymorphism where the same operator performs different operations based on the type of operands. Python supports operator overloading.

For example ‘+’ operator-

  • When used with numbers it performs addition operation.
  • When used with two strings concatenate those strings
  • When used with lists merge those lists
# + operator with integers- Addition
print(3 + 4)
# + operator with Strings- Concatenation
print("Operator " + "Overloading")
a = [10, 11, 12]
b = [100, 200, 300]
# + operator with Lists- Merging
print(a + b)
Output
7
Operator Overloading
[10, 11, 12, 100, 200, 300]

Duck typing and Polymorphism

Python follows the duck typing philosophy which states "If it walks like a duck, and it quacks like a duck, then it must be a duck".

In a dynamic language like Python it means that you don't worry about the type or the class of an object. You can perform the required action with the object or not is more important.

Because of this duck typing principle followed by Python it is possible to create a function that can take any object, allowing for polymorphism. As long as the passed object has the called method it can be called. Let’s clear it with an example where we have two classes with a method make_sound(). There is a function invoke which takes any object as an argument and calls the make_sound() method on that object. When invoke function is called with an object of class Duck make_sound() method of the Duck class is called, when it is called with an object of class Dog make_sound() method of the Dog class is called.

class Duck:
  def make_sound(self):
    print("Quack Quack")

class Dog:
  def make_sound(self):
    print('Bow Wow')

def invoke(obj):
  obj.make_sound()

d = Duck()
invoke(d)
d = Dog()
invoke(d)
Output
Quack Quack
Bow Wow

That's all for the topic Polymorphism in Python With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

January 19, 2021

Encapsulation in Python With Examples

In this post we’ll see the usage of OOPS concept Encapsulation in Python.

What is Encapsulation

Encapsulation is the process of keeping the data and the code (methods) that manipulates that data together as a unit. Any variable can only be changed through a method in the same class that way data is protected from any intentional or accidental modification by any outside entity.

A class is an example of encapsulation as it wraps all the variables and methods defined with in that class.

Encapsulation in Python

Since class is an example of Encapsulation so defining a class in Python which wraps all the variables and methods is first step towards encapsulation. But the question is how to stop outside access to the variables as there are no explicit access modifiers like public, private, protected in Python and all the variables are public by default. Here is an example to clarify it-

class User:
  def __init__(self, name, age):
    self.name = name
    self.age = age

  def display_user(self):
    print('User Name:', self.name)
    print('User Age:', self.age)


user = User('Mike Dallas', 34)
# calling class method
user.display_user()
# Accessing variables directly
print(user.name)
print(user.age)
Output
User Name: Mike Dallas
User Age: 34
Mike Dallas
34

As you can see name and age fields of the class User can be accessed through a class method as well as directly outside the class too.

How to control access in Python

As demonstrated through an example class fields can be accessed directly from outside the class in Python so how to control that access and how to have proper encapsulation in Python?

Python has the concept of using a variable prefixed with a single underscore (e.g. _name) and a variable prefixed with double underscores (e.g. __name) to give some semblance to controlling access with in a class.

Using single underscore

Prefixing a variable with a single underscore is merely a convention followed in Python code to show your intention that such a class member should be treated as a non-public part of the API (whether it is a function, a method or a data member). It is more of an indicator to other developers that such a class member should be used only with in the scope of the class and shouldn’t be accessed from outside the class.

Since using a single underscore is just a convention so it doesn’t actually change the access of the variable in any way.

class User:
  def __init__(self, name, age):
    self.name = name
    self._age = age

  def display_user(self):
    print('User Name:', self.name)
    print('User Age:', self._age)


user = User('Mike Dallas', 34)
# calling class method
user.display_user()
# Accessing variables directly
print(user.name)
print(user._age)
Output
User Name: Mike Dallas
User Age: 34
Mike Dallas
34

You can see that the age variable is now prefixed with a single underscore but that can still be accessed outside the class. You will get this warning though ‘Access to a protected member _age of a class’.

Using double underscore

You can come closest to making a class member private in Python by prefixing it with double underscores. This process is known as name mangling in Python where any identifier of the form __var (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__var by the Python interpreter, where classname is the current class name.

class User:
  def __init__(self, name, age):
    self.name = name
    self.__age = age

  def display_user(self):
    print('User Name:', self.name)
    print('User Age:', self.__age)


user = User('Mike Dallas', 34)
# calling class method
user.display_user()
# Accessing variables directly
print(user.name)
print(user.__age)
Output
User Name: Mike Dallas
User Age: 34
Mike Dallas
Traceback (most recent call last):
  File "F:/knpcode/Programs/Example.py", line 16, in 
    print(user.__age)
AttributeError: 'User' object has no attribute '__age'

Now the age variable is prefixed with double underscores which changes its name internally to _User__age thus it is not accessible from outside the class. From the method with in the class it is still accessible.

Note that using double underscores just change the name of the field so it is still possible to access or modify a variable that is considered private by using the changed name.

In the example you can change statement print(user.__age) to print(user._User__age) to access the changed name directly.

That's all for the topic Encapsulation in Python With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

January 14, 2021

isinstance() in Python With Examples

isinstance() function in Python is used to check if the passed object is an instance of the specific class or not. isinstance() is a built-in function in Python.

Python isinstance() syntax

isinstance(object, classinfo)

Returns true if the object (first argument) is an instance of the classinfo (second argument) or any of its subclass. Function returns false if object is not an object of the given type.

classinfo can also be a tuple of type objects, in that case isinstance() function returns true of object is an instance of any of the types in a passed tuple.

If classinfo is not a type or tuple of types a TypeError exception is raised.

Python isinstance() examples

1. Using isinstance() with built-in types

i = 7
s = "knocode.com"
f = 5.67
print('Is i instance of int:', isinstance(i, int))
print('Is s instance of str:', isinstance(s, str))
print('Is f instance of float:', isinstance(f, float))
print('Is s instance of float:', isinstance(s, float))
Output
Is i instance of int: True
Is s instance of str: True
Is f instance of float: True
Is s instance of float: False

2. With list, dict and tuple

t = (2, 3, 4)
l = [1, 2, 3]
d = {'Name': 'Jack', 'Age': 27}
f = 56.78
print('Is t instance of tuple:', isinstance(t, tuple))
print('Is l instance of list:', isinstance(l, list))
print('Is d instance of dict:', isinstance(d, dict))
# tuple of types
print('Is f instance of any type:', isinstance(f, (str, int, float, tuple)))
Output
Is t instance of tuple: True
Is l instance of list: True
Is d instance of dict: True
Is f instance of any type: True

3. Using isinstance() with object

That’s where isinstance() function is more useful. Since Python is an object-oriented programming language so it supports inheritance and you can create a hierarchical structure of classes where a child class inherits from a parent class.

In the example Person is the super class and Employee is the sub-class inheriting from Person. Because of this inheritance Employee object is of type Employee as well as of Person. Person object is of type Person only. Let’s verify this with the help of isinstance() function.

class Person:
  def __init__(self, name, age):
    self.name = name
    self.age = age

  def display_info(self):
    print('In display_info method of Person class')
    print('Name:', self.name)
    print('Age:', self.age)


class Employee(Person):
  def __init__(self, person_id, department, name, age):
    super().__init__(name, age)
    self.person_id = person_id
    self.department = department

  def display_info(self):
    super().display_info()
    print('In display_info method of Employee class')
    print('Id:', self.person_id)
    print('Department:', self.department)

e = Employee(1, "IT", "Michael Weyman", 42)
p = Person("Amit Tiwari", 34)
print('e is an instance of Employee', isinstance(e, Employee))
print('e is an instance of Person', isinstance(e, Person))
print('p is an instance of Person', isinstance(p, Person))
print('p is an instance of Employee', isinstance(p, Employee))
Output
e is an instance of Employee True
e is an instance of Person True
p is an instance of Person True
p is an instance of Employee False

You might be thinking all this is OK but what benefit do I get by just checking whether isinstance() returns true or false.

Python is a dynamically typed language and type is implicitly assigned depending on the value passed. This function comes handy if you want to be sure if the called method is present for an object or not. Here note that if you call a method that is not present for the object AttributeError is raised at runtime.

Consider the following program-

class Person:
  def __init__(self, name, age):
    self.name = name
    self.age = age

  def display_info(self):
    print('In display_info method of Person class')
    print('Name:', self.name)
    print('Age:', self.age)


class Employee(Person):
  def __init__(self, person_id, department, name, age):
    super().__init__(name, age)
    self.person_id = person_id
    self.department = department

  def display_info(self):
    super().display_info()
    print('In display_info method of Employee class')
    print('Id:', self.person_id)
    print('Department:', self.department)


class Test:
  pass


def call_method(o):
  o.display_info()


e = Employee(1, "IT", "Michael Weyman", 42)
call_method(e)
t = Test()
call_method(t)

Another class Test is added and there is a method call_method which takes an object as argument and calls display_info() method on that object. For object of class Employee it will work fine but calling display_info() method on object of class T results in AttributeError.

Output
in call_method
    o.display_info()
AttributeError: 'Test' object has no attribute 'display_info'
In display_info method of Person class
Name: Michael Weyman
Age: 42
In display_info method of Employee class
Id: 1
Department: IT

In such scenario where you want to be sure if object is of certain type and call to the method is valid you can check the type of the object using isinstance(). You can change call_method to include isinstance() as given below-

def call_method(o):
    if isinstance(o, Person):
        o.display_info()

That's all for the topic isinstance() in Python With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

January 13, 2021

Abstraction in Python With Examples

In this post we’ll see the usage of OOPS concept Abstraction in Python.

What is Abstraction

Abstraction means hiding the complexity of the implementation and just exposing the essential features to the user. As an example you can take any electronics item where you interact with the product using buttons and switches to turn it on and off or increase and decrease the volume or speed. The real complexity, how that functionality is implemented is hidden from us.

In the context of object oriented programming Abstraction means exposing just the end points (methods) and hiding the real implementation from the end user.

Abstraction in Python

Abstraction in Python is achieved by using abstract classes and interfaces.

Abstract class is a class that contains one or more abstract methods. Abstract methods are the methods that don’t contain any implementation, sub classes that inherit from the abstract class should provide implementation for the abstract methods. Abstract class can have regular methods (methods with method body) too so you can say that Abstract class generally provides incomplete functionality providing implementation for the common methods while leaving the specific implementation to the sub-classes.

An interface provides just the method signatures without method bodies. Sub-classes should provide implementation for all the methods defined in an interface. Python doesn't support creation of interface through any separate keyword, you will have to define an interface using abstract class itself. If you create an abstract class which contains only abstract methods that acts as an interface in Python.

Abstraction in Python using abstract class

Let’s see an example of abstraction in Python using an abstract class. For declaring an Abstract class you need to import the abc module.

In the example we have an Abstract class User that has one concrete method display_user() and one abstract method process_fee().

from abc import ABC, abstractmethod

class User(ABC):
  def __init__(self, name, num_of_months):
    self.name = name
    self.num_of_months = num_of_months

  # concrete method
  def display_user(self):
    print('User %s subscribed for %d months' % (self.name, self.num_of_months))

  # abstract method
  @abstractmethod
  def process_fee(self):
    pass

There are two sub classes inheriting from User and implementing the abstract method process_fee().

class PlatinumUser(User):
  PLATINUM_PACKAGE = 2200

  def process_fee(self):
      return self.num_of_months * PlatinumUser.PLATINUM_PACKAGE


class GoldUser(User):
  Gold_PACKAGE = 1500

  def process_fee(self):
      return self.num_of_months * GoldUser.Gold_PACKAGE

As a user we just know that we have to call process_fee() method, we are abstracted from the actual implementation of the method which differs for different child classes of User.

obj = PlatinumUser('Mike Dallas', 8)
obj.display_user()
fee = obj.process_fee()
print('Fee is', fee)

obj = GoldUser('Goldie Hawn', 6)
obj.display_user()
fee = obj.process_fee()
print('Fee is', fee)

obj = PlatinumUser('Ashish Mishra', 10)
obj.display_user()
fee = obj.process_fee()
print('Fee is', fee)
Output
User Mike Dallas subscribed for 8 months
Fee is 17600
User Goldie Hawn subscribed for 6 months
Fee is 9000
User Ashish Mishra subscribed for 10 months
Fee is 22000

That's all for the topic Abstraction in Python With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

January 11, 2021

Inheritance in Python With Examples

In this tutorial you’ll learn about OOPS concept inheritance and how to use inheritance in Python.

Inheritance concept

Inheritance allows us to create a class that acquires, all the properties and methods of another class.

The class whose members are inherited is called the Super class. Also known as parent class or base class.

The class that inherits from another class is called the Sub class. Also known as child class or derived class.

Python inheritance syntax

If there is a class called ParentClass defined as-

class ParentClass:
  body of parent class

Then a ChildClass that inherits from this ParentClass can be defined as-

class ChildClass(ParentClass):
  body of child class

Inheritance Python example

In the example there is a class called Person that acts as a base class and another class Employee that inherits from Person class.

class Person:
  def __init__(self, name, age):
    self.name = name
    self.age = age

  def display_person(self):
    print('In display_person method')
    print('Name:', self.name)
    print('Age:', self.age)

class Employee(Person):
  pass

e = Employee("Michael Weyman", 42)
e.display_person()
Output
In display_person method
Name: Michael Weyman
Age: 42

As you can see in Employee class just pass keyword is used to specify that it doesn’t add any property or method to a class. It just inherits all the properties and methods of the class it inherits from.

You can create an object of Employee class and initialize the ‘name’ and ‘age’ properties because Employee class inherits these properties from Person class. Same way you can also call the method display_person() method using the object of Employee class.

Constructor overriding and use of super with inheritance

When a class inherits another class in Python, by default constructor of the super class is also available to the child class. If you have extra fields in the child class which you need to initialize in the child class then you can override the constructor in the child class to initialize the fields there.

In most of the scenarios you’ll inherit from a base class and add properties and methods of its own in the child class as well. To initialize the properties of the child class you can add __init__() function in the child class too. In our Employee class let’s add two fields person_id and department and add a method display_employee() too.

class Employee(Person):
  def __init__(self, person_id, department, name, age):
    self.name = name
    self.age = age
    self.person_id = person_id
    self.department = department

  def display_employee(self):
    print('In display_employee method')
    print('Id:', self.person_id)
    print('Name:', self.name)
    print('Age:', self.age)
    print('Department:', self.department)

In the above class you can notice the redundancy of initializing the parent class’ fields in the constructor though there is a constructor in the parent class which is already doing that. Same way in the display_employee () method we have print statements to print name and age too though there is a method in Person class which is already doing that.

If you want to call super class constructor and methods from sub-class that can be done using super() function which helps in avoiding code redundancy as present in the above Employee class. Here is the modified Employee class with usage of super() function.

class Employee(Person):
  def __init__(self, person_id, department, name, age):
    # call constructor of super class
    super().__init__(name, age)
    self.person_id = person_id
    self.department = department

  def display_employee(self):
    # call method of super class
    super().display_person()
    print('In display_employee method')
    print('Id:', self.person_id)
    print('Department:', self.department)

e = Employee(1, "IT", "Michael Weyman", 42)
e.display_employee()
Output
In display_person method
Name: Michael Weyman
Age: 42
In display_employee method
Id: 1
Department: IT

Advantages of inheritance

  1. Inheritance helps in writing reusable code where you can use the existing functionality just by inheriting from an existing class.
  2. Inheritance helps in writing hierarchical code where you write more generalized code in the super class and then move on to inherit it and add more specific methods. For example you can have a Vehicle super class with more generic functionality like accelerate(), brake(), gear(). Then inherit it to create more specialized classes like Car, Bus, MotorCycle and further down to inherit from Car to create more specific classes like SUV, SportsCar.
  3. Also makes managing the code easy because you don’t put all the functionality in the same class you rather create several classes to create a hierarchical structure with code distributed among those classes.

That's all for the topic Inheritance in Python With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like