Объекты и классы в Python
В этом руководстве вы познакомитесь с базовым функционалом объектов и классов Python. Что такое класс, как его создать и грамотно использовать в программе.
Python — объектно-ориентированный язык программирования. В отличие от процедурно-ориентированного программирования, ООП опирается на объекты.
Объект — это набор данных (переменных) и методов (функций), которые с этими данными взаимодействуют.
Представьте чертеж дома. В нем содержится вся информация: сколько этажей, какого размера двери, окна и т. д. На основе это чертежа мы можем построить дом. Дом — это объект.
По одному чертежу можно построить сразу несколько домов. Так же и с классом — по нему можно создать много объектов. Объект также можно назвать экземпляром класса, а процесс его создания — инстанцированием.
Как объявить класс
По аналогии с функциями, которые начинаются с def
, объявление класса сопровождается ключевым словом class
.
Первая строка внутри класса называется строкой документации, в ней содержится краткое описание класса. Писать ее рекомендуется, но не обязательно.
Объявим класс.
class MyNewClass:
'''Это строка документации. Мы создали новый класс'''
pass
Класс создает новое локальное пространство имен, где определяются все атрибуты. Атрибутами могут быть и переменные, и функции.
Есть и специальные атрибуты, которые начинаются с двойного нижнего подчеркивания __
. Например, __doc__
— строка документации класса.
После объявления класса создается объект этого класса с тем же именем. Этот объект класса позволяет нам как получить доступ к различным его атрибутам, так и инстанцировать новые объекты этого класса.
class Person:
"Это класс, описывающий человека"
age = 10
def greet(self):
print('Привет')
# Вывод: 10
print(Person.age)
# Вывод: <function Person.greet at 0x7f32dbdbeee0>
print(Person.greet)
# Вывод: 'Это мой второй класс'
print(Person.__doc__)
Вывод:
10
<function Person.greet at 0x7f32dbdbeee0>
Это класс, описывающий человека
Как создать объект
Мы уже знаем, что объект класса можно использовать для доступа к различным его атрибутам.
Использовать его можно и для создания новых экземпляров этого класса. Создание объекта похоже на вызов функции.
>>> harry = Person()
Так мы создадим новый экземпляр класса — harry
. Доступ к атрибутам объекта осуществляется при помощи префикса имени объекта.
Атрибутами могут быть и переменные, и методы. Методы объекта — функции этого класса.
Это значит следующее: Person.greet
— объект функции (атрибут класса), а harry.greet
— объект метода.
class Person:
"Это класс, описывающий человека"
age = 10
def greet(self):
print('Привет')
# создаем новый объект класса Person
harry = Person()
# Вывод: <function Person.greet>
print(Person.greet)
# Вывод: <bound method Person.greet of <__main__.Person object>>
print(harry.greet)
# Вызов метода greet() объекта
# Вывод: Привет
harry.greet()
Вывод:
<function Person.greet at 0x7fd288e4e160>
<bound method Person.greet of <__main__.Person object at 0x7fd288e9fa30>>
Привет
Возможно, вы заметили параметр self
в функции класса. Но вызывали метод мы с помощью harry.greet()
. И почему-то это сработало.
Так происходит потому, что когда объект вызывает свой метод, сам объект является первым аргументом. То есть harry.greet()
это то же самое, что и Person.greet(harry)
.
Обычно вызов метода со списком аргументов длины n
равносилен вызову соответствующей функции со списком аргументов, который создается путем вставки объекта метода перед первым аргументов.
По этим причинам первый аргумент функции в классе должен быть сам объект. Это и есть self
— так договорились программисты на Python. Но в теории можно использовать и другое обозначение.
Теперь вы имеете представление о классах, экземплярах класса, функциях, методах. Главное — понимать их отличия.
Конструкторы
Функции класса, начинающиеся с двойного нижнего подчеркивания, называются специальными функциями.
Наибольший интерес вызывает специальная функция __init__(
). Она вызывается каждый раз, когда вы создаете новый объект класса.
В ООП этот вид функций называют конструкторами. Обычно они используются для инициализации всех переменных класса.
class ComplexNumber:
def __init__(self, r=0, i=0):
self.real = r
self.imag = i
def get_data(self):
print(f'{self.real}+{self.imag}j')
# Создаем новый объект ComplexNumber
num1 = ComplexNumber(2, 3)
# Вызываем метод get_data()
# Вывод: 2+3j
num1.get_data()
# Создаем еще один объект ComplexNumber
# и новый атрибут 'attr'
num2 = ComplexNumber(5)
num2.attr = 10
# Вывод: (5, 0, 10)
print((num2.real, num2.imag, num2.attr))
# У объекта c1 нет атрибута 'attr', поэтому
# вызывается ошибка
# AttributeError: 'ComplexNumber' object has no attribute 'attr'
print(num1.attr)
Вывод:
2+3j
(5, 0, 10)
Traceback (most recent call last):
File "<string>", line 27, in <module>
print(num1.attr)
AttributeError: 'ComplexNumber' object has no attribute 'attr'
В этом примере мы объявили класс, представляющий комплексные числа. В нем две функции. Первая, __init__()
, инициализирует переменные (по умолчанию это нули). Вторая, get_data()
, позволяет правильно отображать числа в консоли.
Стоит отметить, что атрибуты объекта могут создаваться «на лету». Мы и создали, и считали атрибут attr
объекта num2
. Но это не значит, что этот атрибут будет доступен num1
.
Как удалить атрибуты и объекты
Любой атрибут объекта можно в любой момент удалить. Сделать это можно с помощью оператора del
. Попробуйте запустить следующую программу и проверьте, что она выводит.
>>> num1 = ComplexNumber(2,3)
>>> del num1.imag
>>> num1.get_data()
Traceback (most recent call last):
...
AttributeError: 'ComplexNumber' object has no attribute 'imag'
>>> del ComplexNumber.get_data
>>> num1.get_data()
Traceback (most recent call last):
...
AttributeError: 'ComplexNumber' object has no attribute 'get_data'
С помощью del
можно удалить даже объект:
>>> c1 = ComplexNumber(1,3)
>>> del c1
>>> c1
Traceback (most recent call last):
...
NameError: name 'c1' is not defined
На самом деле всё намного сложнее. Когда мы выполняем строку c1 = ComplexNumber(1,3)
, создается новый экземпляр класса. Переменная с1
является ссылкой на него.
После выполнения команды del
c1
ссылка и имя c1
удаляются из соответствующего пространства имен. Однако объект все так же будет существовать. Так что если не связать новую переменную с этим объектом, он позже будет автоматически уничтожен.
Удаление объектов, на которые нет ссылок, называется сборкой мусора.