Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs
Последняя
функция модуля 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>
В этом случае
дополнительно нужно прописать круглые скобки для вызова метода:
Давайте вернем 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