ГлавнаяСтатьиСПО и программирование → ООП без ерунды

ООП без ерунды

28 июля 2016 года
Ключевые слова: Python , программирование

Объектное программирование нередко трудно для понимания и провоцирует бесчисленные споры. Я думаю, это заслуга возвышенного стиля некоторых учебников, наподобие:

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

Не будем претендовать на лавры Михал Михалыча Зощенко, а попробуем изложить тему проще и понятней. Но как всегда, все уже сделано до нас, и эта заметка представляет собой обычный реферат двух замечательных статей Дениса Шереметова [1] и Антона Сухинова [2].

Принципы ООП.

Базовая структура это класс.

Собака, кот, мышь это классы. Жучка, Мурзик, Микки-Маус экземпляры класса/объекты. Для наглядности принято, что первая буква имен класса всегда большая, а у имен объектов, свойств и методов маленькая. У всех составных имен вторая буква всегда большая.

Класс имеет набор свойств/полей и действий/методов. Например, у экземпляра класса "Овчарка" есть свойства "кличка", "возраст" и действия "сидеть", "лежать", "лаять".
Помимо свойств и методов объект всегда должен иметь имя. Не путайте его со свойством "кличка", например:

мояОвчарка.кличка = "Барбос"

Что означает, что у объекта по имени "мояОвчарка" есть кличка и она "Барбос". Похожим образом работают методы/действия объектов, например:

мояОвчарка.сидеть()
мояОвчарка.лежать()

Методы могут параметризоваться, например чтобы лаять заданное число раз:

мояОвчарка.лаять(3)

Объект всегда должен быть создан. Класс существует просто как данность. Создание объекта в разных языках различно, но обычно так:

мояОвчарка = new Овчарка

Так создается новый экземпляр класса "Овчарка". Иногда он может параметризоваться начальной информацией:

мояОвчарка = new Овчарка ("Барбос")

Конечно ничто не вечно под Луной, и когда нибудь произойдет печальное событие:

del мoяОвчарка

Зачем нужно ООП?

Обычные программы выполняют алгоритмы, инструкции для достижения заданного результата. Например, программа решения квадратного уравнения.
У ООП иная цель. Оно моделирует взаимодействия объектов окружающего мира. Мир есть система. Она логично раскладывается на классы и объекты, их свойства и методы, что позволяет создавать интуитивно понятную архитектуру и код, наподобие:

корабль.курс(200)
корабль.скорость(50)
корабль.торпеда.нацелить(220)
корабль.торпеда.выстрел(2)


Сами объекты внутри могут быть очень сложными и содержать десятки, даже сотни частей. Но управлять ими сравнительно просто.

Инкапсуляция, наследование, полиморфизм.

В ООП программные объекты должны имитировать главные свойства реальных объектов — рождаться, уничтожаться, взаимодействовать и изменяться. Как описывать классы, как создавать и уничтожать объекты, их методы и свойства мы уже представляем. Дополним картину.

Поговорим о наследовании. Овчарка это подкласс Собаки. Собака может быть дикой, не иметь клички, не уметь выполнять никакие команды, но возраст у нее есть всегда.

Class Собака()
    свойства: возраст

Class Овчарка(Собака)
    свойства: кличка
    методы: сидеть(), лежать(), лаять()

Итак класс Овчарка унаследовал все свойства и методы Собаки, в данном случае это одно свойство "возраст", и имеет добавочные: "кличка" и "сидеть", "лежать", "лаять". Класс Собака родительский, а Овчарка дочерний.

Что такое инкапсуляция? Пусть коровы на ферме имеют клички и инвентарные номера. Но постороннего (если, конечно, он не ревизор) за проходную не пускают. Ему невозможно узнать или изменить параметры коров. Внутренние свойства объекта, недоступные через его интерфейс (набор способов и средств общения объекта с внешним миром) называют инкапсулированными:

Class Корова()
    свойства:__кличка ,__инвентарный номер

Слово полиморфизм подразумевает единый интуитивно понятный программисту интерфейс разных классов. Например, метод add(x,y) может одновременно означать и сумму двух чисел и склеивание двух строк. Объекты и действия совсем разные, а название метода одинаковое.

В языке слова, пишущиеся одинаково, но означающие разные вещи называют омонимы. Синонимы это слова, означающие, в сущности, одно и тоже. Так уж исторически сложилось , что компьютерные сайентологи очень их полюбили :) Объект могут называть экземпляром класса, а его свойства полями, данными или атрибутами. Действия зовутся методами... Будем надеяться, что в будущем избыток терминов исчезнет.

Cинтаксис классов и объектов в Python.

Образец класса.

Вот файл test.py в котором создан класс Dog, моделирующий служебную собаку.

# -*- coding: utf-8 -*-
# test.py
# Python 2.7
 
class Dog:    
    """ It is a police's dog model """
 
    def __init__(self, name = u'Бобик'):
        print u'Это', name
        self.name = name
        self.__secret='I speak English!'
 
    def __del__(self):
        print self.name, u'на пенсии'
 
    def sit(self):
        print self.name, u'cидит'
 
    def lay (self):
        print self.name, u'лежит'
 
    def bark(self,m):
        for i in range(m):
            print u'Гав!'

Работу класса удобно изучать в пошаговом режиме. Для этого в Windows открываем наш файл в IDLE и жмем F5, а в Linux откроем консоль в текущем каталоге (обычно F4) и пишем:

python
from test import *

Посмотрим, что такое Dog:

>>> Dog
<class __main__.Dog at 0x0218DAB0>
Dog это класс, находящийся в исполняемом модуле ( его имя __main__ ) по некоторому адресу памяти. Специальный метод __doc__ читает его строку документации:

>>> Dog.__doc__
" It is a police's dog model "

Свойства и методы класса.

Создаем объект:

>>> s=Dog()
Это Бобик
__init__ и __del__ это специальные методы, выполняемые при создании и удалении объекта. Их называют конструктором и деструктором класса. Слово self местоимение, означающее свой собственный. Оно показывает место действий. Наша собачка имеет два свойства публичное self.name и приватное self.__secret и три метода sit, lay, bark.

>>> s.sit()
Бобик cидит
 
>>> s.lay()
Бобик лежит
 
>>> s.bark(2)
Гав!
Гав!
Умеет ли собачка охранять секреты? На первый взгляд да:

>>> s.__secret
 
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    s.__secret
AttributeError: Dog instance has no attribute '__secret'
Но рассмотрим ее повнимательнее, интроспектируем объект:

>>> dir(s)
['_Dog__secret', '__del__', '__doc__', '__init__', '__module__', 'bark', 'lay', 'name', 'sit']
Все элементарно. Приватное свойство __secret подменилось на _Dog__secret. Его можно просмотреть и изменить:

>>> s._Dog__secret
'I speak English!'
>>> s._Dog__secret='I like cats'
Можно присвоить собачке новое свойство, а когда вскроются ее темные делишки, отнять его обратно и удалить ее из памяти.

>>> s.orden='Почетная косточка'
>>> s._Dog__secret
'I like cats'
>>> del s.orden
>>> del s
Бобик на пенсии

Удаление объектов.

Удаление в Python работает в два этапа. Сперва команда del удаляет ссылку на объект не трогая его самого. Затем автоматический сборщик мусора стирает лишь те объекты, на которые нет ни единой ссылки, объекты гарантированно не нужные.

К чему это ведет? Создадим Шарика и клонируем его:

>>> s1=Dog('Шарик')
Это Шарик
>>> s2=s1
>>> del s2
>>> del s1
Шарик на пенсии
Объект удаляется, когда удаляются все его клоны. Другой пример. Создадим Шарика и Жучку и пусть они полюбят друг друга:

>>> s1=Dog('Шарик')
Это Шарик
>>> s2=Dog('Жучка')
Это Жучка
>>> s1.love=s2
>>> s2.love=s1
>>> del s1
>>> del s2
>>> s1
 
Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    s1
NameError: name 's1' is not defined

После удаления ссылок s1, s2 уже нет, но сами объекты остались в памяти потому, что они дважды ссылаются друг на друга. Подобная ситуация называется утечкой памяти. Если она повторяется часто, то приложение может исчерпать все ресурсы и аварийно завершиться.

Наследование.

Наследование в Python это просто добавление отличий. Добавим в test.py новый класс SuperDog.

class SuperDog(Dog):
    def meow(self,m):
        for i in range(m):
            print u'Мяу!'
SuperDog умеет все, что Dog и еще мяукает :

>>> s=SuperDog()
Это Бобик
>>> s.bark(1)
Гав!
>>> s.meow(1)
Мяу!

Послесловие.

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

Литература.

  1. Денис Шереметов. ООП для «чайников». Классы и объекты.
  2. Антон Сухинов. Питон, девушки и объектно-ориентированное программирование (18+)

Оставьте свой комментарий

Ваше имя:

Комментарий:

Формулы на латехе: $$f(x) = x^2-\sqrt{x}$$ превратится в $$f(x) = x^2-\sqrt{x}$$.
Для выделения используйте следующий код: [i]курсив[/i], [b]жирный[/b].
Цитату оформляйте так: [q = имя автора]цитата[/q] или [q]еще цитата[/q].
Ссылку начните с http://. Других команд или HTML-тегов здесь нет.

Сколько будет 65+9?