Перейти к содержимому

Как переопределить метод в python

  • автор:

Перегрузка операторов

Python 3 логотип

Перегрузка операторов — один из способов реализации полиморфизма, когда мы можем задать свою реализацию какого-либо метода в своём классе.

Например, у нас есть два класса:

 В данном примере класс B наследует класс A, но переопределяет метод go, поэтому он имеет мало общего с аналогичным методом класса A.

Однако в python имеются методы, которые, как правило, не вызываются напрямую, а вызываются встроенными функциями или операторами.

Например, метод __init__ перегружает конструктор класса. Конструктор — создание экземпляра класса.

 

__new__(cls[, . ]) — управляет созданием экземпляра. В качестве обязательного аргумента принимает класс (не путать с экземпляром). Должен возвращать экземпляр класса для его последующей его передачи методу __init__.

__init__(self[, . ]) - как уже было сказано выше, конструктор.

__del__(self) - вызывается при удалении объекта сборщиком мусора.

__repr__(self) - вызывается встроенной функцией repr; возвращает "сырые" данные, использующиеся для внутреннего представления в python.

__str__(self) - вызывается функциями str, print и format. Возвращает строковое представление объекта.

__bytes__(self) - вызывается функцией bytes при преобразовании к байтам.

__format__(self, format_spec) - используется функцией format (а также методом format у строк).

__le__(self, other) - x ≤ y вызывает x.__le__(y).

__eq__(self, other) - x == y вызывает x.__eq__(y).

__ne__(self, other) - x != y вызывает x.__ne__(y)

__gt__(self, other) - x > y вызывает x.__gt__(y).

__ge__(self, other) - x ≥ y вызывает x.__ge__(y).

__hash__(self) - получение хэш-суммы объекта, например, для добавления в словарь.

__bool__(self) - вызывается при проверке истинности. Если этот метод не определён, вызывается метод __len__ (объекты, имеющие ненулевую длину, считаются истинными).

__getattr__(self, name) - вызывается, когда атрибут экземпляра класса не найден в обычных местах (например, у экземпляра нет метода с таким названием).

__setattr__(self, name, value) - назначение атрибута.

__delattr__(self, name) - удаление атрибута (del obj.name).

__call__(self[, args. ]) - вызов экземпляра класса как функции.

__len__(self) - длина объекта.

__getitem__(self, key) - доступ по индексу (или ключу).

__setitem__(self, key, value) - назначение элемента по индексу.

__delitem__(self, key) - удаление элемента по индексу.

__iter__(self) - возвращает итератор для контейнера.

__reversed__(self) - итератор из элементов, следующих в обратном порядке.

__contains__(self, item) - проверка на принадлежность элемента контейнеру (item in self).

Перегрузка арифметических операторов

__add__(self, other) - сложение. x + y вызывает x.__add__(y).

__sub__(self, other) - вычитание (x - y).

__mul__(self, other) - умножение (x * y).

__truediv__(self, other) - деление (x / y).

