0Pricing
Python Academy · レッスン

functools: partial と reduce

partial で特化した関数を作成し、reduce でシーケンスを畳み込みます。

「functools: partial と reduce」はCoddyKit上の無料Python Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPython Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Python Academyコースには全4レッスンが含まれています。

functoolsの概要

functoolsは、他の関数を操作したり返したりする高階関数を集めた標準ライブラリモジュールです。

import functools

# partial, reduce, lru_cache, wraps, cached_property ...
print(dir(functools))

partial()

functools.partial(func, *args, **kw)は、一部の引数があらかじめ設定された新しい呼び出し可能オブジェクトを作成します。

import functools

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

square = functools.partial(power, exp=2)
cube   = functools.partial(power, exp=3)

print(square(4))  # 16
print(cube(3))    # 27

メソッドでのpartialの利用

partialを使うと、固定パラメーターを持つメソッドをコールバックやイベントハンドラーとして使える形に適応できます。

import functools, logging

logger = logging.getLogger("app")
log_error = functools.partial(logger.log, logging.ERROR)

log_error("Something went wrong")

partialとlambdaの比較

引数をあらかじめ設定する場合はlambdaよりもpartialが推奨されます。partialはpickle化でき、適切なreprを持ち、docstringも保持するためです。

import functools

mul = lambda x, y: x * y

double_lambda = lambda x: mul(x, 2)            # lambda approach
double_partial = functools.partial(mul, y=2)   # partial approach

print(double_partial(5))   # 10

reduce()

functools.reduce(func, iterable, initial)は、二項関数を使ってイテラブルを左から右へ畳み込みます。

import functools, operator

total = functools.reduce(operator.add, [1,2,3,4,5])
print(total)   # 15

product = functools.reduce(operator.mul, [1,2,3,4,5], 1)
print(product) # 120

reduceによるmax()の構築

max()を再実装してreduceの使い方を示します。

import functools

def my_max(seq):
    return functools.reduce(lambda a, b: a if a > b else b, seq)

print(my_max([3, 1, 4, 1, 5, 9]))  # 9

ネストしたリストの平坦化

operator.iconcatとreduceを使うと、1段階のネストを平坦化できます。

import functools, operator

nested = [[1,2],[3,4],[5]]
flat = functools.reduce(operator.iconcat, nested, [])
print(flat)  # [1, 2, 3, 4, 5]

URL構築でのpartialの利用

partialの実用的なパターンとして、ベースURLを固定し、用途別のリクエストヘルパーを作成できます。

import functools, urllib.request

def fetch(base, path):
    url = base.rstrip("/") + "/" + path.lstrip("/")
    with urllib.request.urlopen(url) as r:
        return r.read()

github = functools.partial(fetch, "https://api.github.com")
# github("/users/octocat")

wraps():メタデータの保持

デコレーターを作成するときは、@functools.wraps(wrapped)を使うと、ラッパーが元の関数の名前とdocstringを保持できます。

import functools

def decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        return func(*args, **kw)
    return wrapper

@decorator
def greet(name):
    """Say hello."""
    return f"Hello, {name}"

print(greet.__name__)  # greet
print(greet.__doc__)   # Say hello.

total_ordering

@functools.total_orderingは、__eq__と__lt__/__le__/__gt__/__ge__のいずれか1つを定義すると、不足している比較メソッドを補います。

import functools

@functools.total_ordering
class Version:
    def __init__(self, major, minor):
        self.v = (major, minor)
    def __eq__(self, o): return self.v == o.v
    def __lt__(self, o): return self.v < o.v

print(Version(1,2) >= Version(1,1))  # True

singledispatch

@functools.singledispatchは、最初の引数の型に応じて異なる実装へ振り分ける関数を作成します。

import functools

@functools.singledispatch
def process(arg):
    raise NotImplementedError(type(arg))

@process.register(int)
def _(n): return n * 2

@process.register(str)
def _(s): return s.upper()

print(process(5))     # 10
print(process("hi"))  # HI

クイックチェック

functools.partial(pow, 2)は何を作成しますか。

まとめ

partialは関数の引数をあらかじめ設定し、reduceは二項関数でシーケンスを畳み込み、wrapsはデコレーターのメタデータを保持し、total_orderingは比較メソッドを補い、singledispatchは型に応じて処理を振り分けます。

よくある質問

「functools: partial と reduce」レッスンは無料ですか?

はい。「functools: partial と reduce」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Python Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Python Academyコースには全4レッスンが含まれています。

「functools: partial と reduce」で何を学びますか?

partial で特化した関数を作成し、reduce でシーケンスを畳み込みます。 ブラウザで直接実行するハンズオンコードでPython Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Python Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのPython Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「functools: partial と reduce」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このPython Academyレッスンでコードを書いて実行できますか?

はい。すべてのPython Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. itertools: 無限イテレーターと有限イテレーター
  2. itertools: 組合せ論
  3. functools: partial と reduce
  4. functools: lru_cache と cached_property
← Python Academyに戻る