functools.partial: частично применённые функции

Одной из самых мощных и часто используемых функций в библиотеке functools является functools.partial. Она позволяет создавать новые функции, фиксируя некоторые аргументы исходной функции. Это полезно для упрощения вызовов функций с большим числом параметров или для создания специализированных версий функций.

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

Синтаксис

functools.partial(func, /, *args, **kwargs)
  • func: исходная функция, к которой будет применена частичная фиксация аргументов
  • *args: позиционные аргументы, которые нужно зафиксировать
  • **kwargs: именованные аргументы, которые нужно зафиксировать

Рассмотрим простую функцию, которая принимает три аргумента и возвращает их сумму:

def add(a, b, c):
    return a + b + c

Создадим новую функцию, фиксируя первый аргумент:

import functools

add_five = functools.partial(add, 5)

Теперь add_five – это функция, которая ожидает два оставшихся аргумента:

print(add_five(10, 15))  # Вывод: 30 (5 + 10 + 15)

Рассмотрим более практичный пример использования functools.partial. Допустим, у нас есть функция для обработки строк:

def format_string(template, *args, **kwargs):
    return template.format(*args, **kwargs)

Эта функция позволяет форматировать строки с помощью шаблонов. Создадим частично примененную функцию для часто используемого нами шаблона email-письма:

email_template = "Dear {name},\n\nThank you for your interest in {product}. We are pleased to offer you a special discount on your next purchase."
format_email = functools.partial(format_string, email_template)

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

print(format_email(name="John Doe", product="Pyplanet Programming Course"))

Частичные функции и методы

functools.partial также удобна для использования с методами классов. Рассмотрим следующий пример:

class Calculator:
    def __init__(self, factor):
        self.factor = factor

    def multiply(self, x, y):
        return x * y * self.factor

calc = Calculator(10)
partial_multiply = functools.partial(calc.multiply, 5)

Здесь partial_multiply фиксирует аргумент x метода multiply класса Calculator:

print(partial_multiply(4))  # Вывод: 200 (5 * 4 * 10)

Удобство работы с библиотеками

Многие библиотеки в Python, такие как multiprocessing и concurrent.futures, требуют функции с определенным интерфейсом (например, функции, принимающие один аргумент). functools.partial позволяет легко адаптировать функции к этим требованиям.

Пример с использованием multiprocessing map:

from multiprocessing import Pool

def power(base, exponent):
    return base ** exponent

power_of_two = functools.partial(power, 2)

with Pool(5) as p:
    results = p.map(power_of_two, [1, 2, 3, 4, 5])

print(results)  # Вывод: [2, 4, 8, 16, 32]