Функция methodcaller() модуля operator

Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs

Смотреть материал на YouTube | RuTube

Последняя функция модуля operator, которую мы рассмотрим – это функция methodcaller(). Она полезна в ситуациях, когда нужно вызывать метод объекта динамически множество раз. Давайте рассмотрим работу methodcaller на конкретном примере.

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

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
 
    def get_area(self):
        return self.width * self.height
 
    def get_area_factor(self, factor):
        return self.width * self.height * factor
 
    def __repr__(self):
        return f"{self.width, self.height}: area = {self.get_area()}"

И создается список из таких объектов:

figs = [Rectangle(10, 20), Rectangle(3, 5), Rectangle(7, 4)]

Допустим, что нам требуется вызвать метод get_area() каждого из этих объектов. Для этого создадим объект специального вида путем вызова methodcaller:

get_rect_area = op.methodcaller("get_area")

который позволяет вызывать метод "get_area" любого объекта, в котором такой метод присутствует. Например:

area = get_rect_area(figs[0])
print(area)  # 200

Запись вида get_rect_area(figs[0]) эквивалентна записи:

res = figs[0].get_area() # то же, что и get_rect_area(figs[0])

То есть объект get_rect_area при вызове того или иного метода в его первый параметр self передает указанный объект.

Обратите внимание, что если вместо methodcaller прописать attrgetter:

get_rect_area = op.attrgetter("get_area")

то автоматического вызова метода происходить не будет и в консоли появится сообщение:

<bound method Rectangle.get_area of (10, 20): area = 200>

В этом случае дополнительно нужно прописать круглые скобки для вызова метода:

print(area())  # 200

Давайте вернем methodcaller и воспользуемся get_rect_area для множественного вызова метода get_area. Сделать это можно, используя функцию map():

res = list(map(get_rect_area, figs))
print(res)  # [200, 15, 28]

Конечно, того же результата можно было бы добиться, используя лямбда-функцию:

res = list(map(lambda obj: obj.get_area(), figs))

Но такая конструкция работает несколько медленнее предыдущего варианта. Именно в этом одно из преимуществ использования функции methodcaller().

Применение methodcaller для вызова методов с параметрами

При создании объектов вызываемых методов дополнительно можно указывать аргументы, которые будут автоматически передаваться в соответствующие параметры. Например, в классе Rectangle имеется метод get_area_factor с параметром factor. Создадим вызываемый объект для него следующим образом:

get_rect_area2 = op.methodcaller("get_area_factor", 2)

В этом случае, при вызове get_rect_area2 в параметр factor будет передаваться значение 2. Получим:

area = get_rect_area2(figs[0])
print(area)  # 400 = 200 * factor

По аналогии можно формировать значения аргументов для множества параметров.

Использование methodcaller при сортировке объектов

В заключение рассмотрим практический пример использования methodcaller. Предположим, нужно отсортировать объекты списка figs по возрастанию площадей:

figs = [Rectangle(10, 20), Rectangle(3, 5), Rectangle(7, 4)]

Для этого сформируем объект вызываемого метода:

get_rect_area = op.methodcaller("get_area")

и укажем его в параметре key метода sort():

figs.sort(key=get_rect_area)
print(figs)

В консоли увидим результат:

[(3, 5): area = 15, (7, 4): area = 28, (10, 20): area = 200]

И такой подход бывает удобнее использования лямбда-функции:

figs.sort(key=lambda obj: obj.get_area())

особенно при обработке больших коллекций из объектов.

Таким образом, methodcaller() представляет собой эффективный инструмент для быстрого вызова методов объектов, который широко применяется в обработке больших объемов данных и совместим с различными высокоуровневыми функциями Python, такими как, map(), filter(), sorted() и т. п.

Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs

Видео по теме