Опубликован: 22.12.2005 | Доступ: свободный | Студентов: 16909 / 520 | Оценка: 4.18 / 3.71 | Длительность: 16:16:00
ISBN: 978-5-9556-0109-0
Лекция 4:

Объектно-ориентированное программирование

Полиморфизм

В переводе с греческого полиморфизм означает "многоформие". Так в информатике называют возможность использования одного имени для выполнения различных действий.

Можно встретить множество определений полиморфизма (также есть несколько видов полиморфизма) в зависимости от языка программирования. Как правило, в качестве примера проявления полиморфизма приводят переопределение методов в подклассах. При этом можно создать функцию, требующую формального аргумента - экземпляра базового класса, а в качестве фактического аргумента давать экземпляр подкласса. Функция будет вызывать метод объекта с именем, а за именем будут скрываться различные действия. В связи с этим полиморфизм обычно связывают с иерархией наследования.

В Python полиморфизм связан не с наследованием, а с набором и смыслом доступных методов в экземпляре класса. Ниже будет показано, что, имея определенные методы, можно воссоздать класс для строки или любого другого встроенного типа. Для этого необходимо определить свойственный типу набор методов. Конечно, нужный набор методов можно получить и с помощью наследования, но в Python это не только не обязательно, но иногда и противоречит здравому смыслу.

При написании функции в Python обычно не проверяется, к какому типу (классу) относится тот или иной аргумент: некоторые методы просто применяются к переданному объекту. Тем самым функции получаются максимально обобщенными: они не требуют от объектов-параметров большего, чем наличие методов с определенным именем, набором аргументов и семантикой.

Следующий пример показывает полиморфизм в том виде, в котором он свойственен Python:

def get_last(x):
  return x[-1]

print get_last([1, 2, 3])
print get_last("abcd")

Описанной функции будет подходить в качестве аргумента все, от чего можно взять индекс -1 (последний элемент). Однако семантика "взятие последнего элемента" выполняется только для последовательностей. Функция будет работать и для словарей, но смысл при этом будет немного другой.

Имитация типов

Для иллюстрации понятия полиморфизма можно построить собственный тип, похожий на встроенный тип "функция". Построить класс, объекты которого вызываются подобно методам или функциям, можно так:

class CountArgs(object):
  def __call__(self, *args, **kwargs):
    return len(args) + len(kwargs)

cc = CountArgs()
print cc(1, 3, 4)

Как видно из этого примера, экземпляры класса CountArgs можно вызывать подобно функциям (в результате будет возвращено количество переданных параметров). При попытке вызова экземпляра на самом деле будет вызван метод __call__() со всеми аргументами.

Следующий пример показывает, что сравнением экземпляров класса тоже можно управлять:

class Point:
  def __init__(self, x, y):
    self.coord = (x, y)
  def __nonzero__(self):
    return self.coord[0] != 0 or self.coord[1] != 0
  def __cmp__(self, p):
    return cmp(self.coord, p.coord)

for x in range(-3, 4):
  for y in range(-3, 4):
    if Point(x, y) < Point(y, x):
      print "*",
    elif Point(x, y):
      print ".",
    else:
      print "o",
  print

Программа выведет:

. * * * * * *
. . * * * * *
. . . * * * *
. . . o * * *
. . . . . * *
. . . . . . *
. . . . . . .

В данной программе класс Point (Точка) имеет метод __nonzero__(), который определяет истинностное значение объекта класса. Истину будут давать только точки, отличные от (0, 0). Другой метод - __cmp__() - вызывается при необходимости сравнить точку и другой объект (имеющий как и точка атрибут coord, который содержит кортеж как минимум из двух элементов). Нужно заметить, что вместо __cmp__ можно определить отдельные методы для операций сравнения: __lt__, __le__, __ne__, __eq__, __ge__, __gt__ (для <, <=, !=, ==, >=, > соответственно).

Достаточно легко имитировать и числовые типы. Класс, который пользуется удобством синтаксиса инфиксного +, можно определить так:

class Plussable:
  def __add__(self, x):
    ...
  def __radd__(self, x):
    ...
  def __iadd__(self, x):
    ...

Здесь метод __add__() вызывается, когда экземпляр класса Plussable стоит слева от сложения, __radd__() - если справа от сложения и метод слева от него не имеет метода __add__(). Метод __iadd__() нужен для реализации +=.

Андрей Егоров
Андрей Егоров

def bin(n):

"""Цифры двоичного представления натурального числа """

if n == 0:

   return []

n, d = divmod(n, 2)

return bin(n) + [d]

print bin(69)

Что значит здесь return[] ? Возвращает список? Непонятно какой список? Откуда он? 

 

 

Асмик Гаряка
Асмик Гаряка

Почему при вычислении рейтинга не учитывается уровень, как описано? Для всех курсов У=1, хотя для Специалист должно быть 2.

Алексей Чмыхалов
Алексей Чмыхалов
Россия, Краснодар, Школа-гимназия 33, 2000
Владимир Крюков
Владимир Крюков
Казахстан