Классы
Теперь переходим к азам ООП. Начать стоит с самых азов, а что же такое ООП? Что такое Класс? Зачем он нужен и как нам теперь с этим жить?
В принципе, мы уже вскользь касались многих вещей и понятий, теперь же стоит в них углубиться
Общине понятия
ООП (Объектно-ориентированное программирование) — методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования. Простым языком — это манипуляция объектами.
Объект — некоторая сущность, обладающая определённым состоянием и поведением, имеющая заданные значения свойств (атрибутов) и операций над ними (методов). По сути, это экземпляр класса.
Класс — это элемент программы, описывающий абстрактный тип данных и его частичную или полную реализацию.
По сути, когда мы занимаемся ООП, мы изначально описываем класс, указываем его свойсвта, как с ним работать, а затем на основе класса создаем объекты. При этом, классы могут наследоваться друг от друга, перенимая свойства.
Наследование — описание нового класса, на основе существующего. Изначальный класс — родительский класс, новый класс — дочерний класс.
Полиморфизм — использование объектов с одинаковым интерфейсом без информации о типе и внутренней структуре объекта
При этом, классы могут иметь сложную структуру данных, но при использовании класса, нам это знать не нужно. Нам необходимо знать методы, для работы с ним, его интерфейс
Инкапсуляция — Объединение данных и методов, работающих с этими данными, в классе. По сути, внутренняя кухня класса
С основными понятиями покончено, для лучшего понимания приведу крайне простой и отвлеченный от Python пример:
Предположим, есть Родительский (супер) класс — Млекопитающих. Со своими свойствами (к примеру, 4 конечности, хвост и тд), методами (покушать, погладить и тд). И от него отнаследуем класс Собака. Получается, благодаря Наследованию, все свойства и методы, заложенные в родительский класс, добавятся собаке, при этом, мы можем добавить какие то дополнительные свойства и методы (к примеру, метод лаять). Это и есть наследование класса. Затем создадим элемент класса Собака — Бобик — это уже конкретный объект, со своими методами. Но благодаря тому, что мы знаем “интерфейс” класса, мы знаем, к примеру, как и чем его покормить, что он лает, как его гладить и что ему это нравится и тд.
Надеюсь, данный пример хоть немного смог прояснить основные понятия. Возвращаемся к Python.
Классы в Python
Объявление класса
Для того что бы объявить класс, необходимо выполнить такую конструкцию:
class <class_name>:
<class_code(params,method and etc)>
Для того что бы создать экземпляр класса, надо:
<var_name> = <class_name>()
Как я уже и сказал, у класса могут быть свои методы и свойства. Методы — по сути, простые функции. И вызывать метод надо так же, как мы делали раньше, вызывая методы разных классов (строк, изображений и тд) class_obj.method()
. Но тут есть одно но. Когда объект класса вызывет метод, он передает методу сам себя, что бы можно было работь с параметрами конкретного объекта. По этому при прописывании методов, мы всегда должны указывть ключевое слово self
. Теперь рассмотрим создание простого класса с одним методом — выводом текстовой строки на экран
Пример:
#Объявляем класс
class new_test_class:
# Описываем метод вывода строки
def say_hello(self):
print("Hello from class!")
#Создаем объект созданного нами класса
new_class_obj = new_test_class()
# Дергаем метод
new_class_obj.say_hello()
Результат:
Hello from class!
Работа с классами
При создании объекта класса, происходит его первоначальная инициализация. И данную процедуру можно переопределить. Для этого надо просто описать функцию __init__()
Вообще, конструкция __
— обозначает приватность. Если дописать ее к переменной, то ее модифицировать можно будет только методом класса.
Пример:
class new_test_class:
#Создадим два параметра (атрибуты)
# __a - приватный, к нему нет доступа вне класса (если мы попытаемся к нему обратится, то получим ошибку)
# Параметр b - публичный, мы можем что угодно делать с ним откуда угодно
__a=3
b=4
#Функция инициализации, только выводит текст
def __init__(self):
print ("Class was created!")
#Функция выводит текст и приватный параметр. Обращение идет через self
#Потому что это в данном случае идет изменение параметра объекта, а в self
#как раз сам объект и находится, так как в метод класса всегда передается объект, вызвавший этот метод
#Затем приватной переменной присваивается значение 12
def say_hello(self):
print("Hello from class! "+ str(self.__a))
self.__a = 12
print ("Now let's create obj")
a = new_test_class()
a.say_hello()
a.say_hello()
# Обращаемся к публичному атрибуту, если так же обратиться к приватному, будет ошибка
print (a.b)
Результат:
Now let’s create obj
Class was created!
Hello from class! 3
Hello from class! 12
4
Наследование
Методы можно создавать на основе других методов, в этом случае они унаследуют все атрибуты и методы родителя. При этом никто не мешает дописать новые или переопределить уже имеющиеся. Для того, что бы выполнить наследование, при создании класса всего лишь необходимо указать имя родителя в скобках class <new_class>(<parent class>):
Пример:
#Объявляем родительский класс
#Создаем родительский класс, с парой атрибутов и методов
class new_test_class:
a=3
b=4
#Функция инициализации, только выводит текст
def __init__(self):
print ("Class was created!")
# Описываем метод вывода строки
def say_hello(self):
print("Hello from class! Privat param a = "+str(self.a))
# Метод изменения приватного атрибута
def change_param(self, arg):
self.a=arg
# На основе родительского класса, создадим дочерний, у которого переопределим функцию инициализации
# И добавим новый метод
class child_class(new_test_class):
def __init__(self):
print ("This is new init for childe class")
def sum(self):
print ("{} + {} = {}".format(self.a,self.b,self.a+self.b))
#Создаем объект созданного нами класса
ob = new_test_class()
# Дергаем метод для вывода текста
ob.say_hello()
# Дергаем метод для изменеия приватного параметра
ob.change_param(57)
# Вновь дерним метод, что бы проверить приватный параметр, что он изменился
ob.say_hello()
# Визуально отделю вывод в консоле для нового класса
print()
# Создадим объект дочернего класса и дерним метод, который унаследовался у родительского
ob2 = child_class()
ob2.say_hello()
ob2.change_param(97)
ob2.say_hello()
# Дерним новый метод
ob2.sum()
Результат:
Class was created!
Hello from class! Privat param a = 3
Hello from class! Privat param a = 57This is new init for childe class
Hello from class! Privat param a = 3
Hello from class! Privat param a = 97
97 + 4 = 101
!!!Важно!!!
Приватные атрибуты и методы не наследуются. Не стоит забывать об этом.
Так же хоть и язык Python позволяет это делать, не стоит изменять значения атрибутов класса напрямую, стоит это делать через методы.
В целом, этой информации должно быть достаточно для начала. Больше можно отыскать, как обычено, в документации
Исключения
Общие понятия
Каждый раз, когда совершается любая ошибка, программа завершает свое выполнение и выкидывает исключение. Всего типов исключений много, но самые распространенные исключения:
- SyntaxError — синтаксическая ошибка
- IndexError — Ошибка индекса, обращение к несуществующему индексу
- NameError — Ошибка использования несуществующей переменной
- TypeError — Ошибка при осуществлении действия с несовместимыми типами
- ValueError — Ошибка при попытки передать некорректное значение
- ImportError — Неверный импорт, попытка импорта несуществующей библиотеки
Пример:
print (z)
Результат:
Traceback (most recent call last):
File “”, line 1, in
NameError: name ‘z’ is not defined
Пример:
a=3
print ("Value a = "+a)
Результат:
Traceback (most recent call last):
File “”, line 1, in
TypeError: must be str, not int
В языке Python у разработчика есть возможность контролировать данные исключения. Это необходимо для того, что бы в случае возникновения ошибки, возникшего в связи с внешними условиями (ошибка ввода пользователя, или при взаимодействии с внешними системами), программа продолжала свое выполнение. Реализуется при помощи конструкции
try:
<Операторы, которые могут выкинуть исплючение>
except [<ExeptionType>]:
<Действия, которые необходимо сделать, в случае исключения>
except [<AnotherExeptionType>]:
<Действия, которые необходимо сделать, в случае другого типа исключения>
Данная конструкция попытается выполнить какие то действия, и в случае возникновения исключения типа ExeptionType, программа выполнит одни действия, в случае другого типа исключения AnotherExeptionType — другие.
При этом можно не указывать тип исключения, в этом случае, будут отлавливаться все исключения, кроме синтаксических ошибок
Исключения будут ловиться только в блоке try!
Пример:
a=3
try:
print ("Value a = " + a)
except TypeError:
print ("Oops!")
Результат:
Oops!
Пример:
a=3
try:
print ("Value a = " + a)
except:
print ("Oops!")
Результат:
Oops!
Так же можно указывать разные типы не раздельно, а разом except (<ExeptionType1>,<ExeptionType2>...)
. Так же при помощи finaly:
можно указать действия, которые будут выполнены в любом случае.
Пример:
a=3
try:
print ("Value a = " + a)
except:
print ("Oops!")
finally:
print ("This will be executed in any case")
Результат:
Oops!
This will be executed in any case
Пример:
a=3
try:
print ("Value a = " + str(a))
except:
print ("Oops!")
finally:
print ("This will be executed in any case")
Результат:
Value a = 3
This will be executed in any case
Собственные исключения
Иногда необходимо самостоятельно отслеживать какие то данные, и в случае несоответсвия ожиданиям, необходимо выбросить исключение. Для этого используется ключевое слово raise <ExeptionType>
Пример:
Программа будет выбрасывать исключения, если переменная а является типом int
try:
a = 3
if type(a)==int:
raise TypeError
print ("Type A !=int :)")
except:
print ("Type a = int :(")
Результат:
Type a = int 🙁
Пример:
try:
a = "3"
if type(a)==int:
raise TypeError
print ("Type A !=int :)")
except:
print ("Type a = int :(")
Результат:
Type A !=int 🙂
Пример:
Выбрасываем исключение, с остановкой программы, без попытки отловить, для демонстрации того, как выбрасываются исключения
a = 3
if type(a)==int:
raise TypeError ("Some error text")
print ("Type A !=int :)")
Результат:
Traceback (most recent call last):
File “test5.py”, line 3, in
raise TypeError (“Some error text”)
TypeError: Some error text
Так же бывают случаи, когда исключение надо выкинуть и экстренно завершить программу, но перед этим программа что то должна сделать (к примеру, сохранить данные или что-то еще). Для этого так же можно применить raise
, но уже в блоке except:
Пример:
try:
print (10/0)
except ZeroDivisionError:
print ("Oooops.... but sorry, i have to stop...")
raise
Результат:
Oooops… but sorry, i have to stop…
Traceback (most recent call last):
File “test5.py”, line 2, in
print (10/0)
ZeroDivisionError: division by zero
Собственные типы исключений
Не редко, особенно при написании собственных библиотек, необходимо использовать новые типы исключений, которых нет в Python. Это делает через создания класса для собвственного исключения. Отличия от классов, что мы выше изучали, лишь в том, что он наследуется от родительского класса Exeption.
Пример:
В примере используется ключевое слово pass, которое буквально обозначате ничего не делать. Его исапользуют для создания пустых классов и функций
# Имя класса для исключений принято указывать с Error на конце. Это не обязательно, но так приянто
class MyExeptionError(Exception):
pass
raise MyExeptionError("Some non-required text for error")
Результат:
Traceback (most recent call last):
File “test6.py”, line 5, in
raise MyExeptionError(“Some non-required text for error”)
main.MyExeptionError: Some non-required text for error