Python Basics13/13
Starting sandbox…
Intermediate·3 graded tests

Classes

A class defines a type: the data an object of that type holds, and the operations available on it. Instantiating a class creates an object with its own attributes. Classes are worth writing when several values are always handled together and a set of operations applies specifically to that combination.

Reading classes matters more than writing them in this course. Biopython's Seq, SeqRecord and SeqFeature, and the hgvs variant model, are all classes, and using them requires understanding attributes, methods and the role of self.

[1]python
out1ms
chr17 7676154 True

__init__ runs immediately after the object is created and assigns its initial attributes. It is not a constructor in the sense used by some other languages; the object already exists when it is called.

self is the object the method was called on, and is the first parameter of every instance method. Python supplies it automatically: variant.is_snv() calls is_snv(variant). Omitting self from a method definition produces a TypeError on the first call.

String representation

Printing an object without a defined representation produces the class name and a memory address, which is of no diagnostic value. __repr__ should return a precise, unambiguous description, ideally one that resembles the expression which would recreate the object.

[2]python
out1ms
Variant('chr17', 7676154)
[Variant('chr1', 100)]

!r in an f-string applies repr to the value, which is why the chromosome appears quoted above. __repr__ is also what is shown for objects inside a list, since containers display their elements using repr.

Class attributes and instance attributes

An attribute assigned in the class body is shared by every instance. An attribute assigned in __init__ through self belongs to one instance. Use a class attribute for a constant that is a property of the type itself.

[3]python
out1ms
GRCh38 GRCh38

A mutable class attribute is shared across all instances and modifying it through one instance affects every other, which is rarely intended.

Dataclasses

The dataclass decorator generates __init__, __repr__ and __eq__ from the annotated attributes. For a class that principally holds data, this removes a substantial amount of code that would otherwise be written by hand.

[4]python
out1ms
Variant(chrom='chr17', pos=7676154, ref='G', alt='A')
True

Task

Write a Sequence class with:

  • __init__(self, name, bases) storing both, with bases converted to uppercase.
  • length() returning the number of bases.
  • gc_content() returning the GC fraction rounded to four decimal places, or 0.0 for an empty sequence.
  • __repr__ returning "Sequence(<name>, <length>bp)".

Converting to uppercase in __init__ allows every other method to assume a single case, rather than repeating the conversion.

exerciseEvery submission runs independently in a fresh namespace.

Test cases · 3

#viainputexpected stdout
1stdinTP53 atggccSequence(TP53, 6bp) 6 0.6667
2stdinchr17 GGGGCCCCSequence(chr17, 8bp) 8 1.0
3stdintest ATATSequence(test, 4bp) 4 0.0

Hints · 2

01Hint

Uppercase in __init__ so every method can assume uppercase bases.

02Hint

length() can be called from gc_content() as self.length().