Содержание
Краткая памятка по созданию объектов в Python
- Определите класс с помощью ключевого слова class.
- Реализуйте метод __init__ для инициализации атрибутов.
- Используйте self для доступа к атрибутам экземпляра.
- Создайте объект, вызвав класс с аргументами: MyClass(args).
- Примените инкапсуляцию для защиты данных.
- Используйте наследование для расширения функциональности.
- Переопределяйте методы для изменения поведения.
- Применяйте полиморфизм для работы с разными классами.
- Удаляйте объекты с помощью del или сборщика мусора.
- Используйте свойства (property) для управления доступом.
- Определяйте приватные атрибуты с двойным подчеркиванием.
- Изучите встроенные атрибуты класса, такие как __doc__.
Создание классов и объектов
Для того чтобы создать объект класса необходимо воспользоваться следующим синтаксисом:
Методы класса
Добавим к нашему классу метод. Метод – это функция, находящаяся внутри класса и выполняющая определенную работу.
Методы бывают статическими, классовыми (среднее между статическими и обычными) и уровня класса (будем их называть просто словом метод). Статический метод создается с декоратором @staticmethod, классовый – с декоратором @classmethod, первым аргументом в него передается cls, обычный метод создается без специального декоратора, ему первым аргументом передается self:
Статический и классовый метод можно вызвать, не создавая экземпляр класса, для вызова ex_method() нужен объект:
>>> MyClass.ex_static_method() static method >>> MyClass.ex_class_method() class method >>> MyClass.ex_method() Traceback (most recent call last): File «<stdin>», line 1, in <module> TypeError: ex_method() missing 1 required positional argument: ‘self’ >>> m = MyClass() >>> m.ex_method() method
Поддержка получения произвольных атрибутов методами.
Связанные методы имеют два специальных атрибута, доступных только для чтения: m.__ self__ — это объект, с которым работает метод, и m.__func__ — это функция, реализующая метод. Вызов m(arg-1, arg-2,…, arg-n) полностью эквивалентен вызову m.__func__(m.__self__, arg-1, arg-2,…, arg-n).
Как и объекты функций, связанные объекты методов поддерживают получение произвольных атрибутов. Однако, поскольку атрибуты метода фактически хранятся в базовом объекте функции (meth.__func__), то установка атрибутов метода для связанных методов запрещена. Попытка установить атрибут в методе приводит к возникновению исключения AttributeError. Чтобы установить атрибут метода, необходимо явно установить его для базового объекта функции:
>>> class C:… def method(self):… pass… >>> c = C() >>> = ‘my name is method’ # can’t set on the method # Traceback (most recent call last): # File «<stdin>», line 1, in <module> # AttributeError: ‘method’ object has no attribute ‘whoami’ >>>.__func__.whoami = ‘my name is method’ >>> # ‘my name is method’
Конструктор класса и инициализация экземпляра класса
В Python разделяют конструктор класса и метод для инициализации экземпляра класса. Конструктор класса это метод __new__(cls, *args, **kwargs) для инициализации экземпляра класса используется метод __init__(self). При этом, как вы могли заметить __new__ – это классовый метод, а __init__ таким не является. Метод __new__ редко переопределяется, чаще используется реализация от базового класса object (см. раздел Наследование), __init__ же наоборот является очень удобным способом задать параметры объекта при его создании.
Создадим реализацию класса Rectangle с измененным конструктором и инициализатором, через который задается ширина и высота прямоугольника:
class Rectangle: def __new__(cls, *args, **kwargs): print(«Hello from __new__») return super().__new__(cls) def __init__(self, width, height): print(«Hello from __init__») = width = height >>> rect = Rectangle(10, 20) Hello from __new__ Hello from __init__ >>> 10 >>> 20
Что такое self?
До этого момента вы уже успели познакомиться с ключевым словом self. self – это ссылка на текущий экземпляр класса, в таких языках как Java, C# аналогом является ключевое слово this. Через self вы получаете доступ к атрибутам и методам класса внутри него:
В приведенной реализации метод area получает доступ к атрибутам width и height для расчета площади. Если бы в качестве первого параметра не было указано self, то при попытке вызвать area программа была бы остановлена с ошибкой.
Создание экземпляров класса
Чтобы создать экземпляры классов, нужно вызвать класс с использованием его имени и передать аргументы, которые принимает метод __init__.
Доступ к атрибутам
Получите доступ к атрибутам класса, используя оператор. после объекта класса. Доступ к классу можно получить используя имя переменой класса:
class Employee: «»»Базовый класс для всех сотрудников»»» emp_count = 0 def __init__(self, name, salary): = name = salary Employee.emp_count += 1 def display_count(self): print(‘Всего сотрудников: %d’ % Employee.emp_count) def display_employee(self): print(‘Имя: {}. Зарплата: {}’.format(,)) emp1 = Employee(«Андрей», 2000) emp2 = Employee(«Мария», 5000) emp1.display_employee() emp2.display_employee() print(«Всего сотрудников: %d» % Employee.emp_count)
Вместо использования привычных операторов для доступа к атрибутам вы можете использовать эти функции:
- getattr(obj, name [, default]) — для доступа к атрибуту объекта.
- hasattr(obj, name) — проверить, есть ли в obj атрибут name.
- setattr(obj, name, value) — задать атрибут. Если атрибут не существует, он будет создан.
- delattr(obj, name) — удалить атрибут.
hasattr(emp1, ‘age’) getattr(emp1, ‘age’) setattr(emp1, ‘age’, 8) delattr(empl, ‘age’)
Встроенные атрибуты класса
Каждый класс Python хранит встроенные атрибуты, и предоставляет к ним доступ через оператор., как и любой другой атрибут:
- __dict__ — словарь, содержащий пространство имен класса.
- __doc__ — строка документации класса. None если, документация отсутствует.
- __name__ — имя класса.
- __module__ — имя модуля, в котором определяется класс. Этот атрибут __main__ в интерактивном режиме.
- __bases__ — могут быть пустые tuple, содержащие базовые классы, в порядке их появления в списке базового класса.
Для вышеуказанного класса давайте попробуем получить доступ ко всем этим атрибутам:
class Employee: «»»Базовый класс для всех сотрудников»»» emp_count = 0 def __init__(self, name, salary): = name = salary += 1 def display_count(self): print(‘Всего сотрудников: %d’ %) def display_employee(self): print(‘Имя: {}. Зарплата: {}’.format(,)) print(«Employee.__doc__:», Employee.__doc__) print(«Employee.__name__:», Employee.__name__) print(«Employee.__module__:», Employee.__module__) print(«Employee.__bases__:», Employee.__bases__) print(«Employee.__dict__:», Employee.__dict__)
Удаление объектов (сбор мусора)
Python автоматически удаляет ненужные объекты (встроенные типы или экземпляры классов), чтобы освободить пространство памяти. С помощью процесса ‘Garbage Collection’ Python периодически восстанавливает блоки памяти, которые больше не используются.
Сборщик мусора Python запускается во время выполнения программы и тогда, когда количество ссылок на объект достигает нуля. С изменением количества обращений к нему, меняется количество ссылок.
Когда объект присваивают новой переменной или добавляют в контейнер (список, кортеж, словарь), количество ссылок объекта увеличивается. Количество ссылок на объект уменьшается, когда он удаляется с помощью del, или его ссылка выходит за пределы видимости. Когда количество ссылок достигает нуля, Python автоматически собирает его.
Обычно вы не заметите, когда сборщик мусора уничтожает экземпляр и очищает свое пространство. Но классом можно реализовать специальный метод __del__(), называемый деструктором. Он вызывается, перед уничтожением экземпляра. Этот метод может использоваться для очистки любых ресурсов памяти.
Пример работы __del__()Деструктор __del__() выводит имя класса того экземпляра, который должен быть уничтожен:
class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print(‘{} уничтожен’.format(class_name)) pt1 = Point() pt2 = pt1 pt3 = pt1 print(id(pt1), id(pt2), id(pt3)) del pt1 del pt2 del pt3
В идеале вы должны создавать свои классы в отдельном модуле. Затем импортировать их в основной модуль программы с помощью import SomeClass.
Уровни доступа атрибута и метода
Если вы знакомы с языками программирования Java, C#, C++ то, наверное, уже задались вопросом: “а как управлять уровнем доступа?”. В перечисленных языка вы можете явно указать для переменной, что доступ к ней снаружи класса запрещен, это делается с помощью ключевых слов (private, protected и т.д.). В Python таких возможностей нет, и любой может обратиться к атрибутам и методам вашего класса, если возникнет такая необходимость. Это существенный недостаток этого языка, т.к. нарушается один из ключевых принципов ООП – инкапсуляция. Хорошим тоном считается, что для чтения/изменения какого-то атрибута должны использоваться специальные методы, которые называются getter/setter, их можно реализовать, но ничего не помешает изменить атрибут напрямую. При этом есть соглашение, что метод или атрибут, который начинается с нижнего подчеркивания, является скрытым, и снаружи класса трогать его не нужно (хотя сделать это можно).
class Rectangle: def __init__(self, width, height): self._width = width self._height = height def get_width(self): return self._width def set_width(self, w): self._width = w def get_height(self): return self._height def set_height(self, h): self._height = h def area(self): return self._width * self._height
В приведенном примере для доступа к _width и _height используются специальные методы, но ничего не мешает вам обратиться к ним (атрибутам) напрямую.
Если же атрибут или метод начинается с двух подчеркиваний, то тут напрямую вы к нему уже не обратитесь (простым образом). Модифицируем наш класс Rectangle:
class Rectangle: def __init__(self, width, height): self.__width = width self.__height = height def get_width(self): return self.__width def set_width(self, w): self.__width = w def get_height(self): return self.__height def set_height(self, h): self.__height = h def area(self): return self.__width * self.__height
>>> rect = Rectangle(10, 20) >>> rect.__width Traceback (most recent call last): File «<stdin>», line 1, in <module> AttributeError: ‘Rectangle’ object has no attribute ‘__width’ >>> rect.get_width() 10
Но на самом деле это сделать можно, просто этот атрибут теперь для внешнего использования носит название: _Rectangle__width:
Приватные методы и атрибуты
Атрибуты класса могут быть не видимыми вне определения класса. Вам нужно указать атрибуты с __ вначале, и эти атрибуты не будут вызваны вне класса.
class JustCounter: __secret_count = 0 def count(self): self.__secret_count += 1 print(self.__secret_count) counter = JustCounter() () () print(counter.__secret_count)
Вы можете получить доступ к таким атрибутам, так object._className__attrName. Если вы замените свою последнюю строку следующим образом, то она будет работать.
Свойства
Свойством называется такой метод класса, работа с которым подобна работе с атрибутом. Для объявления метода свойством необходимо использовать декоратор @property.
Важным преимуществом работы через свойства является то, что вы можете осуществлять проверку входных значений, перед тем как присвоить их атрибутам.
class Rectangle: def __init__(self, width, height): self.__width = width self.__height = height @property def width(self): return self.__width @ def width(self, w): if w > 0: self.__width = w else: raise ValueError @property def height(self): return self.__height @ def height(self, h): if h > 0: self.__height = h else: raise ValueError def area(self): return self.__width * self.__height
Если вы обратили внимание: в setter’ах этих свойств осуществляется проверка входных значений, если значение меньше нуля, то будет выброшено исключение ValueError:
В организации наследования участвуют как минимум два класса: класс родитель и класс потомок. При этом возможно множественное наследование, в этом случае у класса потомка может быть несколько родителей. Не все языки программирования поддерживают множественное наследование, но в Python можно его использовать. По умолчанию все классы в Python являются наследниками от object, явно этот факт указывать не нужно.
class Figure: def __init__(self, color): self.__color = color @property def color(self): return self.__color @ def color(self, c): self.__color = c class Rectangle(Figure): def __init__(self, width, height, color): super().__init__(color) self.__width = width self.__height = height @property def width(self): return self.__width @ def width(self, w): if w > 0: self.__width = w else: raise ValueError @property def height(self): return self.__height @ def height(self, h): if h > 0: self.__height = h else: raise ValueError def area(self): return self.__width * self.__height
Родительским классом является Figure, который при инициализации принимает цвет фигуры и предоставляет его через свойства. Rectangle – класс наследник от Figure. Обратите внимание на его метод __init__: в нем первым делом вызывается конструктор (хотя это не совсем верно, но будем говорить так) его родительского класса:
super – это ключевое слово, которое используется для обращения к родительскому классу.
Теперь у объекта класса Rectangle помимо уже знакомых свойств width и height появилось свойство color:
Как уже было сказано во введении в рамках ООП полиморфизм, как правило, используется с позиции переопределения методов базового класса в классе наследнике. Проще всего это рассмотреть на примере. Добавим в наш базовый класс метод info(), который печатает сводную информацию по объекту класса Figure и переопределим этот метод в классе Rectangle, добавим в него дополнительные данные:
class Figure: def __init__(self, color): self.__color = color @property def color(self): return self.__color @ def color(self, c): self.__color = c def info(self): print(«Figure») print(«Color: » + self.__color) class Rectangle(Figure): def __init__(self, width, height, color): super().__init__(color) self.__width = width self.__height = height @property def width(self): return self.__width @ def width(self, w): if w > 0: self.__width = w else: raise ValueError @property def height(self): return self.__height @ def height(self, h): if h > 0: self.__height = h else: raise ValueError def info(self): print(«Rectangle») print(«Color: » +) print(«Width: » + str()) print(«Height: » + str()) print(«Area: » + str(())) def area(self): return self.__width * self.__height
Наследование
Наследование — это процесс, когда один класс наследует атрибуты и методы другого. Класс, чьи свойства и методы наследуются, называют Родителем или Суперклассом. А класс, свойства которого наследуются — класс-потомок или Подкласс.
Вместо того, чтобы начинать с нуля, вы можете создать класс, на основе уже существующего. Укажите родительский класс в круглых скобках после имени нового класса.
Класс наследник наследует атрибуты своего родительского класса. Вы можете использовать эти атрибуты так, как будто они определены в классе наследнике. Он может переопределять элементы данных и методы родителя.
Синтаксис наследования класса
Классы наследники объявляются так, как и родительские классы. Только, список наследуемых классов, указан после имени класса.
Пример наследования класса в Python
class Parent: parent_attr = 100 def __init__(self): print(‘Вызов родительского конструктора’) def parent_method(self): print(‘Вызов родительского метода’) def set_attr(self, attr): Parent.parent_attr = attr def get_attr(self): print(‘Атрибут родителя: {}’.format(Parent.parent_attr)) class Child(Parent): def __init__(self): print(‘Вызов конструктора класса наследника’) def child_method(self): print(‘Вызов метода класса наследника’) c = Child() c.child_method() c.parent_method() c.set_attr(200) c.get_attr()
Аналогичным образом вы можете управлять классом с помощью нескольких родительских классов:
Вы можете использовать функции issubclass() или isinstance() для проверки отношений двух классов и экземпляров.
- Логическая функция issubclass(sub, sup) возвращает значение True, если данный подкласс sub действительно является подклассом sup.
- Логическая функция isinstance(obj, Class) возвращает True, если obj является экземпляром класса Class или является экземпляром подкласса класса.
Переопределение методов
Вы всегда можете переопределить методы родительского класса. В вашем подклассе могут понадобиться специальные функции. Это одна из причин переопределения родительских методов.
class Parent: def my_method(self): print(‘Вызов родительского метода’) class Child(Parent): def my_method(self): print(‘Вызов метода наследника’) c = Child() c.my_method()
Полиморфизм
Полиморфизм позволяет одинаково обращаться с объектами, имеющими однотипный интерфейс, независимо от внутренней реализации объекта. Например, с объектом класса “грузовой автомобиль” можно производить те же операции, что и с объектом класса “автомобиль”, т.к. первый является наследником второго, при этом обратное утверждение неверно (во всяком случае не всегда). Другими словами полиморфизм предполагает разную реализацию методов с одинаковыми именами. Это очень полезно при наследовании, когда в классе наследнике можно переопределить методы класса родителя.
Популярные базовые методы
В данной таблице перечислены некоторые общие функции. Вы можете переопределить их в своих собственных классах.
Таблица №1
| № | Метод, описание и пример вызова |
|---|---|
| 1 | __init__(self [, args...]) — конструктор (с любыми необязательными аргументами)obj = className(args) |
| 2 | __del__(self) — деструктор, удаляет объектdel obj |
| 3 | __repr__(self) — программное представление объектаrepr(obj) |
| 4 | __str__(self) — строковое представление объектаstr(obj) |
Пример использования __add__
Предположим, вы создали класс Vector для представления двумерных векторов. Что происходит, когда вы используете дополнительный оператор для их добавления? Скорее всего, Python будет против.
Однако вы можете определить метод __add__ в своем классе для добавления векторов и оператор + будет вести себя так как нужно.
class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return ‘Vector ({}, {})’.format(self.a, self.b) def __add__(self, other): return Vector(self.a + other.a, self.b + other.b) v1 = Vector(2, 10) v2 = Vector(5, -2) print(v1 + v2)
P.S.
Если вам интересна тема анализа данных, то мы рекомендуем ознакомиться с библиотекой Pandas. На нашем сайте вы можете найти вводные уроки по этой теме.
Все уроки по библиотеке Pandas собраны в книге “Pandas. Работа с данными”.
Часто задаваемые вопросы о методах создания объектов в Python
Вопрос: Какой метод класса в Python создает объект?
Ответ: Объект создается с помощью конструктора __init__, который вызывается автоматически при создании экземпляра класса.
Вопрос: В чем разница между __new__ и __init__?
Ответ: __new__ создает новый объект, а __init__ инициализирует его атрибуты.
Вопрос: Обязательно ли определять __init__ в классе?
Ответ: Нет, если не требуется инициализация, Python создаст объект без него.
Вопрос: Можно ли создать объект без вызова конструктора?
Ответ: Да, через __new__ напрямую, но это редко используется.
Вопрос: Как передать аргументы в конструктор класса?
Ответ: Через параметры метода __init__, например: def __init__(self, name).
Вопрос: Что такое self в конструкторе?
Ответ: self — ссылка на текущий экземпляр класса, передается автоматически.
Вопрос: Может ли конструктор возвращать значение?
Ответ: Нет, __init__ должен возвращать None.
Вопрос: Как создать объект с атрибутами по умолчанию?
Ответ: Задать значения в __init__ через параметры по умолчанию.
Вопрос: Что произойдет, если не определить __init__?
Ответ: Python использует конструктор по умолчанию, который не инициализирует атрибуты.
Вопрос: Как вызвать конструктор родительского класса?
Ответ: Через super().__init__() в дочернем классе.

























