Объектно-ориентированное программирование. Специальные методы.
Содержание
- Статические и классовые методы
- Специальные методы (магические) вида _ < param > _
- Задачи:
- Задача 1:
- Задача 2:
Существуют 2 особенных декоратора, которые можно повесить на функции внутри класса: — @staticmethod — @classmethod
Декоратор @staticmethod определяет обычную функцию (статический метод) в пространстве имён класса. У него нет обязательного параметра-ссылки self. Может быть полезно для вспомогательных функций, чтобы не мусорить пространство имён модуля. Доступ к таким методам можно получить как из экземпляра класса, так и из самого класса:
class SomeClass(object): @staticmethod def hello(): print("Hello, world") SomeClass.hello() # Hello, world obj = SomeClass() obj.hello() # Hello, world
Hello, world Hello, world
Декоратор @classmethod создаёт метод класса и требует обязательную ссылку на класс (cls).
class SomeClass(object): @classmethod def hello(cls): print('Hello, класс {}'.format(cls.__name__)) SomeClass.hello() # Hello, класс SomeClass
Hello, класс SomeClass
Давайте взглянем на пример кода, в котором одновременно показаны она декоратора, это может помочь понять основные принципы:
class Person: def __init__(self, name, age): self.name = name self.age = age # classmethod чтобы создать объект по году рождения, # "альтернативный" конструктор @classmethod def fromBirthYear(cls, name, year): return cls(name, 2019 - year) # статический метод,чтобы проверить совершеннолетие @staticmethod def isAdult(age): return age > 18 person1 = Person('Петя', 21) person2 = Person. fromBirthYear('Петя', 1996) print(person1.age) print(person2.age) # print the result print(Person.isAdult(22))
21 23 True
Важно понимать, что ни classmethod ни staticmethod НЕ являются функциями от конкретного объекта класса и соответственно не принимают self. Подчеркнем еще раз их различия: — classmethod принимает cls как первый параметр, тогда как staticmethod в специальных аргументах не нуждается — classmethod может получать доступ или менять состояние класса, в то время как staticmethod нет — staticmethod в целом вообще ничего не знают про класс. Это просто функция над аргументами, объявленная внутри класса.
В Python существует огромное количество специальных методов, расширяющих возможности пользовательских классов. Например, можно определить вид объекта на печати, его «официальное» строковое представление или поведение при сравнениях.
Эти методы могут эмулировать поведение встроенных классов, но при этом они необязательно существуют у самих встроенных классов. Например, у объектов int при сложении не вызывается метод add. Таким образом, их нельзя переопределить.
Давайте для примера переопределим стандартную операцию сложения. Рассмотрим класс Vector, используемый для представления радиус-векторов на координатной плоскости, и определим в нем поля-координаты: x и y. Также очень хотелось бы определить для векторов операцию +, чтобы их можно было складывать столь же удобно, как и числа или строки.
Для этого необходимо перегрузить операцию +: определить функцию, которая будет использоваться, если операция + будет вызвана для объекта класса Vector. Для этого нужно определить метод add класса Vector, у которого два параметра: неявная ссылка self на экземпляр класса, для которого она будет вызвана (это левый операнд операции +) и явная ссылка other на правый операнд:
class Vector(): def __init__(self, x = 0, y = 0): self.x = x self.y = y def __add__(self, other): return Vector(self. x + other.x, self.y + other.y) A = Vector(1, 2) B = Vector(3, 4) C = A + B print(C.x, C.y)
4 6
Теперь при вызове оператора A + B Питон вызовет метод A.add(B), то есть вызовет указанный метод, где self = A, other = B.
Аналогично можно определить и оставшиеся операции. Полезной для
переопределения является операция <. Она должна возвращать логическое
значение True, если левый операнд меньше правого или False в противном
случае (также в том случае, если объекты равны). Для переопределения
этого операнда нужно определить метод
class Vector: def __lt__(self, other): return self.x < other.x or self.x == other.x and self.y < other.y
В этом примере оператор вернет True, если у левого операнда поле x меньше, чем у правого операнда, а также если поля x у них равны, а поле y меньше у левого операнда.
После определения оператора <, появляется возможность упорядочивать объекты, используя этот оператор. Теперь можно сортировать списки объектов при помощи метода sort() или функции sorted, при этом будет использоваться именно определенный оператор сравнения <.
Список основных перегружаемых операторов
Метод | Использование |
---|---|
Операторы сравнения | |
__lt__(self, other) | x < y |
__le__(self, other) | x <= y |
__eq__(self, other) | x == y |
__ne__(self, other) | x != y |
__gt__(self, other) | x > y |
__ge__(self, other) | x >= y |
Арифметические операторы | |
Сложение | |
__add__(self, other) | x + y |
__radd__(self, other) | y + x |
__iadd__(self, other) | x += y |
Вычитание | |
__sub__(self, other) | x — y |
__rsub__(self, other) | y — x |
__isub__(self, other) | x -= y |
Умножение | |
__mul__(self, other) | x * y |
__rmul__(self, other) | y * x |
__imul__(self, other) | x *= y |
Математическое умножение (например векторное) | |
__matmul__(self, other) | x @ y |
__rmatmul__(self, other) | y @ x |
__imatmul__(self, other) | x @= y |
Деление | |
__truediv__(self, other) | x / y |
__rtruediv__(self, other) | y / x |
__itruediv__(self, other) | x /= y |
Целочисленное деление | |
__floordiv__(self, other) | x // y |
__rfloordiv__(self, other) | y // x |
__ifloordiv__(self, other) | x //= y |
__divmod__(self, other) | divmod(x, y) |
Остаток | |
__mod__(self, other) | x % y |
__rmod__(self, other) | y % x |
__imod__(self, other) | x %= y |
Возведение в степень | |
__pow__(self, other) | x ** y |
__rpow__(self, other) | y ** x |
__ipow__(self, other) | x **= y |
Отрицание, модуль | |
__pos__(self) | +x |
__neg__(self) | -x |
__abs__(self) | abs(x) |
__len__(self) | len(x) |
Преобразование к стандартным типам | |
__int__(self) | int(x) |
__float__(self) | float(x) |
__complex__(self) | complex(x) |
__str__(self) | str(x) |
__round__(self, digits = 0) | round(x, digits) |
Блок with | |
__enter__(self) | |
__exit__(self) |
Задача 1:
Реализуйте свой класс Complex для комплексных чисел, аналогично встроенной реализации complex:
- Добавьте инициализатор класса
- Реализуйте основные математические операции
- Реализуйте операцию модуля (abs, вызываемую как |c|)
- Оба класса должны давать осмысленный вывод как при print, так и просто при вызове в ячейке
Задача 2:
- Создайте класс Vector с полями x, y, z определите для него конструктор, метод __str__, необходимые арифметические операции. Реализуйте конструктор, который принимает строку в формате «x,y».
- Программа получает на вход число N, далее координаты N точек. Доопределите в классе Vector недостающие операторы, найдите и выведите координаты точки, наиболее удаленной от начала координат.
- Используя класс Vector выведите координаты центра масс данного множества точек.
- Даны два вектора. Выведите площадь параллелограмма, построенного на заданных векторах.
- Даны три вектора. Выведите объём параллелепипеда, построенного на заданных векторах.
- Среди данных точек найдите три точки, образующие треугольник с наибольшим периметром. Выведите данный периметр.
- Среди данных точек найдите три точки, образующие треугольник с наибольшей площадью. Выведите данную площадь.
Специальные (магические) методы класса Python.
Класс может реализовывать определенные операции, которые вызываются специальным синтаксисом (например, арифметические операции или индексирование и срезы), определяя методы со специальными именами. Это подход Python к перегрузке операторов, позволяющий классам определять собственное поведение по отношению к операторам языка. Например, если класс определяет метод с именем __getitem__()
, а x
является экземпляром этого класса, то x[i]
примерно эквивалентен type(x).__getitem__(x, i)
. Если соответствующий метод не определен, то попытки выполнить операцию вызывают исключение (обычно AttributeError
или TypeError
).
Установка для специального метода значения None
означает, что соответствующая операция недоступна. Например, если класс устанавливает для __iter__()
значение None
, то класс не является итерируемым, поэтому вызов функции iter()
в его экземплярах вызовет ошибку TypeError
, без возврата к __getitem__()
.
При реализации класса, эмулирующего любой встроенный тип, важно, чтобы эмуляция была реализована только в той степени, в которой это имеет смысл для моделируемого объекта. Например, некоторые последовательности могут хорошо работать с извлечением отдельных элементов, но извлечение фрагмента среза может не иметь смысла. Одним из примеров этого является интерфейс NodeList
в объектной модели документа W3C.
Как и где использовать магические методы?
- Настройка классов Python магическими методами;
- Создание вычисляемых атрибутов класса;
- Создание дескрипторов класса в Python;
- Специальный атрибут
__slots__
в классах Python; - Специальный метод
__init_subclass__
класса Python; - Определение метаклассов;
- Эмуляция контейнерных типов в классах Python;
- Другие магические методы класса в Python.
Применение магических методов на примере
__getitem__()
.Представьте себе класс, который моделирует здание. В рамках данных для здания он включает в себя ряд атрибутов, включая описания компаний, которые занимают каждый этаж :
Без использования специального метода __getitem__()
получился бы такой класс:
class Building(object): def __init__(self, floors): self. _floors = [None]*floors def occupy(self, floor_number, data): self._floors[floor_number] = data def get_floor_data(self, floor_number): return self._floors[floor_number] # Строим здание с 4 этажами building = Building(4) building.occupy(0, 'Reception') building.occupy(1, 'ABC Corp') building.occupy(2, 'DEF Inc') print(building.get_floor_data(2))
Можно использовать магический метод __getitem__
и его аналог __setitem__
, чтобы сделать использование класса Building()
более приятным.
class Building(object): def __init__(self, floors): self._floors = [None]*floors def __setitem__(self, floor_number, data): self._floors[floor_number] = data def __getitem__(self, floor_number): return self._floors[floor_number] # Строим здание с 4 этажами building = Building(4) building[0] = 'Reception' building[1] = 'ABC Corp' building[2] = 'DEF Inc' print(building[2])
Используя в примере специальные методы __getitem__
и __setitem__
таким образом, мы решили рассматривать здание как контейнер этажей. Также можно реализовать итератор для класса Building()
и, возможно, даже взятие среза — то есть получать данные более чем с одного этажа за раз — это зависит от того, какие действия требуются от реализации конкретного класса.
4 обязательных специальных метода для Python | by Soner Yıldırım
Методы, которые необходимо реализовать в определяемых пользователем классах
Фото Доротеи ОЛДАНИ на UnsplashВсе в Python является объектом, и мы определяем объекты через классы. Когда мы определяем объект, мы фактически создаем экземпляр класса. Таким образом, класс — это самая фундаментальная часть Python.
Классы имеют:
- Атрибуты данных: Определите, что необходимо для создания экземпляра класса
- Методы (то есть процедурные атрибуты): определение того, как взаимодействовать с экземплярами класса
Мы можем создавать наши собственные классы, используя данные и процедурные атрибуты. Это наша игровая площадка, поэтому мы можем реализовать различные функции для настройки класса.
Помимо пользовательских функций, можно использовать встроенные функции Python в пользовательских классах. Для этого и существуют специальные (или магические) методы.
Специальные методы позволяют использовать встроенные функции Python для обогащения пользовательских классов. Рассмотрим функцию печати, которая является одной из наиболее часто используемых функций Python. Если вы используете его для печати экземпляра вашего класса, он напечатает что-то вроде следующего:
<__main__.Объект Book по адресу 0x7f9ed5b1d590>
Отображает имя класса (Book) и расположение объекта в памяти, что не является правильным использованием функции печати. Мы можем настроить его поведение, реализовав в нашем классе специальный метод __str__.
В этой статье мы рассмотрим 4 специальных метода, которые вы, вероятно, будете использовать на своих занятиях.
1. __init__
Специальный метод __init__ автоматически выполняется при создании экземпляра класса. Его также называют конструктором класса. Параметры __init__ представляют атрибуты данных класса.
Создадим класс Book.
класс Book(): def __init__(я, имя, писатель, страницы):
self.name = имя
self.writer = писатель
self.pages = страницы
Сам относится к самому экземпляру. Класс Book имеет 3 атрибута данных, которые необходимо указать при создании экземпляра Book.
b = Book("Моби Дик", "Герман Мелвилл", "378")type(b)
__main__.Book
Переменная b является экземпляром класса Book.
2. __str__
Мы используем специальный метод __str__ для реализации встроенной функции печати в нашем классе. Без __str__ вот что делает функция печати.
print(b)
<__main__.Объект Book по адресу 0x7f9ed5b1d590>
Давайте определим метод __str__ в нашем определении класса.
def __str__(self):
return f"Название книги {self.name}"
Теперь функция печати будет возвращать название имени. Он получает доступ к названию книги через атрибут name. Вы можете настроить его любым удобным для вас способом.
print(b)
Книга называется "Моби Дик"
3. __len__
Функция len возвращает длину объекта. Для строк возвращает количество символов. Для фрейма данных Pandas он возвращает номер строки.
Мы можем настроить его поведение, реализовав специальный метод __len__ в нашем определении класса. Давайте сделаем так, чтобы он возвращал количество страниц объекта книги.
Если __len__ не реализован в определении класса, вы получите сообщение об ошибке, если попытаетесь использовать его для объекта вашего класса. У него нет поведения по умолчанию, как у функции печати.
def __len__(self):
return int(self.pages)len(b)
378
Обратите внимание, что каждый раз, когда вы добавляете новую функцию в свой класс, вам необходимо заново создавать объект, чтобы иметь возможность использовать новые функции.
4. __eq__
Специальный метод __eq__ позволяет сравнивать два экземпляра класса. Если он определен в нашем классе, мы можем проверить, равен ли экземпляр другому экземпляру. Условие равенства задается с помощью метода __eq__.
В нашем случае мы можем объявить две книги равными, если имена и авторы книги совпадают. Они могут иметь разное количество страниц.
def __eq__(self, other):
return (self.name == other.name) & (self.writer == other.writer)
Оператор «==» вернет True, если и имена, и записи то же самое для двух экземпляров. Давайте создадим две книги и проверим, равны ли они.
b = Book("Моби Дик", "Герман Мелвилл", "378")a = Book("Моби Дик", "Герман Мелвилл", "410")b == a
True
Если либо имена, либо пишет отличается, оператор равенства возвращает False.
b = Книга("Моби Дик", "Герман Мелвилл", "378")a = Книга("Моби Дик", "Мелвилл", "410")b == a
False
Заключение
Объекты лежат в основе Python, поэтому создание надежных, функциональных и хорошо спроектированных классов имеет решающее значение. Мы рассмотрели 4 специальных метода, которые вам нужно будет реализовать в ваших собственных классах.
Спасибо, что прочитали. Пожалуйста, дайте мне знать, если у вас есть какие-либо отзывы.
Special Methods in Python OOP by Samer Sallam
Узнайте, что такое специальный метод и как его переопределить в Python.
Фото Эмиля Перрона на UnsplashПрежде чем мы начнем, позвольте мне сказать вам, что:
- Эта статья является частью Полного курса объектно-ориентированного программирования на Python, который вы можете найти здесь.
- Все ресурсы доступны в разделе «Ресурсы» ниже.
- Эта статья также доступна здесь в виде видео на YouTube.
Введение
До сих пор мы видели, что мы используем специальные методы для определения действий, которые должны выполняться, когда операторы используются с объектами пользователя. определенные классы.
Но подождите, иногда мы называем их специальными методами, а иногда мы называем их магическими методами или dunder методами. Итак, что это за термины?
Если вы заинтересованы в изучении этих новых концепций, продолжайте читать…
Содержание
- Что такое специальные методы?
- Методы Дандера и магические методы
- Как переопределить специальные методы?
1. Что такое специальные методы?
Специальные методы — это методы, которые не предназначены для непосредственного вызова вами. Другими словами, вы не будете вызывать эти методы явно. Однако вызов происходит внутри и вне сцены из класса, когда происходит определенное действие. Это действие может заключаться в использовании оператора вроде (+ — * /) между двумя объектами класса.
Теперь вопрос в том, какое поведение должно выполняться в этом случае?
Будь то оператор «плюс» или любой другой, для каждого из этих операторов существует метод определения того, что произойдет при использовании этого оператора, и хорошая новость заключается в том, что вы можете переопределить или переопределить его.
Переопределяя этот метод, вы определяете действие, которое должно выполняться при использовании этого оператора.
Примечание : специальные методы на самом деле не ограничиваются только операторами, но охватывают другие встроенные функции Python, такие как, например, функции типов данных (str, int, dir…).
Например, когда вы используете функцию str()
с объектом вашего класса, вы конвертируете этот объект в строку. Но преобразование объекта в строку иногда бывает странным, потому что в этом нет смысла.
Вы можете сделать это преобразование более осмысленным, переопределив специальный метод, представляющий это преобразование в строку.
Чтобы упростить задачу, давайте посмотрим на реальный пример этих специальных методов:
-
__init__
: используется для инициализации атрибутов экземпляра начальными значениями. Как вы видели ранее, он автоматически вызывается, когда вы определяете объект из своего класса (событием в данном случае является определение нового объекта). -
__str__
: этот метод вызывается автоматически, когда вы используете функциюstr()
с объектом вашего класса (в данном случае событием является вызовstr
с объектом в качестве входных данных).
До сих пор было представлено определение специальных методов. Теперь возникает вопрос: к чему относятся методы dunder и магические методы ?
Photo by Mert Talay on Unsplash2. Методы Дандера и магические методы
В сообществе Python Специальные методы известны как Методы Дандера.
Он называется dunder , потому что, как вы видели из двух предыдущих примеров, эти методы имеют следующее соглашение об именах :
__special_method_name__
Обычно он называется под
, вместо двойного подчеркивания . По этой причине эти специальные методы называются также методами Дандера.
Кроме того, не удивляйтесь, что иногда эти методы также называют магическими методами.
Короче говоря, даже если вы скажете специальные методы , методы dunder или магические методы , все эти понятия относятся к одному и тому же понятию. Теперь давайте узнаем, как переопределить эти специальные методы.
Photo by Sigmund on Unsplash3. Как переопределить специальные методы?
Предположим, что у вас есть класс ClassName
. Чтобы переопределить любой специальный метод, вы должны определить этот специальный метод, как любой обычный метод в Python, следующим образом:0005
class ClassName:
def __specialmethod__(self):
pass
Примечание: вы должны быть осторожны с его именем, потому что имена этих специальных методов зарезервированы в Python.
Как только вы определите специальный метод, класс поймет, что этот метод будет вызываться автоматически, когда произойдет действие, с которым связан этот метод.
Круто, правда?
Фото Бретта Джордана на Unsplash Теперь давайте продолжим и напишем несколько кодов, чтобы лучше понять идею. Предположим, что у нас есть Класс Student
с некоторыми атрибутами экземпляра (id, first_name, last_name,….)
и одним методом экземпляра enrol()
.
Определим объект из Student
class:
student = Student('John', 'Doe', 25)
Затем вызовите функцию dir() для этого объекта:
dir(student )
Вывод:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__','__format__','__ge__','__getattribute__','__gt__','__hash__','__init__','__init_subclass__','__le___','__lt ,'__module__','__ne__','__new__','__reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__str__','__subclasshook__','__weakref__', 'возраст', 'classes', 'enrol', 'first_name', 'full_name', 'id', 'last_name']методы, которые у вас есть внутри
Ученик
класса. Кроме того, существуют другие имена, такие как ( __class__
, __delatter__
, …), где все эти имена являются специальными именами, и они появляются из-за наследования между классом Student
и классом Object
.В Python все классы неявно наследуют класс Object (подробнее об этом вы узнаете позже в этом курсе).
В заключение вы должны знать, что есть некоторые специальные методы, которые уже доступны и предопределены для каждого класса в Python по умолчанию .
Теперь попробуем вызвать метод str()
для объекта student
.
str(student)
Вывод:
<__main__.Student object at 0x000001E22C2EA448>
Число в предыдущем выводе представляет ячейку памяти, в которой объект студента сохранен. Эта строка очень некрасивая. Итак, давайте переопределим этот метод, чтобы вывести более репрезентативное значение для объекта student
.
Предположим, вы хотите, чтобы метод __str__
возвращал предложение вроде:
- Первый случай: «Я объект класса Студент»
- Второй случай: «Я объект класса Студент, мое имя is object_first_name `
Первый случай: относится к последнему методу в следующем фрагменте кода.
Вывод:
Я объект класса Студент.
Второй вариант ввода:
Подсказка:
- Вы можете получить доступ и использовать атрибуты объекта, вызывающего специальный метод, используя ключевое слово self в определении вашего специального метода. Обратитесь к последнему методу в следующем фрагменте кода.
Вывод:
Я объект класса Студент, Меня зовут Джон
Из этого простого примера мы можем понять, что переопределение метода __str__
меняет поведение функции str()
, когда она вызывается с объектом из нашего класса, которым в данном случае является Student
.
Теперь давайте обобщим то, что мы узнали в этой статье:
Photo by Ann H на pexels- Специальные методы: — это методы, которые не предназначены для непосредственного вызова вами, но вызов происходит внутри от класса на определенное действие.
- Специальные методы, метод Дандера и магические методы — три термина, взаимозаменяемо обозначающие одно и то же.
- Вы можете переопределить специальные методы, определив их как любые другие методы в Python, и будьте осторожны, чтобы использовать правильное зарезервированное имя в Python.
П.С. : Миллион благодарностей за то, что уделили время чтению моей истории. Прежде чем вы уйдете, позвольте мне быстро упомянуть два момента:
- Во-первых, чтобы получать мои сообщения непосредственно в ваш почтовый ящик, не могли бы вы подписаться здесь , и вы можете подписаться на меня здесь .