• No results found

Inheritance: Properties Are Transmitted between the Re- Re-lated Classes

In document Python for Bioinformatics (Page 161-165)

Classes can be related between themselves and are not isolated entities. It is possible to have a mammal class with common properties with the orca class and the dog class. For example, the method reproduction can be defined for the mammal class. When we create the classes dog and orca, we can define them as “children” of mammal. It won’t be necessary to create for them the method reproduction. Child classes will be able to have their own methods themselves that make them unique, like immersion and race.

Polymorphism

Is the ability of different types of objects to respond to the same method with a different behaviour. For example you can iterate over a list, a set, a dictionary, a file, a database, and more in the same way.

Encapsulation

Is the ability to hide the internal operation of an object and leave access for the programmers only through their public methods. The term encap-sulation is not associated with Python because this language does not have a true encapsulation. It is possible to make the access to certain methods difficult, but not to prevent it. It is not in the philosophy of Python to be in the way of the programmer. What it is possible to do in Python is to make clear what methods and properties are owned by a class and those thought to be shared. Sometimes this behavior is referred to as pseudo-encapsulation or translucent encapsulation. It is up to the programmer to make a rational use of this option. That is called in Python: Protection by convention, not by legislation. See the section “Making our code private” on page 154 for using this property.

8.3 Creating Classes

Remember that classes are the template of the objects. The syntax to create classes in Python is very simple:

class NAME:

[body]

Let’s see a class that actually does something:

class Square:

def __init__(self):

self.side=1

This class (Square) has a method called init . It is a special method that has as a characteristic the fact that it does not return anything and that it is executed whenever an instance of Square is created. In this case it sets the value of the attribute side. Another peculiarity to consider is the word self that is repeated as parameter of the method and as part of the name of the attribute. Self is a variable that is used to represent the instance of Square. It is possible to use another name instead of self, but self is used by convention. It is advisable to follow the convention because it makes our program easier to understand by other programmers who may want to read our code in the future.1

Instantiation uses function notation. It is like a function without parameters that returns a new instance of the class. Let’s see an example, the use of the Square class, with the creation of the instance Bob:

>>> Bob=Square() # Bob is an instance of Square.

>>> Bob.side #Let’s see the value of side 1

It is possible to change the value of the attribute side of the instance Bob:

>>> Bob.side=5 #Assing a new value to side

>>> Bob.side #Let’s see the new value of side 5

Although this change is specific for this instance, when new instances are created the method init is executed again to assign the side value to the new instance:

1There are also code analyzers that depend on this convention for working.

>>> Krusty=Square()

>>> Krusty.side 1

In the case that the variable side is a variable that must be accessible from all the instances of the class, it is advisable to use a class variable. These variables are shared by all the objects of the same class.

class Square:

side=1

This way, the value of side will be defined even before we create an instance of Square:

>>> Square.side 1

Of course if we created instances of Square, they will also have this value of side:

>>> Crab=Square()

>>> Crab.side 1

The class variables can have information on the instances. For example it is possible to use them to control how many instances of a class have been created.

class Square:

CountObjects=0 def __init__(self):

Square.CountObjects=Square.CountObjects+1 print "Object created successfully"

This version of Square can count the number of instances that have been created. Note that the CountObjects variable is acceded within the class as Square.CountObjects to distinguish itself from an instance variable, which is noted with the prefix self.VARIABLENAME. Let’s see how this object is used:

>>> Bob=Square()

Object created successfully

>>> Patrick=Square()

Object created successfully

>>> Square.CountObjects 2

Let’s see a more useful, though simple class:

class Sequence:

TranscriptionTable = {"A":"U","T":"A","C":"G","G":"C"}

def __init__(self, seqstring):

self.seqstring=seqstring.upper() def transcription(self):

tt = ""

for x in self.seqstring:

if x in ’ATCG’:

tt += self.TranscriptionTable[x]

return tt

This class has two methods and one attribute. The method init is used to set the value of seqstring in each instance:

>>> DangerousVirus=Sequence(’atggagagccttgttcttggtgtcaa’)

>>> DangerousVirus.seqstring

’ATGGAGAGCCTTGTTCTTGGTGTCAA’

>>> HarmlessVirus=Sequence(’aatgctactactattagtagaattgatgcca’)

>>> HarmlessVirus.seqstring

’AATGCTACTACTATTAGTAGAATTGATGCCA’

The Sequence class also has a method called transcription that has as its only parameter the instance itself (represented by self ). This parameter does not appear when the function is called, because it is implicit. Notice that the function transcription uses the class variable of the TranscriptionTable (that is a dictionary) to convert the sequence seqstring to its transcript equivalent:

>>> DangerousVirus.transcription()

’GCUAAGAGCUCGCGUCCUCAGAGUUUAGGA’

The methods can also have parameters. In order to show this, here is a new mehod (restriction) in the Sequence class. This method calculates how many restriction sites has a sequence for a given enzyme.2 Therefore, this method will require as parameter a restriction enzyme. Another difference is that this class will contain a dictionary that relates the name of the enzyme to the recognition sequence:

Listing 8.1: Sequence class (py3.us/26) class Sequence:

TranscriptionTable = {"A":"U","T":"A","C":"G","G":"C"}

2Remember that a restriction enzyme is a protein that recognizes a specific DNA sequence and produces a cut within the recognition zone.

# Dictionary with the name of the restriction enzyme and

# the recognition sequence.

EnzDict = {"EcoRI":"GAATTC","EcoRV":"GATATC"}

def __init__(self, seqstring):

self.seqstring = seqstring.upper() def restriction(self,enz):

try:

return self.seqstring.count(Sequence.EnzDict[enz]) except:

return 0

def transcription(self):

tt = ""

for x in self.seqstring:

if x in ’ATCG’:

tt += Sequence.TranscriptionTable[x]

return tt Using the Sequence class:

>>> other_virus=Sequence(’atgatatcggagaggatatcggtgtcaa’)

>>> other_virus.transcription()

’UACUAUAGCCUCUCCUAUAGCCACAGUU’

>>> other_virus.restriction("EcoRV") 2

Tip: Not All Classes Are Created Equal: Classic Versus

In document Python for Bioinformatics (Page 161-165)