У многих Junior Python-программистов возникают проблемы с классами. Сегодня подробно разберём применение классов в Python, а также затронем тему *args и **kwargs.
Почему эти темы трудные? На начальном уровне программирования нам не требуется строить громоздкие конструкции. Обычно мы ограничиваемся скриптами без собственных классов. Или же создаем объекты классов, не задумываясь о том, что внутри.
Сегодня научимся настраивать классы под себя, добавлять в них новый функционал.
Знакомство с классами в Python
Что потребуется:
- Компьютер или любая другая ЭВМ
- Редактор кода
- Python версии 3.9 и выше
- Соединение с интернетом (впрочем можно и без него)
Начнем разбираться: для чего нужен класс? Он нужен для создания объектов с определенными функциями и данными внутри. То есть класс упрощает нам жизнь. Если у нас есть функционал взаимодействия с чем-либо и для этого нужно вызывать много функций, будет проще объединить все функции в один объект.
Например, мы взаимодействуем с базой данных. Нам приходится выполнять ряд однотипных действий:
- Подключиться к базе
- Найти нужную нам таблицу
- Сделать поиск значений по каким-то параметрам
- Вывести полученные значения.
Таких действий может быть и больше. Скоро нам надоест руками перебирать все функции для работы с БД. Тут и вступают в игру классы.
Рассмотрим на примере кода:
class Person:
def __init__(self, sex: str):
self.sex = sex
self.gender = 'heterosexual'
self.age = 0
print('I was born')
def change_gender(self, preferred_gender: str):
self.gender = preferred_gender
def describe_the_action(self, action: str):
print('I do ', action)
def __del__(self):
print('I am dead')
Сразу уточним, что функции в рамках класса будут называться методами, а переменные - полями. Обратите внимание - в Python принято записывать имя класса с большой буквы, а имена методов - с маленькой.
Метод __init__ - это конструктор, он автоматически вызывается при создании объекта. Как только мы создали новый объект, нам выведется ‘I was born’.
Все методы принимают обязательный элемент self - он указывает, что мы обращаемся именно к этому объекту, а не к какому-то другому.
Для пояснения self есть красочный пример со stackoverflow:
У нашей персоны будет его пол, гендер (стандартный при рождении) и возраст (изначально он будет равен 0). Дальше передаем аргументы.
Теперь немного о полях: они обозначаются обращением к self через точку и название поля.
Метод __del__ - это деконструктор, который срабатывает когда объект уничтожается (вызов del object или завершение скрипта).
Также, мы добавляем свои собственные методы, которые будут выводить что делает человек и выполнять изменение гендера персоны.
Создаем объект на основе класса и передаем его пол "male":
person = Person('male')
Давайте посмотрим что выведется и попробуем изменить пол:
print('gender:', person.gender)
person.change_gender('cat')
print('gender:', person.gender)
Выводы в консоль:
I was born
gender: heterosexual
gender: cat
I am dead
Тут мы видим, что все работает корректно. Предлагаю вам самостоятельно поиграться с классом персон.
Наследование класса
Итак, мы хотим создать новый класс на базе Person. Для этого после названия класса в скобках пишем класс, от которого хотим наследоваться:
class Ivan(Person):
def __init__(self, sex: str, name: str):
super().__init__(sex)
self.name = name
Класс Ivan унаследует все методы и поля, которые есть у родителя Person.
Анонсы всех видео, статей и полезностей - в нашем Telegram-канале🔥
Присоединяйтесь, обсуждайте и автоматизируйте!
Также, надо сделать инициализацию класса родителя. С этим нам поможет super().__init__(sex). После чего добавляем имя для Ivan, чего не было у Person. Теперь можем создать объект "man" и провести с ним некоторые операции:
man = Ivan('male', 'Ivan')
print('gender:', man.gender)
man.change_gender('cat')
print('gender:', man.gender)
Вывод в консоль:
I was born
gender: heterosexual
gender: cat
I am dead
Не забывайте, что обращаться к полям класса можно через точку:
print(man.name)
Вывод в консоль:
Ivan
Теперь вы убедились, что Ivan унаследовал все методы от Person + к ним добавилось поле "name".
Секреты *args и **kwargs
Что это за звёздочки и зачем они нужны? Начнём с *args.
Неважно какое будет название у аргумента, важен сам оператор - звёздочка. В нашем примере звёздочка сообщает Python, что если пользователь укажет больше двух аргументов, все лишние аргументы передадутся в кортеж под названием other:
def arguments(first, second, *other):
print('first:', first)
print('second:', second)
print('other:', other)
print(type(other))
arguments(1, 2, 3, 4, 5, 6, 7, 8)
Давайте посмотрим что выведется в консоль:
first: 1
second: 2
other: (3, 4, 5, 6, 7, 8)
<class 'tuple'>
Первые аргументы, поступающие в функцию, имеют свои названия - first и second. Все остальные аргументы попали в кортеж (tuple). К other нужно обращаться по индексу, как и к обычному кортежу (подробнее о tuple тут).
Что будет, если мы не передадим в other никаких аргументов?
arguments(1, 2)
Вывод в консоль:
first: 1
second: 2
other: ()
<class 'tuple'>
Мы просто получим пустой кортеж - никаких ошибок не будет.
Теперь разберёмся с **kwargs.
def keyword_arguments(first, second, **other):
print('first:', first)
print('second:', second)
print('other:', other)
print(type(other))
keyword_arguments(1, 2, nums=[1, 2, 3, 3], string='text', dict={'key': 'value'})
У ваc может возникнуть вопрос - что за новые аргументы nums, string и dict?
Давайте запустим и посмотрим:
first: 1
second: 2
other: {'nums': [1, 2, 3, 3], 'string': 'text', 'dict': {'key': 'value'}}
<class 'dict'>
Удивительно, но other стал словарем с ключами в виде названий аргументов. Как мы видим, туда можно передавать любое количество аргументов с названием и значением - они будут доступны в виде словаря.
Если мы задаём всего 2 аргумента - словарь просто останется пустым:
keyword_arguments(1, 2)
Вывод в консоль:
first: 1
second: 2
other: {}
<class 'dict'>
Как видите, ошибок нет, мы получили пустой словарь.
Заключение
Темы классов и аргументов не просты в освоении. Надеюсь, мне удалось пролить больше света на эти удивительные возможности Python.
Чем крупнее будут становиться проекты, тем больше вам придётся иметь дело с классами. Без них просто невозможно управлять сложными объектами с большим количеством функций.
Ну а если вы не знаете заранее какие аргументы и в каком количестве вам нужны для функции, на помощь всегда придут *args и **kwargs.
Чтобы понять и закрепить материал, я рекомендую самостоятельно поиграться с классами, с *args и **kwargs. Лучше, если вы примените их на реальном проекте, чтобы как следует разобраться и усвоить детали.
Комментарии