Определение класса. Пример класса.
Класс - разновидность абстрактного типа данных в объектно-ориентированном программировании. При использовании классов все элементы кода программы, такие, как переменные, константы, методы, процедуры и функции, могут принадлежать (а во многих языках обязаны принадлежать) тому или иному классу. Сам класс в итоге определяется как список своих членов, а именно полей(свойств) и методов/функций/процедур.
Пример класса в Python.
class OurClass(object):
def __init___(self,arg1,arg2)
self.arg1 = arg1
self.arg2 = arg2
def print_args(self):
print self.arg1
print self.arg2
Метод __init__() вызывается сразу же после создания экземпляра класса. Он напоминает конструктор класса в других языках программирования, и является первым блоком кода, который исполняется в контексте только что созданного экземпляра класса, но на момент вызова __init__() объект уже является созданным, и можно оперировать ссылкой на него - self.
Первым аргументом любого метода класса, включая __init__() всегда является ссылка на текущий экземпляр класса. Принято называть этот аргумент self. При вызове метода self указывать не надо, Python добавит его автоматически:
c = OurClass('1', '2')
c.print_args()
>>1
>>2
В языке Python реализовано автоматическое управление памятью, поэтому деструктор требуется достаточно редко. Вот пример класса с деструктором:
class Line(object):
def __init__(self, p1, p2):
self.line = (p1, p2)
def __del__(self):
print "Удаляется линия %s - %s" % self.line
Рассмотрим еще один пример класса. Это класс, который позволяет вести банковский счет клиента.
class Account(object):
num_accounts = 0
def __init__(self, name, balance):
self.name = name
self.balance = balance
Account.num_accounts += 1
def __del__(self):
Account.num_accounts -= 1
def deposit(self, amt):
self.balance = self.balance + amt
Переменные класса (такие как num_accounts в данном примере) - значения, которые совместно используются всеми экземплярами класса.
Наследование
Наследование - механизм для создания новых классов, призванный настроить или изменить поведение существующего класса. Оригинальный класс называют базовым или суперклассом. Новый класс называют производным или подклассом. Наследование определяется перечислением в определении класса имен базовых классов через запятые. Наследование часто используется для переопределения поведения существующих методов (можно переопределять любое количество методов суперкласса). Если поиск атрибута в экземпляре или классе экземпляра не увенчался успехом, то он ищется в базовых классах. Подкласс может добавлять к экземплярам новые атрибуты, определяя собственную версию метода __init__(). Например (класс Account ищи выше),
class EvilAccount(Account):
def __init(self, name, balance, evilfactor):
Account.__init__(self, name, balance)
self.evilfactor = evilfactor
def inquiry(self):
#переопределим функцию запроса баланса. При выполнении некоторого случайного
#условия данный класс будет возвращать искаженное значение баланса на счете.
if random.randint(0,4) == 1:
return self.balance*self.evilfactor
else:
return self.balance
Когда производный класс определяет собственный метод __init__(), методы __init__() базовых классов перестают вызываться автоматически. Поэтому производный класс должен следить за выполнением инициализации базовых классов, вызывая их методы __init__(). Если базовый класс не имеет метод __init__(), этот шаг может быть пропущен. Если заранее не известно, определяется ли в базовом классе метод __init__(), для надежности можно вызвать его без аргументов, потому что всегда существует реализация по умолчанию, которая ничего не делает.
Рассмотрим пример, когда в производном классе требуется переопределить метод, но при этом желательно вызвать оригинальную реализацию:
class MoreEvilAccount(EvilAccount):
def deposit(self, amount):
self.withdraw(5.00) #вычесть комиссию
super(MoreEvilAccount,self).deposit(amount) #а теперь пополнить счет
В Python поддерживается множественное наследование.
class DepositCharge(object):
fee = 5.00
def deposit_fee(self):
self.withdraw(self.fee)
class WithdrawCharge(object):
fee = 2.50
def withdraw_fee(self):
self.withdraw(self.fee)
class MostEvilAccount(EvilAccount, DepositCharge, WithdrawCharge):
def deposit(self, amt):
self.deposit_fee()
super(MostEvilAccount, self).deposit(amt)
def withdraw(self, amt):
self.withdraw_fee()
super(MostEvilAccount, self).withdraw(amt)
Чтобы обеспечить поиск атрибутов при множественном наследовании, все базовые классы включаются в список, в порядке от более специализированных к менее специализированным. Класс EvilAccount является более специализированным, чем Account, так как он его наследует. DepositCharge более специализирован, чем WithdrawCharge, потому что стоит первее в списке базовых классов.
Полиморфизм - свойство, которое позволяет одно и то же имя использовать для решения двух или более схожих, но технически разных задач. Например, для языка Си, в котором полиморфизм поддерживается недостаточно, нахождение абсолютной величины числа требует 3 различных функций: abs(), labs() и fabs(). Эти функции подсчитывают и возвращают абсолютную величину целых, длинных целых и чисел с плавающей точкой соответственно. В C++ вместо нескольких таких функций используется функция abs().
В более общем смысле, в основе полиморфизма лежит идея "один интерфейс, множество методов". Это означает возможность использования одного и того же имени операции или метода у объектов разных классов, при этом действия, совершаемые с объектами, при выполнении этой операции или метода, одинаковы или близки по смыслу, но технически различаются. Вот пример полиморфизма.
class Animal(object):
def talk(self):
pass
class Cat(Animal):
def talk(self):
return 'meow'
class Dog(Animal):
def talk(self):
return 'bark'
Полиморфизм позволяет, например, осуществлять такие вещи:
Kitty = Cat()
Toto = Dog()
d = [Kitty, Toto]
for el in d:
el.talk() #без разницы, экземпляром какого класса является el - полиморфизм
Композиция: объект может быть составным и включать в себя другие объекты. Еще композицию определяют так: механизм для создания нового класса путем объединения нескольких объектов существующих классов в одно целое. Вложенные объекты обычно объявляются закрытыми - частными внутри класса-агрегата. Возникает вопрос: чем отличается композиция от наследования? Наследование предполагает похожесть, а композиция - формирование целого из частей.
А вот из этого источника следует, что композиция является частным случаем агрегации. Агрегация - отношение вида часть-целое между классом, который представляет собрание компонент и классами, представляющими компоненты. Класс-супермножество содержит 1 или более классов-подмножеств. Свойство включения может быть сильным (агрегация по значению) или слабым (агрегация по ссылке). Композиция обладает дополнительным свойством зависимость по существованию. Объект класса-подмножества не может существовать в отсутствие связи с объектом класса-супермножества. Отсюда следует, что если объект супермножества удален, объекты его подмножеств также удаляются.
Обратим внимание на инструкцию OurClass(object). Если вы не хотите определить этот класс как наследованный от какого-то другого класса, то его нужно определить как наследованный от object. Также можно наследовать встроенные классы и классы из модулей расширения. Эта особенность появилась начиная с Python 2.2, классы, наследованные от object или других классов, называются "новыми классами".
До сих пор в коде библиотек Python можно встретить и классы старого образца, которые определяются так:
class ClassName:
...
Они еще работают, но уже помечены как deprecated.
class EvilAccount(Account):
def __init(self, name, balance, evilfactor):
Account.__init__(self, name, balance)
self.evilfactor = evilfactor
def inquiry(self):
#переопределим функцию запроса баланса. При выполнении некоторого случайного
#условия данный класс будет возвращать искаженное значение баланса на счете.
if random.randint(0,4) == 1:
return self.balance*self.evilfactor
else:
return self.balance
Когда производный класс определяет собственный метод __init__(), методы __init__() базовых классов перестают вызываться автоматически. Поэтому производный класс должен следить за выполнением инициализации базовых классов, вызывая их методы __init__(). Если базовый класс не имеет метод __init__(), этот шаг может быть пропущен. Если заранее не известно, определяется ли в базовом классе метод __init__(), для надежности можно вызвать его без аргументов, потому что всегда существует реализация по умолчанию, которая ничего не делает.
Рассмотрим пример, когда в производном классе требуется переопределить метод, но при этом желательно вызвать оригинальную реализацию:
class MoreEvilAccount(EvilAccount):
def deposit(self, amount):
self.withdraw(5.00) #вычесть комиссию
super(MoreEvilAccount,self).deposit(amount) #а теперь пополнить счет
В Python поддерживается множественное наследование.
class DepositCharge(object):
fee = 5.00
def deposit_fee(self):
self.withdraw(self.fee)
class WithdrawCharge(object):
fee = 2.50
def withdraw_fee(self):
self.withdraw(self.fee)
class MostEvilAccount(EvilAccount, DepositCharge, WithdrawCharge):
def deposit(self, amt):
self.deposit_fee()
super(MostEvilAccount, self).deposit(amt)
def withdraw(self, amt):
self.withdraw_fee()
super(MostEvilAccount, self).withdraw(amt)
Чтобы обеспечить поиск атрибутов при множественном наследовании, все базовые классы включаются в список, в порядке от более специализированных к менее специализированным. Класс EvilAccount является более специализированным, чем Account, так как он его наследует. DepositCharge более специализирован, чем WithdrawCharge, потому что стоит первее в списке базовых классов.
Полиморфизм
Полиморфизм - свойство, которое позволяет одно и то же имя использовать для решения двух или более схожих, но технически разных задач. Например, для языка Си, в котором полиморфизм поддерживается недостаточно, нахождение абсолютной величины числа требует 3 различных функций: abs(), labs() и fabs(). Эти функции подсчитывают и возвращают абсолютную величину целых, длинных целых и чисел с плавающей точкой соответственно. В C++ вместо нескольких таких функций используется функция abs().
В более общем смысле, в основе полиморфизма лежит идея "один интерфейс, множество методов". Это означает возможность использования одного и того же имени операции или метода у объектов разных классов, при этом действия, совершаемые с объектами, при выполнении этой операции или метода, одинаковы или близки по смыслу, но технически различаются. Вот пример полиморфизма.
class Animal(object):
def talk(self):
pass
class Cat(Animal):
def talk(self):
return 'meow'
class Dog(Animal):
def talk(self):
return 'bark'
Полиморфизм позволяет, например, осуществлять такие вещи:
Kitty = Cat()
Toto = Dog()
d = [Kitty, Toto]
for el in d:
el.talk() #без разницы, экземпляром какого класса является el - полиморфизм
Инкапсуляция
Можно скрыть ненужные внутренние подробности работы объекта от окружающего мира. В Python инкапсуляция реализована лишь частично. А именно, если вы хотите, чтобы атрибут класса (т.е. переменная, свойство или метод) был скрыт от посторонних глаз, вам нужно изменить его имя, дописав сначала два подчеркивания (__):
class Simple(object):
__private_attr = 10
def __init__(self):
self.__private_attr = 20
s = Simple()
print s.__private_attr #вызовет ошибку
Вот здесь показано, что в Python такую инкапсуляцию можно при желании легко обойти.
Композиция и агрегация
А вот из этого источника следует, что композиция является частным случаем агрегации. Агрегация - отношение вида часть-целое между классом, который представляет собрание компонент и классами, представляющими компоненты. Класс-супермножество содержит 1 или более классов-подмножеств. Свойство включения может быть сильным (агрегация по значению) или слабым (агрегация по ссылке). Композиция обладает дополнительным свойством зависимость по существованию. Объект класса-подмножества не может существовать в отсутствие связи с объектом класса-супермножества. Отсюда следует, что если объект супермножества удален, объекты его подмножеств также удаляются.
"Старые" и "новые" классы: отличия
Обратим внимание на инструкцию OurClass(object). Если вы не хотите определить этот класс как наследованный от какого-то другого класса, то его нужно определить как наследованный от object. Также можно наследовать встроенные классы и классы из модулей расширения. Эта особенность появилась начиная с Python 2.2, классы, наследованные от object или других классов, называются "новыми классами".
До сих пор в коде библиотек Python можно встретить и классы старого образца, которые определяются так:
class ClassName:
...
Они еще работают, но уже помечены как deprecated.
Класс (Википедия), Погружение в Python 3 (викитека), Полиморфизм в python younglinux, Программирование на python. Часть 6 ibm, Композиция в python younglinux, Д.Бизли. Python. Подробный справочник, introduction to OOP with python, ООП Python (википедия)
Комментариев нет:
Отправить комментарий