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.
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"
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")
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
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