0 знаков
66. Разбираемся с атрибутами и методами класса в Python
В предыдущем уроке мы реализовали два класса User
и Admin
, создали конструктор, добавили атрибуты и методы класса, перегрузили оператор и попробовали наследовать Admin
от User
. В этом уроке более детально поговорим о реализации оператора class
, атрибутах и методах в Python.
Оператор class
Например, как и в C++, оператор class
представляет собой главный инструмент ООП в Python, но в отличие от C++ оператор class
языка Python class
не является объявлением. Подобно def
оператор class
создает объекты и неявно присваивает их - при выполнении он генерирует объект класса и сохраняет ссылку на него в имени, используемом в заголовке.
Также подобно def
оператор class
относится к настоящему исполняемому коду - ваш класс не существует до тех пор, пока Python не достигнет и не выполнит оператор class
, который его определяет. Обычно это происходит во время импортирования модуля, содержащего оператор class
, но не ранее.
Общая форма оператора class
:
class имя(суперкласс, ...):
атрибут = значение
def метод(self, ...):
self.атрибут = значение
Оператор class
определяет пространство имен. Он напоминает как модули (подобно именам в модуле имена, присвоенные в операторе class
, становятся атрибутами в объекте класса), так и функции (подобно функциям операторы class
являются локальными областями видимости, где находятся имена, созданные вложенными присваиваниями).
Зачем тогда использовать классы, если они вбирают в себя возможности модулей и функций? Пространство имен классов формирует основу для наследования в Python. Используемые атрибуты, отсутствующие в объекте класса, извлекаются из других классов, от которых он наследуется.
Атрибуты класса
Присвоение значений простым объектам (не функциям) создают атрибуты класса:
class TestClass:
a = 10 # атрибут класса
x = TestClass() # первый экземпляр класса
y = TestClass() # второй экземпляр класса
print(x.a, y.a) # => 10 10
Чтобы изменить значение атрибута для всех экземпляров класса, необходимо обратиться к этому атрибуту через имя класса:
TestClass.a = 100
print(x.a, y.a) # => 100 100
Что если менять значение через экземпляр? Посмотрим на примере:
x.a = 99
print(x.a, y.a) # => 99 10
Далее рассмотрим пример поведения атрибутов класса и экземпляра:
class TestClass:
data = 'atr'
def __init__(self, value):
self.data = value
def display(self):
print(f'Атрибут экземпляра: {self.data}',
f'Атрибут класса: {TestClass.data}')
x = TestClass(1)
y = TestClass(2)
x.display() # => 1 atr
y.display() # => 2 atr
Значение имени data
находится в локальной области видимости класса и поэтому становится атрибутом класса, который разделяется всеми экземплярами класса. Атрибут data
присутствует в двух местах: в локальной области видимости класса и в конструкторе (в __init__()
).
Методы класса
Метод класса является обычной функцией, в дополнении к последней имеет аргумент self
(через него метод получает объект экземпляра) и находится в области видимости класса, в котором объявлен. То есть следующий вызов метода display()
из предыдущего примера:
x.display() # => 1 atr
Интерпретатор Python преобразует в следующий вид:
TestClass.display(x) # => 1 atr
Рассмотрим еще один пример метода класса в Python:
class TestClass:
def display(self, text):
self.data = text
print(self.data)
x = TestClass()
x.display(123) # => 123
print(x.data) # => 123
Имя display
ссылается на объект функции (def
) и находится в области видимости оператора class
, тем самым является методом класса, который наследуется всеми экземплярами, созданным из класса. Когда мы вызываем метод следующим способом x.display(123)
, метод display
сначала ищется в иерархии наследования и затем интерпретатор Python автоматически присваивает аргументу self
объект экземпляра x
. Далее разберемся для чего может пригодиться вызывать метод через имя класса, а не экземпляра.
Вызов метода через имя класса
Могла показаться ненужность вызова метода через класс:
TestClass.display(x)
Однако такой подход полезен в некоторых случаях: конструктор __init__
. На стадии конструирования интерпретатор Python ищет только один метод __init__
в иерархии наследования. Если нужна гарантия вызова подклассом (в примере SubClass
) конструктора суперкласса (в примере SuperClass
), то конструктор __init__
суперкласса нужно вызывать явно через имя класса:
class SuperClass:
def __init__(self, x) -> None:
pass
class SubClass(SuperClass):
def __init__(self, x, y) -> None:
SuperClass.__init__(self, x)
pass
x = SubClass(2, 3)
Думаю после этого урока вы уже полностью разобрались с атрибутами и методами классов Python. В следующем уроке еще раз поговорим про наследование и познакомимся с абстрактными суперклассами.
Тест
Похожие уроки Codebra
Подписывайся на наш Telegram-канал!
Новости, полезный материал,
программирование и ИБ
Подписывайся на наш Telegram-канал!
Новости, полезный материал,
программирование и ИБ