In [1]:
%load_ext cython

Inheritance in Cython


In [2]:
%%cython
# cython: embedsignature=True

cdef class Bird:
    cdef public:
        double weight  # ounces
    def __init__(self, weight):
        self.weight = weight
    def weight_ratio(self, carry_weight):
        return carry_weight / self.weight

        
cdef class Swallow(Bird):
    cdef public:
        bint migratory  # True/False
    def __init__(self, weight, migratory):
        super().__init__(weight)  # Call parent constructor
        self.migratory = migratory

Examples of use


In [3]:
bird1 = Bird(5)
bird2 = Bird(7)
bird3 = Bird(100)
# etc.

swallow = Swallow(5, True)  # e.g., a five-ounce swallow

swallow.weight_ratio(16)  # e.g., 16 ounces: a 1 pound coconut


Out[3]:
3.2

Python can subclass Cython classes


In [4]:
class EuropeanSwallow(Swallow):
    def __init__(self):
        # Weight is 20 grams, or 0.7 ounces (not 5 ounces!)
        super().__init__(0.705479, migratory=True)  
        
class AfricanSwallow(Swallow):
    def __init__(self):
        # Weight is 21 grams, or 0.74 ounces
        super().__init__(0.740753, migratory=False)

Demo


In [5]:
euroswallow = EuropeanSwallow()
afriswallow = AfricanSwallow()

load = 3.2 * 16  # A coconut is 3.2 pounds, and 16 oz per lb.

print('Weight ratios')
print('=============')
print('European Swallow: {:.2f}'.format(euroswallow.weight_ratio(load)))
print('African Swallow : {:.2f}'.format(afriswallow.weight_ratio(load)))


Weight ratios
=============
European Swallow: 72.57
African Swallow : 69.12

Polymorphism


In [6]:
%%cython

cdef class Parent:
    cdef str dancing_style(self):
        return "💃: Waltz"
    
cdef class Child(Parent):
    cdef str dancing_style(self):
        return "💃: B-boying/Breaking"
    
# Pay attention!  Declare a var called "obj".  Type is "Parent"
cdef Parent obj

# Create the instance.  But use a subclass!
obj = Child()

# Call the "dancing style" method on obj.  What will display?
print(obj.dancing_style())


💃: B-boying/Breaking

Your code can handle subclasses, but stay fast


In [7]:
%%cython

# The root class
cdef class Ship:
    cdef int passengers
    def __init__(self, int passengers):
        self.passengers = passengers

        
def port_taxes(list ships not None):
    # Because the loop var is TYPED, access to "passengers" is fast
    cdef Ship ship  
    cdef double tot = 0
    for ship in ships:
        tot += ship.passengers * 10.0  # e.g. $10 per passenger
    return tot

Here are some Python subclasses


In [8]:
class Speedboat(Ship):
    def __init__(self):
        super().__init__(2)
        
class LuxuryLiner(Ship):
    def __init__(self):
        super().__init__(1000)

class Yacht(Ship):
    def __init__(self):
        super().__init__(30)

# Lots of instances of different kinds of boats
ships = [Speedboat(), LuxuryLiner(), Speedboat(), Yacht(), Yacht()]

This calculation remains very fast


In [9]:
port_taxes(ships)


Out[9]:
10640.0

In [ ]: