ООП:
—инкапсуляция (скрываем внутреннее представление, ограничивая пользователя каким-то внешним интерфейсом)
—полиморфизм
—наследование
объект (класс) содержит данные и функции/поведение.
по сути, объект является моделью некоторой сущности (в т.ч., например, физической — например, велосипеда).
предметная область — грубо говоря, «контекст» (ср. «фрейм»), в котором функционирует программа (e.g. продажа велосипедов) — он предопределяет типы объектов/данных и типы требуемых функций/поведения; предметная область включает сущности и процессы.
class Bike:
def __init__ (self, color, frame_material):
self. color = color
self. frame_material = frame_material
def brake(self):
print("The {} {} bike is breaking".format(self.color, self.frame_material))
red_wooden_bike = Bike("red", "wood")
green_steel_bike = Bike("green", "steel")
red_wooden_bike .brake()
green_steel_bike .brake()
инкапсуляция — сокрытие данных в оболочке класса. снаружи ко всем данным объекта мы можем получить доступ только через его интерфейс (~набор функций-методов).
напрямую можно тоже, язык позволяет, — но это считается неправильным:
print("Color = {}".format(red_wooden_bike.color))
так уже немного лучше:
…
def get_color(self):
return self.color
…
print("Color = {}".format(red_wooden_bike.get_color()))
но ещё лучше вообще реализовывать нужное поведение прямо внутри класса везде, где это возможно (т.е. в данном случае — создать внутреннюю функцию типа “show_color”).
небольшой хак: плейсхолдер pass — когда нам что-то нужно написать в коде, но мы пока не написали — чтобы код продолжал работать:)
ср.:
…
class Frame: pass
…
плюс pass бывает нужен и в готовом коде — если мы намеренно создаём пустышку, которая потом где-то в коде переопределяется.
инвариант — строго определённое, согласованное состояние
в хорошем ООП у класса должно быть инвариантное состояние.
аналогия: робот, которого нужно переместить из точки A в точку B — мы не руками его перетаскиваем, а передаём ему набор команд, который приводит в итоге к его перемещению в нужную точку.
т.е. по возможности всё делать через методы класса (интерфейс), а не через прямые отсылки к его внутренним переменным.
можно визуализировать сложные структуры объектов/классов с помощью UML, Rational Rose, etc.
class Person():
species = 'Human'
— это переменная «по умолчанию»
в Питоне классы (абстрактные, без конкретных экземпляров) сами по себе тоже являются изменяемыми объектами, и их можно менять во время исполнения кода!!! т.е. добавлять новые переменные / менять переменные «по умолчанию», даже добавлять и менять функции!
class Square():
side = 8
def area(self):
return self.side ** 2
sq = Square()
print("Square = {}".format(sq.area()))
print("Square = {}".format(Square.area(sq)))
# print("Square = {}".format(Square.area())) # не должно работать
объявлять функции внутри класса без аргумента self можно, но только как статические (и не понятно, зачем), и с вызовом собственных переменных через название класса:
def perimeter ()
return Square. side * 4
но в норме всегда пишется self при определении функции внутри класса.
вообще на самом деле при стандартном виде вызова — “sq.area()” — self добавляется автоматически, т.е. эта запись на самом деле эквивалентна “Square.area(sq)”
даже конструктор вызывается на самом деле так же. т.е. обычная краткая запись:
sq = Square()
— равносильна на самом деле:
Square.__init__(sq)
конструктор класса — это метод __init__()
вообще внутри самих создаваемых экземпляров класса по умолчанию создаётся только то, что создаётся внутри __init__(), остальное остаётся в общем объекте класса, и вызывается оттуда.
==============
Февраля
Пользовательский интерфейс — будет на следующем занятии.
взял доклад про PyQt!!
общий тьюториал, как установить, как окошко отобразить, примеры небольшие.
если что — писать Антону.
см. wiki.python.org/moin/GuiProgramming/
Объектно-ориентированное программирование (ООП) в Питоне, ч. 2
Наследование (inheritance)
class Base:
def __init__(self, value_1, value_2):
self._value_1 = value_1 # конвенция: нижнее подчёркивание (_) в начале имени переменной показывает, что это внутренние данные, которые лучше не трогать извне
self._value_2 = value_2
def calculate_sum(self):
return self._value_1 + self._value_2
class Derived (Base): pass
test_derived = Derived(12, 12)
print(test_derived.calculate_sum())
можно теперь что-то поменять, например, сделать создание класса с дважды продублированным аргументом:
class Base:
def __init__(self, value_1, value_2):
self._value_1 = value_1
self._value_2 = value_2
def calculate_sum(self):
return self._value_1 + self._value_2
class Derived(Base):
def __init__(self, single_value):