In [19]:
class Chair(object):
def __init__(self, occupant=None, colour='unknown'):
self.occupant = occupant
self.colour = colour
def is_occupied(self):
if self.occupant == None:
return False
else:
return True
def sit_in(self, person):
if self.is_occupied():
raise ValueError("Chair occupied by {}".format(
self.occupant))
else:
self.occupant = person
def get_up(self):
self.occupant = None
In [20]:
chair1 = Chair()
chair1.sit_in('Yves')
print chair1.occupant
chair1.sit_in('Megan')
In [23]:
class Bed(object):
def __init__(self):
self.occupants = []
self.size = 1
def set_size(self, size):
self.size = size
def get_size(self):
if self.size == 1:
return 'single'
elif self.size == 2:
return 'double'
elif self.size == 3:
return 'king'
def get_in(self, person):
if len(self.occupants) == self.size:
return ValueError("Bed full!")
else:
self.occupants.append(person)
def has_space(self):
if len(self.occupants) < self.size:
return True
else:
return False
def leave(self, person):
if person in self.occupants:
del self.occupants[self.occupants.index(person)]
In [28]:
bed1 = Bed()
bed1.get_size()
bed1.set_size(2)
bed1.get_in('Peter')
bed1.get_in('Andrew')
print bed1.occupants
print bed1.has_space()
In [55]:
class BlastHit(object):
def __init__(self, fields):
if type(fields) != list and len(fields) != 12:
raise ValueError("BLAST hit requires a list of 12 fields")
self.query_id = fields[0]
self.subject_id = fields[1]
self.perc_identity = float(fields[2])
self.aln_length = int(fields[3])
self.mismatches = int(fields[4])
self.gap_opens = int(fields[5])
self.q_start = int(fields[6])
self.q_end = int(fields[7])
self.s_start = int(fields[8])
self.s_end = int(fields[9])
self.e_val = float(fields[10])
self.bit_score = float(fields[11])
Classes have a signature which is their collection of methods, i.e. their behaviour. Special method names allow us to give a class a certain behaviour, e.g. acting like a collection. See the documentation on emulating containter types.
In [66]:
class BlastHits(object):
def __init__(self):
self.hits = []
def add_hit(self, hit):
if type(hit) != BlastHit:
raise ValueError("Can only add a BlastHit type")
else:
self.hits.append(hit)
def __getitem__(self, i):
return self.hits[i]
def __len__(self):
return len(self.hits)
In [112]:
import sys
import subprocess
import shlex
import os
import tempfile
class BlastRunner(object):
def __init__(self, query_filename, dbname):
self.query_filename = query_filename
self.dbname = dbname
self.blast_cmd = 'unknown'
def parse_results(self, tempfile):
input_file = open(tempfile)
hits = BlastHits()
with input_file:
# Fields: query id, subject id, % identity, alignment length, mismatches,
# gap opens, q. start, q. end, s. start, s. end, evalue, bit score
for line in input_file:
line = line.rstrip()
fields = line.split('\t')
blast_hit = BlastHit(fields)
hits.add_hit(blast_hit)
return hits
def run(self):
if self.blast_cmd == 'unknown':
raise ValueError("Unknown BLAST type")
tmpfile = tempfile.NamedTemporaryFile(delete=False)
cmd_str = '{} -query {} -db {} -outfmt 6 -out {}'.format(
self.blast_cmd, self.query_filename,
self.dbname, tmpfile.name)
cmd = shlex.split(cmd_str)
code = subprocess.call(cmd)
hits = self.parse_results(tmpfile.name)
os.remove(tmpfile.name)
return hits
class NuclBlastRunner(BlastRunner):
def __init__(self, query_filename, dbname):
self.query_filename = query_filename
self.dbname = dbname
self.blast_cmd = 'blastn'
class ProtBlastRunner(BlastRunner):
def __init__(self, query_filename, dbname):
self.query_filename = query_filename
self.dbname = dbname
self.blast_cmd = 'blastp'
In [115]:
runner = NuclBlastRunner('query.fasta', 'blastdb')
hits = runner.run()
In [106]:
print hits
In [120]:
class RollableChair(Chair):
def __init__(self, occupant=None, colour='unknown', location='here'):
super(RollableChair, self).__init__(occupant, colour)
self.location = location
def roll(self, destination):
self.location = destination
In [123]:
chair3 = RollableChair()
chair3.roll("Peter's office")
chair3.sit_in("Long")
Illustration of class variables (aka. class attributes) that are distinct from the attributes of objects.
In [142]:
class DNA(object):
bases = set('ACTG')
def __init__(self, sequence):
self.sequence = sequence
def is_dna(self):
for char in self.sequence:
if char not in self.__class__.bases:
return False
return True
def change(self, bases):
self.bases = set(bases)
In [143]:
dna1 = DNA('ACTG')
In [145]:
print dna1.is_dna()
dna1.change('ACTGN')
print dna1.bases
print dna1.__class__.bases
print DNA.bases
By convention if we want to make an attribute (or a method) private, we prefix its named with an undercore (_). There is nothing stopping a programmer from directly accessing the attributes in the example below but they should not.
In [146]:
class Bird(object):
def __init__(self, species):
self._species = species
def get_species(self):
return species
def set_species(self, species):
self._species = species
(1) Create a class Table that has the attributes num_legs and colour and a method paint to change the colour.
In [153]:
class Table(object):
def __init__(self, num_legs, colour):
self.colour = colour
self.num_legs = num_legs
def paint(self, colour):
self.colour = colour
def get_colour():
return self.colour
def __str__(self):
return "{} table with {} legs".format(self.colour,
self.num_legs)
def __int__(self):
return self.num_legs
In [154]:
table1 = Table(4, 'red')
print "table1:", table1
table1.paint('white')
print "table1:", table1
int(table1)
Out[154]:
In [ ]: