10.9 Duck Typing and Polymorphism

Most other object-oriented programming languages require inheritance-based “is a” relationships to achieve polymorphic behavior. Python is more flexible. It uses a concept called duck typing, which the Python documentation describes as:

A programming style which does not look at an object’s type to determine if it has the right interface; instead, the method or attribute is simply called or used (“If it looks like a duck and quacks like a duck, it must be a duck.”).8

So, when processing an object at execution time, its type does not matter. As long as the object has the data attribute, property or method (with the appropriate parameters) you wish to access, the code will work.

Let’s reconsider the loop at the end of Section 10.8.3, which processes a list of employees:

for employee in employees:
    print(employee)
    print(f'{employee.earnings():,.2f}
')

In Python, this loop works properly as long as employees contains only objects that:

  • can be displayed with print (that is, they have a string representation) and

  • have an earnings method which can be called with no arguments.

All classes inherit from object directly or indirectly, so they all inherit the default methods for obtaining string representations that print can display. If a class has an earnings method that can be called with no arguments, we can include objects of that class in the list employees, even if the object’s class does not have an “is a” relationship with class CommissionEmployee. To demonstrate this, consider class WellPaidDuck:

In [1]: class WellPaidDuck:
   ...:     def __repr__(self):
   ...:         return 'I am a well-paid duck'
   ...:     def earnings(self):
   ...:         return Decimal('1_000_000.00')
   ...:

WellPaidDuck objects, which clearly are not meant to be employees, will work with the preceding loop. To prove this, let’s create objects of our classes CommissionEmployee, SalariedCommissionEmployee and WellPaidDuck and place them in a list:

In [2]: from decimal import Decimal

In [3]: from commissionemployee import CommissionEmployee

In [4]: from salariedcommissionemployee import SalariedCommissionEmployee

In [5]: c = CommissionEmployee('Sue', 'Jones', '333-33-3333',
   ...:                        Decimal('10000.00'), Decimal('0.06'))
   ...:

In [6]: s = SalariedCommissionEmployee('Bob', 'Lewis', '444-44-4444',
   ...:     Decimal('5000.00'), Decimal('0.04'), Decimal('300.00'))
   ...:

In [7]: d = WellPaidDuck()

In [8]: employees = [c, s, d]

Now, let’s process the list using the loop from Section 10.8.3. As you can see in the output, Python is able to use duck typing to polymorphically process all three objects in the list:

In [9]: for employee in employees:
   ...:     print(employee)
   ...:     print(f'{employee.earnings():,.2f}
')
   ...:
CommissionEmployee: Sue Jones
social security number: 333-33-3333
gross sales: 10000.00
commission rate: 0.06
600.00

SalariedCommissionEmployee: Bob Lewis
social security number: 444-44-4444
gross sales: 5000.00
commission rate: 0.04
base salary: 300.00
500.00

I am a well-paid duck
1,000,000.00
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.131.110.169