Объект класса в Python представляет собой ИМЯ класса, созданного (определенного/записанного) в коде. Объекты класса поддерживают два вида операций: ссылки на атрибуты и создание экземпляров.
Ссылки на атрибуты используют стандартный синтаксис, используемый для всех ссылок на атрибуты в Python: obj.name
. Допустимые имена атрибутов - это все имена, которые были определены в пространстве имен класса при создании объекта класса.
Итак, если определение класса выглядит так:
class MyClass: """Простой пример класса""" i = 12345 def f(self): return 'hello world' # `MyClass` - это объект класса >>> MyClass.i # 12345 >>> MyClass.f # <function MyClass.f at 0x7f3c1fd6e840>
то имя MyClass
- это объект класса, а MyClass.i
и MyClass.f
являются действительными ссылками на атрибуты класса, возвращая целое число и функциональный объект соответственно. Атрибуты объекта класса также могут быть присвоены, так что можно изменить значение MyClass.i
путем операции присвоения. __doc__
также является допустимым атрибутом, возвращающим строку документации "Простой пример класса"
, принадлежащую классу MyClass
.
Экземпляр класса использует нотацию функций. Представьте, что объект класса - это функция без параметров, которая возвращает новый экземпляр класса. Пример ниже создает новый экземпляр класса и присваивает этот объект локальной переменной x
:
x = MyClass() >>> x.i # 12345 >>> x.f() # 'hello world'
__init__()
.Объекты классов обычно создают с экземплярами, настроенными на определенное начальное состояние. Для этого в классе Python определятся специальный метод "конструктор класса" с именем __init__()
, который выполняется при создании экземпляра класса. Метод .__init__()
принимает новый объект в качестве первого аргумента self
.
class MyClass: """Простой пример класса""" i = 12345 def __init__(self): self.data = [] def f(self): return 'hello world'
Когда в классе определен метод .__init__()
, то экземпляр класса автоматически вызывает .__init__()
для вновь созданного экземпляра класса. Таким образом, в примере ниже, новый инициализированный экземпляр может быть получен с помощью:
>>> x = MyClass() >>> x.data # []
Метод __init__()
может иметь аргументы для большей гибкости. В этом случае аргументы, переданные оператору создания класса, передаются в метод __init__()
.
Например:
>>> class Complex: ... def __init__(self, realpart, imagpart): ... self.r = realpart ... self.i = imagpart ... >>> x = Complex(3.0, -4.5) >>> x.r, x.i (3.0, -4.5)
Важно отметить, что без учета self
, аргументы метода .__init__()
- это те же самые аргументы, которые передаются при вызове конструктора класса. Таким образом, сигнатура .__init__()
определяет сигнатуру конструктора класса.
Имейте в виду, что конструктор класса .__init__()
не должен явно возвращать ничего отличного от None
, иначе будет вызываться исключение TypeError
:
>>> class Complex: ... def __init__(self, realpart, imagpart): ... self.r = realpart ... self.i = imagpart ... return realpart + imagpart >>> x = Complex(3.0, -4.5) # Traceback (most recent call last): # File "<stdin>", line 1, in <module> # TypeError: __init__() should return None, not 'float'
В конструкторе класса .__init__()
можно выполнить любое преобразование входных аргументов, чтобы правильно инициализировать атрибуты экземпляра. Например, если пользователи будут использовать класс Rectangle
, то например, можно проверить предоставленные ширину и высоту, для того, чтобы убедиться в их верном значении:
>>> class Rectangle: ... def __init__(self, width, height): ... if not (isinstance(width, (int, float)) and width > 0): ... raise ValueError(f"Необходима положительная ширина, получена: {width}") ... self.width = width ... if not (isinstance(height, (int, float)) and height > 0): ... raise ValueError(f"Необходима положительная высота, получена: {height}") ... self.height = height >>> rectangle = Rectangle(-21, 42) # Traceback (most recent call last): # File "<stdin>", line 1, in <module> # File "<stdin>", line 4, in __init__ # ValueError: Необходима положительная ширина, получена: -21
Теперь предположим, что используется наследование для создания пользовательской иерархии классов и повторного использования некоторых функций в своем коде. Если подклассы предоставляют конструктор .__init__()
, то он должен явно вызывать метод .__init__()
базового класса с соответствующими аргументами, чтобы обеспечить правильную инициализацию экземпляров. Для этого необходимо использовать встроенную функцию super()
, как в следующем примере:
>>> class Person: ... def __init__(self, name, birth_date): ... self.name = name ... self.birth_date = birth_date >>> class Employee(Person): ... def __init__(self, name, birth_date, position): ... super().__init__(name, birth_date) ... self.position = position >>> john = Employee("John Doe", "2001-02-07", "Разработчик Python") >>> john.name # 'John Doe' >>> john.birth_date # '2001-02-07' >>> john.position # 'Разработчик Python'