__floordiv__(self, other) - целочисленное деление (x // y).

__mod__(self, other) - остаток от деления (x % y).

__divmod__(self, other) - частное и остаток (divmod(x, y)).

__pow__(self, other[, modulo]) - возведение в степень (x ** y, pow(x, y[, modulo])).

__lshift__(self, other) - битовый сдвиг влево (x

__rshift__(self, other) - битовый сдвиг вправо (x >> y).

__and__(self, other) - битовое И (x & y).

__xor__(self, other) - битовое ИСКЛЮЧАЮЩЕЕ ИЛИ (x ^ y).

__or__(self, other) - битовое ИЛИ (x | y).

__radd__(self, other),

__rsub__(self, other),

__rmul__(self, other),

__rtruediv__(self, other),

__rfloordiv__(self, other),

__rmod__(self, other),

__rdivmod__(self, other),

__rpow__(self, other),

__rlshift__(self, other),

__rrshift__(self, other),

__rand__(self, other),

__rxor__(self, other),

__ror__(self, other) - делают то же самое, что и арифметические операторы, перечисленные выше, но для аргументов, находящихся справа, и только в случае, если для левого операнда не определён соответствующий метод.

Например, операция x + y будет сначала пытаться вызвать x.__add__(y), и только в том случае, если это не получилось, будет пытаться вызвать y.__radd__(x). Аналогично для остальных методов.

__iadd__(self, other) - +=.

__isub__(self, other) - -=.

__imul__(self, other) - *=.

__itruediv__(self, other) - /=.

__ifloordiv__(self, other) - //=.

__imod__(self, other) - %=.

__ipow__(self, other[, modulo]) - **=.

__ilshift__(self, other) -

__irshift__(self, other) - >>=.

__iand__(self, other) - &=.

__ixor__(self, other) - ^=.

__ior__(self, other) - |=.

__neg__(self) - унарный -.

__pos__(self) - унарный +.

__abs__(self) - модуль (abs()).

__invert__(self) - инверсия (~).

__complex__(self) - приведение к complex.

__int__(self) - приведение к int.

__float__(self) - приведение к float.

__round__(self[, n]) - округление.

__enter__(self), __exit__(self, exc_type, exc_value, traceback) - реализация менеджеров контекста.

Рассмотрим некоторые из этих методов на примере двухмерного вектора, для которого переопределим некоторые методы:

  В заключение хочу сказать, что перегрузка специальных методов - вещь хорошая, но не стоит ей слишком злоупотреблять. Перегружайте их только тогда, когда вы уверены в том, что это поможет пониманию программного кода.

Для вставки кода на Python в комментарий заключайте его в теги

  • Модуль csv - чтение и запись CSV файлов
  • Создаём сайт на Django, используя хорошие практики. Часть 1: создаём проект
  • Онлайн-обучение Python: сравнение популярных программ
  • Книги о Python
  • GUI (графический интерфейс пользователя)
  • Курсы Python
  • Модули
  • Новости мира Python
  • NumPy
  • Обработка данных
  • Основы программирования
  • Примеры программ
  • Типы данных в Python
  • Видео
  • Python для Web
  • Работа для Python-программистов
  • Сделай свой вклад в развитие сайта!
  • Самоучитель Python
  • Карта сайта
  • Отзывы на книги по Python
  • Реклама на сайте

Python Переопределение родительского метода

Возможно ли в данном случае переопределить поведение метода _subconstructor из класса Child не переопределяя сам __init__ метод родительского класса?

Отслеживать
задан 12 мая 2016 в 10:27
user207200 user207200
5,210 8 8 золотых знаков 23 23 серебряных знака 41 41 бронзовый знак

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Можно. Опишите метод который хотите переопределить в наследнике.

введите сюда описание изображения

Отслеживать
ответ дан 12 мая 2016 в 10:56
2,332 6 6 золотых знаков 21 21 серебряный знак 34 34 бронзовых знака

Спасибо. Но уже решился вопрос. Не понимал, почему не работает переопределение в дочернем классе. Оказалось, пропущена буква в имени метода. Хотел удалять вопрос, но, раз уж вы дали ответ, может, это кому-то понадобится.

#18 – Конструкторы, переопределение методов

#18 – Конструкторы, переопределение методов

Для быстрой установки данных при создании объекта можно использовать конструкторы. За урок мы научимся создавать и применять для классов конструкторы в языке Питон. Помимо этого мы изучим тему переопределения методов.

Видеоурок

Конструкторы позволяют задать некие характеристики для объекта сразу же при его создании. К примеру, у вас есть несколько переменных, которые точно должен иметь объект. Вы можете создать конструктор и указать несколько параметров, которые будут переданы при создании объекта.

В одном классе может быть неограниченное количество конструкторов и сам интерпретатор будет понимать к какому конструктору вы обращаетесь. Чтобы создать конструктор необходимо использовать ключевое слово __init__ .

Пример класса с конструктором:

class Cars: wheels = 0 marka = "" def __init__(self, wheels, marka): self.wheels = wheels self.marka = marka bmw = Cars(4, "X3") # Сразу добавили характеристики print (bmw.wheels) # Результат - 4

Конструкторы

class Cat: name = None age = None isHappy = None def __init__(self, name=<>, age=None, isHappy=None): self.set_data(name, age, isHappy) self.get_data() def set_data(self, name = None, age = None, isHappy = None): self.name = name self.age = age self.isHappy = isHappy def get_data(self): print(self.name, "age:", self.age, ". Happy:", self.isHappy) cat1 = Cat() cat2 = Cat("Жопен", 2, False)

Задание к уроку

Необходимо оформить подписку на проект, чтобы получить доступ ко всем домашним заданиям

Большое задание по курсу

Вам необходимо оформить подписку на сайте, чтобы иметь доступ ко всем большим заданиям. В задание входит методика решения, а также готовый проект с ответом к заданию.
PS: подобные задания доступны при подписке от 1 месяца

Переопределение методов — Python: Погружаясь в классы

В программировании часто возникают ситуации, когда необходимо изменить поведение существующего класса без изменения его кода. Как это сделать эффективно и без дублирования кода? Для этого существует концепция объектно-ориентированного программирования — переопределение методов.

В этом уроке мы научимся переопределять методы в подклассах и на примерах посмотрим, как переопределение методов может упростить код.

Как работает переопределение

Представим, что у нас есть класс HTMLSelectElement . Это HTML-элемент со списком элементов и методом для извлечения конкретного элемента:

class HTMLSelectElement: def __init__(self, options): self.options = options def item(self, index): return self.options[index] 

В данном случае класс HTMLSelectElement является простым и содержит список опций и метод item , который позволяет извлекать конкретный элемент списка по индексу.

Теперь представим, что нам нужно изменить поведение метода item так, чтобы он возвращал элемент списка, если индекс находится в пределах допустимого диапазона, и возвращал сообщение об ошибке, если индекс находится вне диапазона. Мы можем сделать это с помощью наследования и переопределения метода item :

class HTMLCustomSelectElement(HTMLSelectElement): def item(self, index): if index  0 or index >= len(self.options): return "Ошибка: индекс вне диапазона" return super().item(index) 

Мы создали подкласс HTMLCustomSelectElement , который переопределяет метод item(self, index) . Переопределение означает, что в подклассе создается метод с тем же именем, что и в родительском классе.

Наш новый метод выполняет дополнительную работу по проверке индекса, но ему все еще нужен исходный метод item(self, index) для выборки нужного элемента. Для этого применяется специальный синтаксис, который указывает, что нужно взять метод из родительского класса: super().item(index) .

Теперь, используя наш новый класс, если пользователь попробует обратиться к элементу списка с несуществующим индексом, он получит сообщение об ошибке:

custom_options = HTMLCustomSelectElement(["Opt 1", "Opt 2", "Opt 3"]) print(custom_options.item(1)) # "Opt 2" print(custom_options.item(3)) # "Ошибка: индекс вне диапазона" 

Таким образом, переопределив метод item в подклассе, мы расширили его функциональность и добавили обработку ошибок.

В нашем примере мы обращаемся к элементам списка. Но почему понадобился специальный синтаксис? Представим, что вместо него там был бы такой код:

def item(self, possible_index): self.item(possible_index) 

Какой в этом случае метод item нужно брать — в определении которого мы находимся прямо сейчас или родительский?

Наследование устроено так, что всегда выбирается тот метод, который находится ближе в цепочке наследования. Поэтому вызов через self породит рекурсию, но родительский метод никогда не будет вызван.

По этой же причине снаружи объекта невозможно вызвать методы, которые были переопределены в наследниках:

select = HTMLCustomSelectElement() # Этот вызов всегда относится к методу item, переопределенному внутри HTMLCustomSelectElement # Вызвать item напрямую из HTMLSelectElement невозможно select.item(3) 

Переопределение не ограничивается одним уровнем наследования. Любой переопределенный метод можно снова переопределить в наследниках текущего класса. Главное — соблюдать два условия:

  • У обоих методов должны совпадать имена
  • Они должны иметь одинаковое количество обязательных аргументов

Теперь рассмотрим, как на практике можно использовать классы-наследники, и какие трудности могут возникнуть.

Как использовать наследников

Создать класс-наследник и начать его использовать — это две большие разницы. В ситуациях, где эти классы создаются вами, все просто. Достаточно заменить вызовы старого класса на новый. Но если объекты этого класса создаются чужим кодом, то задача усложняется. Для подмены такого класса от чужого кода требуется поддержка полиморфного поведения.

Например, при работе с элементами HTML объекты этих классов иногда порождаются самим программистом, а иногда системой. Например:

# Создаем сами element1 = HTMLSelectElement() # Где-то внутри создается объект HTMLSelectElement element2 = html.query_selector('select') 

Можно ли в данном случае подменить класс в примере с query_selector() ? Единственный выход — использовать собственный класс. То есть конвертировать вернувшийся объект в объект нужного нам класса. Стоит ли оно того? Почти наверняка, что нет.

Другими словами, наследование для переопределения поведения хоть и кажется логичным шагом, но в действительности имеет серьезные ограничения по использованию.

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов

Наши выпускники работают в компаниях:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *