Учебная страница курса биоинформатики,
год поступления 2013
Ещё раз про объекты и классы. Работа с исключениями
О пользе объектно-ориентированного подхода. Наследование.
Зачастую бывает так, что в программе необходимо создать новые объекты, которые отличаются от уже имеющихся наличием каких-то дополнительных свойств или слегка другим поведением. Например, если мы найдем в классе ошибку, нам придется ее исправлять сразу в двух местах. Для того, чтобы избежать такое копирование, придумали механизм наследования.
Предположим, у нас есть класс Man, заданный следующим образом:
Мы хотим задать класс Superman, который будет наследовать все методы и свойства класса Man, т.к. супермэн обладает теми же способностями, что и обычный человек и иметь свои собственные методы:
1 class Superman(Man): # This class inherits from Man class.
2
3 def __init__(self, P_name, P_secret_identity):
4 #super(Superman, self).__init__(P_name)
5 Man.__init__(self,P_name)
6 self.secret_identity = P_secret_identity
7 print("...but his secret identity is '" \
8 + self.secret_identity + "' and he's a super-hero!")
9
10
11 def walk(self, P_super_speed = False):
12 if (not P_super_speed):
13 Man.walk(self)
14 else:
15 print(self.secret_identity + " run at the speed of light")
16
17 def fly(self):
18 print(self.secret_identity + " fly up in the sky")
19
20 def x_ray(self):
21 print(self.secret_identity + " uses his x-ray vision")
Некоторые методы изменяются по сравнению с родительским классом, переопределить их можно двумя способами: обратившись к методу родительского класса
либо с помощью метода super(), который вызывает тот же самый метод у родителя класса:
Этот способ позволяет избежать багов при сложной разветвленной схеме наследования или когда мы меняем что-то в родительских классах.
Наследование - еще один пример
В качестве еще одного примера, рассмотрим систему классов для геометрических фигур. Каждая фигура задается своим положением на холсте, цветом и размерами. Все фигуры умеют вычислить свою площадь, и у каждого типа фигур площадь вычисляется по своим правилам. Помимо фигур, в нашей системе будут просто точки. Точка не имеет размера, но задается координатами и цветом.
Метод str - это строковое представление объекта. Если определен этот метод, то когда мы печатаем с помощью print, объект преобразуется по таким правилам в строку для печати. Поскольку точка не имеет размера, ее площадь равна 0. Теперь зададим класс для прямоугольников. У прямоугольника, в отличие от точки, есть ширина и высота.
1 class Rect(Point): #в скобках указываем класс, от которого наследуем
2 def __init__(self, x, y, color, w, h):
3 Point.__init__(self, x, y, color) # вызываем конструктор родительского класса
4 self.w = w
5 self.h = h
6 def square(self):
7 return self.w*self.h
8 def __str__(self):
9 return "rect (%d, %d), %s, %d, %d" % (self.x, self.y, self.color, self.w, self.h)
Квадрат – это прямоугольник, у которого ширина равна высоте. То есть, квадрат – особый вид прямоугольников. И площадь у него вычисляется по тем же законам. Это тоже можно выразить с помощью наследования.
Ну и теперь создадим список из разных фигур и выведем на экран:
Работа с исключениями
Исключение (exceptions) – это особый тип данных, способ обозначить в программе ошибку (например "нам дали плохие данные") таким образом, чтобы потом эту ошибку можно было исправить. Программы и методы в python могут иметь некоторые требования к тому, с какими данными и в каких ситуациях они могут быть применимы, когда эти ожидаемые требования не исполняются, выбрасываются исключения - исключения из общего порядка вещей для работы этих методов. Примеры возможных исключений -
exception ArithmeticError (OverflowError, ZeroDivisionError)
-основной класс для описания арифметических ошибок (результат арифметической операции слишком велик, чтобы быть представленным; деление на ноль)
exception IOError
- ошибки, связанные с потоками ввода – вывода (например методы print, open()), ошибки – не существует файла, нет места на диске для записи
exception ImportEror
- нет модуля с указанным названием для import’а
exception IndexError
- отсутствие элемента с заданным индексом
exception KeyError
- нет в словаре заданного ключа
exception ValueError
При встрече исключительного случая - программа прерывается с выводом сообщение об ошибке или продолжает работать с предупреждением в зависимости от типа ошибки. Предположим, мы хотим написать программу, которая читает информацию из файлов (например, просто считает, сколько строк в каждом файле), имена которых подаются в командной строке. python countLines.py a.txt b.txt c.txt
Допустим, в директории, в которой мы находимся, есть файлы a.txt и c.txt, но нет b.txt. Тогда при попытке открыть несуществующий файл программа упадет, так и не посмотрев третий файл. При этом питон напишет вам сообщение об ошибке, которое помимо прочего будет содержать строчку
Выполнение программы прервется и файл c.txt обработан не будет.
Отлов исключений
Покуда мы с исключением ничего не делаем, выброс исключения для нас означает прекращение работы программы здесь и сейчас. Но мы можем его поймать, и тогда сделать то, что кажется нам местным в данном случае, например, напечатать предупреждение и продолжить работать:
Теперь, если внутри блока try было выброшено исключение, то в этот момент питон прекратит исполнять содержимое блока и перейдёт к блоку except. Если исключения не случилось, то в блок except питон не попадёт.
С помощью конструкции try..except также можно ловить и обрабатывать исключения определенных типов.
Ещё пример:
Выброс исключений
Исключения можно не только ловить, но и выбрасывать в заданных ситуациях.
Файл infile.txt формата:
#description
#another
12 100
34 450
…
Преимущество программы, в которой везде как положено выбрасываются исключения состоит в том, что мы сначала пишем основной ход программы так, как мы считаем она должна работать на правильных данных, а потом вставляем в нужных местах отлов исключений, не меняя кода по содержанию.
Конструкция операторов try..except..else – в else определяется то, что должно быть сделано в случае, если ни одно из исключений except не случилось. Оператор finally - то, что под ним будет выполнено в любом из описанных случаях.
1 >>> def divide(x, y):
2 ... try:
3 ... result = x / y
4 ... except ZeroDivisionError:
5 ... print "division by zero!"
6 ... else:
7 ... print "result is", result
8 ... finally:
9 ... print "executing finally clause"
10
11 >>> divide(2, 1)
12 result is 2
13 executing finally clause
14 >>> divide(2, 0)
15 division by zero!
16 executing finally clause
17 >>> divide("2", "1")
18 executing finally clause
19 Traceback (most recent call last):
20 File "<stdin>", line 1, in ?
21 File "<stdin>", line 3, in divide
22 TypeError: unsupported operand type(s) for /: 'str' and 'str'
При возникновении исключения оно не обрабатывается сразу а передается вверх по стеку вызовов функций, пока это возможно, если обработки исключения не случилось, то выдается исключение и сообщение об ошибке.