Intermediate classes: Difference between revisions

From 22118
Jump to navigation Jump to search
Line 21: Line 21:
# Implement the ''addition'', using [https://zetcode.com/python/dunder-add/ '''__add__''']. Addition creates a new Fasta instance, but leaves the originals untouched.<div style="font-family:'Courier New'">FastaInstance3 = FastaInstance1 + FastaInstance2<br></div>The resulting Fasta object must contain the headers and sequences from FastaInstance1 and FastaInstance2 in that order. Note that this works as an alternative constructor. Now that the Fasta class is done, save it in a file, so you can import it for the next exercises.<br><br>
# Implement the ''addition'', using [https://zetcode.com/python/dunder-add/ '''__add__''']. Addition creates a new Fasta instance, but leaves the originals untouched.<div style="font-family:'Courier New'">FastaInstance3 = FastaInstance1 + FastaInstance2<br></div>The resulting Fasta object must contain the headers and sequences from FastaInstance1 and FastaInstance2 in that order. Note that this works as an alternative constructor. Now that the Fasta class is done, save it in a file, so you can import it for the next exercises.<br><br>
# You can consider a '''Fasta''' instance as a ''set'' of headers/sequences. The sequences are obviously uniquely identified by the identifier in the header, which is what will be used as key in the set operations. In the rest of the exercises we will explore inheritance by making a new class called '''FastaSet''', which inherits from the '''Fasta''' class.<br>A) The original '''__init__''', '''save''', '''load''', '''insert''', the iteration and the corresponding '''deletethis''', '''insertthis''', '''verifythis''' and '''discardthis''' methods are fine to keep in the new class (meaning do nothing about them).<br>B) To help in the new class create a new getter method '''identifiers''', which returns a list of identifiers from the header lines.<br>C) Override the '''content''' method such that it takes a set or list of identifiers and returns only the headers/sequences that corresponds to the identifiers in the list. If you do not specify a list/set of identifiers, it still returns all.<br>D) Override the '''delete''' method in a similar way - it deletes the headers/sequences that corresponds to the input.<br>E) Override the '''verify''' method in a similar way to '''content''' - it verifies the headers/sequences that corresponds to the input.<br>F) Override the '''discard''' method in a similar way to '''content''' - it discards the headers/sequences that corresponds to the input.<br><br>
# You can consider a '''Fasta''' instance as a ''set'' of headers/sequences. The sequences are obviously uniquely identified by the identifier in the header, which is what will be used as key in the set operations. In the rest of the exercises we will explore inheritance by making a new class called '''FastaSet''', which inherits from the '''Fasta''' class.<br>A) The original '''__init__''', '''save''', '''load''', '''insert''', the iteration and the corresponding '''deletethis''', '''insertthis''', '''verifythis''' and '''discardthis''' methods are fine to keep in the new class (meaning do nothing about them).<br>B) To help in the new class create a new getter method '''identifiers''', which returns a list of identifiers from the header lines.<br>C) Override the '''content''' method such that it takes a set or list of identifiers and returns only the headers/sequences that corresponds to the identifiers in the list. If you do not specify a list/set of identifiers, it still returns all.<br>D) Override the '''delete''' method in a similar way - it deletes the headers/sequences that corresponds to the input.<br>E) Override the '''verify''' method in a similar way to '''content''' - it verifies the headers/sequences that corresponds to the input.<br>F) Override the '''discard''' method in a similar way to '''content''' - it discards the headers/sequences that corresponds to the input.<br><br>
# As the new FastaSet class is set orientated, implement the following set operations in the class:<br>A) union, operator is '''|''', magic method is '''__or__'''.<br>B) intersection, operator is '''&''', magic method is '''__and__'''.<br>C) difference, operator is '''-''', magic method is '''__sub__'''.<br>D) symmetric difference, operator is '''^''', magic method is '''__xor__'''.<br>These are quite similar to the addition in exercise 4 - the operators are used in the same way and a new Fasta object is returned. The identity of the sequence depends on the identifier in the corresponding header. This is an example of operator overloading.
# As the new FastaSet class is set orientated, implement the following set operations in the class:<br>A) union, operator is '''|''', magic method is '''__or__'''.<br>B) intersection, operator is '''&''', magic method is '''__and__'''.<br>C) difference, operator is '''-''', magic method is '''__sub__'''.<br>D) symmetric difference, operator is '''^''', magic method is '''__xor__'''.<br>These are quite similar to the addition in exercise 4 - the operators are used in the same way and a new Fasta object is returned. The identity of the sequence depends on the identifier in the corresponding header. This is an example of operator overloading - the normal arithmetic operator used on numbers are used on something completely different.


== Exercises for extra practice ==
== Exercises for extra practice ==
# You continue to add the unique identifier control for all methods in Fasta and FastaSet, as mentioned last week.
# You continue to add the unique identifier control for all methods in Fasta and FastaSet, as mentioned last week.

Revision as of 23:06, 18 March 2026

Previous: Beginning classes Next: Beginning unit test

Required course material for the lesson

Powerpoint: Classes
Resource: Example code - Classes

Subjects covered

Magic methods in classes
Object Oriented Programming
Polymorphism and inheritance
Practical knowledge

Exercises to be handed in

The first four exercises will continue with the Fasta class from last time.

  1. Use magic methods to add iteration and length evaluation (using __iter__ and __len__ magic methods) to the Fasta class. Do this so you can write code like
    if len(MyFastaInstance) > 0:
        for header, sequence in MyFastaInstance:
            # Do something with header and sequence
            print(header, sequence)
    The function len returns the number of sequences.

  2. Add the methods deletethis(), insertthis(header, sequence), verifythis(alphabet) and discardthis(alphabet) to the Fasta class. The methods should only work when iterating over an instance at the current item, i.e. they work when you are iterating over the fasta sequences on the current sequence and header, like this:
    for header, sequence in MyFastaInstance:
        if not MyFastaInstance.verifythis("DNA"):
            MyFastaInstance.deletethis()
            continue
        # Do something with header and sequence
    As some may remember, it is normally impossible to successfully iterate straightforward through a list and delete and/or add elements to the list during the iteration. You have to make this possible. Hint: change the way your iteration works in the previous exercise. You need to take a position on this issue: When iterating over entries, how should you continue after inserting entries at your current position? Example: You are at element in position 5, you insert 2 elements at that position. This WILL mean the new elements are at position 5 and 6, and the one you "looked at" is now on position 7. Do you continue the iteration on position 5 or is the next position 8? My opinion is that you should not look at the new elements and you have already looked at the "old" element ant 5, so the next one is at 8. You are free to make your own decision - just be clear about it.

  3. Let's do something natural. Make it possible to add one FastaInstance to another using the += operator, like this:
    FastaInstance1 += FastaInstance2
    The headers and sequences in Fastainstance2 should be added (list extension) to the headers and sequences in FastaInstance1. Use the magic method __iadd__. Try with the files dna7.fsa and protein.fsa. That will be a strange DNA and protein mix, but it is a great opportunity to use the discard method to get rid of one of the types.

  4. Implement the addition, using __add__. Addition creates a new Fasta instance, but leaves the originals untouched.
    FastaInstance3 = FastaInstance1 + FastaInstance2
    The resulting Fasta object must contain the headers and sequences from FastaInstance1 and FastaInstance2 in that order. Note that this works as an alternative constructor. Now that the Fasta class is done, save it in a file, so you can import it for the next exercises.

  5. You can consider a Fasta instance as a set of headers/sequences. The sequences are obviously uniquely identified by the identifier in the header, which is what will be used as key in the set operations. In the rest of the exercises we will explore inheritance by making a new class called FastaSet, which inherits from the Fasta class.
    A) The original __init__, save, load, insert, the iteration and the corresponding deletethis, insertthis, verifythis and discardthis methods are fine to keep in the new class (meaning do nothing about them).
    B) To help in the new class create a new getter method identifiers, which returns a list of identifiers from the header lines.
    C) Override the content method such that it takes a set or list of identifiers and returns only the headers/sequences that corresponds to the identifiers in the list. If you do not specify a list/set of identifiers, it still returns all.
    D) Override the delete method in a similar way - it deletes the headers/sequences that corresponds to the input.
    E) Override the verify method in a similar way to content - it verifies the headers/sequences that corresponds to the input.
    F) Override the discard method in a similar way to content - it discards the headers/sequences that corresponds to the input.

  6. As the new FastaSet class is set orientated, implement the following set operations in the class:
    A) union, operator is |, magic method is __or__.
    B) intersection, operator is &, magic method is __and__.
    C) difference, operator is -, magic method is __sub__.
    D) symmetric difference, operator is ^, magic method is __xor__.
    These are quite similar to the addition in exercise 4 - the operators are used in the same way and a new Fasta object is returned. The identity of the sequence depends on the identifier in the corresponding header. This is an example of operator overloading - the normal arithmetic operator used on numbers are used on something completely different.

Exercises for extra practice

  1. You continue to add the unique identifier control for all methods in Fasta and FastaSet, as mentioned last week.