Skip to content

Composition

Putting Things Together

Start by doing Task 4

We now need to combine this new class with our Sample. In a picture, the current situation looks something like this:

Kroki

We have two classes that are lying around without any relation to each other. What we want to achieve is that the Location class represents a location in which a sample was found. This can be achieved by introducing a new attribute found_at into the Sample class which will be given as a Location-instance when creating a new Sample. Such a way of combining classes is called composition.

# If you put the "Location"-class into in its own file,
# make sure to import it before use

class Sample:

    def __init__(self, id, collector, found_at):
          # All the other attributes
        self.found_at = found_at

      # Everything else as before

# Let's try to use this

galapagos = Location(latitude=-0.777259, longitude=-91.142578)
my_sample = Sample(id="22-A-01", collector="Darwin", found_at=galapagos)

# When composing a model of multiple classes, you can chain the "."-operator
print(my_sample.found_at.latitude)
print(my_sample.found_at.longitude)

This is how it would look like in a diagram:

Kroki

We read this as: a Sample is composed of a Location via the found_at attribute.

For future convenience, we have put the Location-class into its own file, called location.py.

If we want to use attributes or methods of the Location-class in our Sample-class, we have to add

from location import Location
before the definition of the Sample-class.

Note: A benefit of putting classes into their own files is to keep programs organized and split them into dedicated pieces that can be easier handled on their own. In technical terms we talk about concerns and responsibilities: A class of type DnaSequencer should not include concerns and responsibilities of a class representing a Location. This means, that for example handling of the coordinates has nothing to do with sequencers and, the other way around, analysing DNA has nothing to do with the location where a sample was taken. In general we want to achieve a so-called Separation of Concerns and make each class adhere to the paradigma of having a single responsibility.

Let’s assume we also want to provide a few default locations for easier use. Our file could now look something like this:

class Location:
     # As before

# A few default locations that we often visit
# Notice that we indicate them to be constants by naming them in UPPER_CASE
DRESDEN = Location(latitude=51.05089, longitude=13.73832)
GALAPAGOS = Location(latitude=-0.777259, longitude=-91.142578)
NORTH_POLE = Location(latitude=90, longitude=0)
NAURU = Location(latitude=-0.5284144, longitude=166.9342384)

By defining these constants, we can now refer to location.DRESDEN in our code, which is a lot easier than repeating the coordinates all over or defining them each time we need them.