Skip to content

Inheritance

Generally speaking…

Let’s imagine that for a DnaSequencer the sequence length is tied to the model of sequencer we are using. Also of course all sequencers of the same model have the same name for the model and consequently provide the same sequence length. We could say that all sequencers of a specific model are a special case of DNA sequencers in general. Such specializations can be modelled in OOP via a relationship called inheritance.

Kroki

The key idea is that a specific model of DNA sequencer inherits all general attributes and methods from its more generic parent class and only needs to add its own specific attributes and methods.

In Python, the parent class is provided in parenthesis after the class name.

# Make sure the class DnaSequencer is either in the same file
# Or available via import

class DnaMaster2000(DnaSequencer):
    MODEL = "DNA Master 2000"

Our new DnaMaster2000 actually does things a bit differently. While the analysis behaves as usual, it always prints its model and serial number before each run and a summary afterwards. This specialization of behaviour incorporates two further concepts:

  • Overriding, where a method from a super-class is replaced by an implementation of a sub-class.
  • Calling members of the super-class with the super-keyword.
class DnaMaster2000:
    MODEL =   # as before

    def analyze_sample(self, sample):  # Provide our own implementation
        print(self.MODEL, "- S/N", self.serial_number)  # Note how we access MODEL here! See notes on class instance accessibility!
        super().analyze_sample(sample)  # Call to the superclass implementation
        print("Analyzed ", len(sample.dna_sequence), "bases")

The function super() gives access to the underlying instance of the superclass for an object. There is a LOT more to be said about this topic, but it quickly becomes super()-complicated. A good writeup can be found on the Real Python Blog.

The DNA Master 2000 also comes specially sealed, so it does not get dirty during deliveriy and is ready to use. We can model this by overriding the __init__(…)-method.

class DnaMaster2000(DnaSequencer):
    MODEL = 

    def __init__(self, serial_number):
        super().__init__(
            serial_number=serial_number,
            is_clean=True
        )

    def analyze_sample(self, sample):
          # as before

Let’s give this a try:

from sample import Sample
import location
from dna_sequencer import DnaMaster2000

my_sample = Sample(identifier="0123", collector="Darwin", found_at=location.NAURU)
my_sequencer = DnaMaster2000(serial_number="R2D2-C3PO")

my_sequencer.analyze_sample(my_sample)

print(my_sample)
print(my_sample.dna_sequence)

Now try your hand at Task 8