functools --- 高階関数と呼び出し可能オブジェクトの操作

ソースコード:Lib/functools.py


functools モジュールは高階関数、つまり関数に影響を及ぼしたり他の関数を返したりする関数のためのものです。一般に、どんな呼び出し可能オブジェクトでもこのモジュールの目的には関数として扱えます。

モジュールfunctools は以下の関数を定義します:

@functools.cache(user_function)

簡単で軽量な無制限の関数キャッシュです。"メモ化 (memoize)" とも呼ばれることがあります。

Returns the same aslru_cache(maxsize=None), creating a thinwrapper around a dictionary lookup for the function arguments. Because itnever needs to evict old values, this is smaller and faster thanlru_cache() with a size limit.

例えば:

@cachedeffactorial(n):returnn*factorial(n-1)ifnelse1>>>factorial(10)# no previously cached result, makes 11 recursive calls3628800>>>factorial(5)# just looks up cached value result120>>>factorial(12)# makes two new recursive calls, the other 10 are cached479001600

The cache is threadsafe so that the wrapped function can be used inmultiple threads. This means that the underlying data structure willremain coherent during concurrent updates.

It is possible for the wrapped function to be called more than once ifanother thread makes an additional call before the initial call has beencompleted and cached.

Added in version 3.9.

@functools.cached_property(func)

クラスのメソッドを、値を一度だけ計算して通常の属性としてキャッシュするプロパティに変換します。キャッシュはインスタンスの生存期間にわたって有効です。property() に似ていて、さらにキャッシュを行います。計算コストが高く、一度計算すればその後は不変であるようなインスタンスのプロパティに対して有用です。

以下はプログラム例です:

classDataSet:def__init__(self,sequence_of_numbers):self._data=tuple(sequence_of_numbers)@cached_propertydefstdev(self):returnstatistics.stdev(self._data)

cached_property() のしくみはproperty() とやや異なります。通常のプロパティは、セッター (setter) が定義されない限り書き込みを禁止します。対照的に、cached_property は書き込みを許します。

cached_property デコレータはルックアップテーブルで、同名の属性が存在しない場合のみ動作します。動作した場合、cached_property は同名の属性に書き込みを行います。その後の属性の読み込みと書き込みはcached_property メソッドより優先され、通常の属性のように働きます。

キャッシュされた値は属性を削除することで取り除くことができます。これによりcached_property メソッドを再度実行することが可能になります。

Thecached_property does not prevent a possible race condition inmulti-threaded usage. The getter function could run more than once on thesame instance, with the latest run setting the cached value. If the cachedproperty is idempotent or otherwise not harmful to run more than once on aninstance, this is fine. If synchronization is needed, implement the necessarylocking inside the decorated getter function or around the cached propertyaccess.

このデコレータはPEP 412 のキー共有辞書のインターフェースを持ちます。これは、インスタンス辞書がより多くのスペースを使う可能性があることを意味します。

また、このデコレータは各インスタンスの__dict__ 属性が可変のマッピングであることを要求します。すなわち、このデコレータはいくつかの型、たとえばメタクラス (型インスタンスの__dict__ 属性はクラスの名前空間に対する読み込み専用のプロキシであるため) や、__slots__ を指定していてその中に__dict__ を含まない型 (それ自体が__dict__ 属性を提供しないため) に対しては動作しないことを意味します。

If a mutable mapping is not available or if space-efficient key sharing isdesired, an effect similar tocached_property() can also be achieved bystackingproperty() on top oflru_cache(). Seeメソッド呼び出しをキャッシュするには どうしたらいいですか? for more details on how this differs fromcached_property().

Added in version 3.8.

バージョン 3.12 で変更:Prior to Python 3.12,cached_property included an undocumented lock toensure that in multi-threaded usage the getter function was guaranteed torun only once per instance. However, the lock was per-property, notper-instance, which could result in unacceptably high lock contention. InPython 3.12+ this locking is removed.

functools.cmp_to_key(func)

古いスタイルの比較関数をkey function に変換します。key 関数を受け取るツール (sorted(),min(),max(),heapq.nlargest(),heapq.nsmallest(),itertools.groupby() など) と共に使用します。この関数は、主に比較関数を使っていた Python 2 からプログラムの移行のための変換ツールとして使われます。

比較関数は2つの引数を受け取り、それらを比較し、 "より小さい" 場合は負の数を、同値の場合には 0 を、 "より大きい" 場合には正の数を返す、あらゆる呼び出し可能オブジェクトです。key 関数は呼び出し可能オブジェクトで、1つの引数を受け取り、ソートキーとして使われる値を返します。

以下はプログラム例です:

sorted(iterable,key=cmp_to_key(locale.strcoll))# locale-aware sort order

ソートの例と簡単なチュートリアルはソートのテクニック を参照して下さい。

Added in version 3.2.

@functools.lru_cache(user_function)
@functools.lru_cache(maxsize=128,typed=False)

関数をメモ化用の呼び出し可能オブジェクトでラップし、最近の呼び出し最大maxsize 回まで保存するするデコレータです。高価な関数や I/O に束縛されている関数を定期的に同じ引数で呼び出すときに、時間を節約できます。

The cache is threadsafe so that the wrapped function can be used inmultiple threads. This means that the underlying data structure willremain coherent during concurrent updates.

It is possible for the wrapped function to be called more than once ifanother thread makes an additional call before the initial call has beencompleted and cached.

結果のキャッシュには辞書が使われるので、関数の位置引数およびキーワード引数はハッシュ可能 でなくてはなりません。

引数のパターンが異なる場合は、異なる呼び出しと見なされ別々のキャッシュエントリーとなります。例えば、f(a=1,b=2)f(b=2,a=1) はキーワード引数の順序が異なっているので、2つの別個のキャッシュエントリーになります。

user_function が指定された場合、それは呼び出し可能でなければなりません。これによりlru_cache デコレータがユーザー関数に直接適用できるようになります。このときmaxsize の値はデフォルトの 128 となります:

@lru_cachedefcount_vowels(sentence):returnsum(sentence.count(vowel)forvowelin'AEIOUaeiou')

maxsizeNone に設定された場合は、LRU 機能は無効化され、キャッシュは際限無く大きくなります。

Iftyped is set to true, function arguments of different types will becached separately. Iftyped is false, the implementation will usuallyregard them as equivalent calls and only cache a single result. (Sometypes such asstr andint may be cached separately even whentypedis false.)

Note, type specificity applies only to the function's immediate argumentsrather than their contents. The scalar arguments,Decimal(42) andFraction(42) are be treated as distinct calls with distinct results.In contrast, the tuple arguments('answer',Decimal(42)) and('answer',Fraction(42)) are treated as equivalent.

The wrapped function is instrumented with acache_parameters()function that returns a newdict showing the values formaxsizeandtyped. This is for information purposes only. Mutating the valueshas no effect.

To help measure the effectiveness of the cache and tune themaxsizeparameter, the wrapped function is instrumented with acache_info()function that returns anamed tuple showinghits,misses,maxsize andcurrsize.

The decorator also provides acache_clear() function for clearing orinvalidating the cache.

元々の基底の関数には、__wrapped__ 属性を通してアクセスできます。これはキャッシュを回避して、または関数を別のキャッシュでラップして、内観するのに便利です。

The cache keeps references to the arguments and return values until they ageout of the cache or until the cache is cleared.

If a method is cached, theself instance argument is included in thecache. Seeメソッド呼び出しをキャッシュするには どうしたらいいですか?

AnLRU (least recently used) cacheworks best when the most recent calls are the best predictors of upcomingcalls (for example, the most popular articles on a news server tend tochange each day). The cache's size limit assures that the cache does notgrow without bound on long-running processes such as web servers.

In general, the LRU cache should only be used when you want to reusepreviously computed values. Accordingly, it doesn't make sense to cachefunctions with side-effects, functions that need to createdistinct mutable objects on each call (such as generators and async functions),or impure functions such as time() or random().

静的 web コンテンツ の LRU キャッシュの例:

@lru_cache(maxsize=32)defget_pep(num):'Retrieve text of a Python Enhancement Proposal'resource=f'https://peps.python.org/pep-{num:04d}'try:withurllib.request.urlopen(resource)ass:returns.read()excepturllib.error.HTTPError:return'Not Found'>>>fornin8,290,308,320,8,218,320,279,289,320,9991:...pep=get_pep(n)...print(n,len(pep))>>>get_pep.cache_info()CacheInfo(hits=3,misses=8,maxsize=32,currsize=8)

キャッシュを使って動的計画法 の技法を実装し、フィボナッチ数 を効率よく計算する例:

@lru_cache(maxsize=None)deffib(n):ifn<2:returnnreturnfib(n-1)+fib(n-2)>>>[fib(n)forninrange(16)][0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610]>>>fib.cache_info()CacheInfo(hits=28,misses=16,maxsize=None,currsize=16)

Added in version 3.2.

バージョン 3.3 で変更:typed オプションが追加されました。

バージョン 3.8 で変更:user_function オプションが追加されました。

バージョン 3.9 で変更:Added the functioncache_parameters()

@functools.total_ordering

ひとつ以上の拡張順序比較メソッド (rich comparison ordering methods) を定義したクラスを受け取り、残りを実装するクラスデコレータです。このデコレータは全ての拡張順序比較演算をサポートするための労力を軽減します:

The class must define one of__lt__(),__le__(),__gt__(), or__ge__().In addition, the class should supply an__eq__() method.

例えば:

@total_orderingclassStudent:def_is_valid_operand(self,other):return(hasattr(other,"lastname")andhasattr(other,"firstname"))def__eq__(self,other):ifnotself._is_valid_operand(other):returnNotImplementedreturn((self.lastname.lower(),self.firstname.lower())==(other.lastname.lower(),other.firstname.lower()))def__lt__(self,other):ifnotself._is_valid_operand(other):returnNotImplementedreturn((self.lastname.lower(),self.firstname.lower())<(other.lastname.lower(),other.firstname.lower()))

注釈

このデコレータにより、このデコレータにより、行儀の良い(well behaved)全順序型を簡単に作ることができますが、その代償として実行速度は遅く、比較メソッドの演繹によってのスタックトレースは複雑になります。性能ベンチマークにより、これがアプリケーションのボトルネックになっていることがわかった場合は、代わりに 6 つの拡張比較メソッドをすべて実装すれば、簡単にスピードアップを図れるでしょう。

注釈

This decorator makes no attempt to override methods that have beendeclared in the classor its superclasses. Meaning that if asuperclass defines a comparison operator,total_ordering will notimplement it again, even if the original method is abstract.

Added in version 3.2.

バージョン 3.4 で変更:ReturningNotImplemented from the underlying comparison function forunrecognised types is now supported.

functools.partial(func,/,*args,**keywords)

新しいpartial オブジェクト を返します。このオブジェクトは呼び出されると位置引数args とキーワード引数keywords 付きで呼び出されたfunc のように振る舞います。呼び出しに際してさらなる引数が渡された場合、それらはargs に付け加えられます。追加のキーワード引数が渡された場合には、それらでkeywords を拡張または上書きします。おおよそ次のコードと等価です:

defpartial(func,/,*args,**keywords):defnewfunc(*fargs,**fkeywords):newkeywords={**keywords,**fkeywords}returnfunc(*args,*fargs,**newkeywords)newfunc.func=funcnewfunc.args=argsnewfunc.keywords=keywordsreturnnewfunc

Thepartial() is used for partial function application which "freezes"some portion of a function's arguments and/or keywords resulting in a new objectwith a simplified signature. For example,partial() can be used to createa callable that behaves like theint() function where thebase argumentdefaults to two:

>>>fromfunctoolsimportpartial>>>basetwo=partial(int,base=2)>>>basetwo.__doc__='Convert base 2 string to an int.'>>>basetwo('10010')18
classfunctools.partialmethod(func,/,*args,**keywords)

partial と似た動作をする新しいpartialmethod 記述子 (デスクリプタ) を返します。直接呼び出しではなく、メソッド定義としての使用が目的であることのみが、partial とは異なります。

func は、descriptor または呼び出し可能オブジェクトである必要があります (通常の関数など、両方の性質を持つオブジェクトは記述子として扱われます。)

Whenfunc is a descriptor (such as a normal Python function,classmethod(),staticmethod(),abstractmethod() oranother instance ofpartialmethod), calls to__get__ aredelegated to the underlying descriptor, and an appropriatepartial object returned as the result.

func が記述子以外の呼び出し可能オブジェクトである場合、適切な束縛メソッドが動的に作成されます。この func は、メソッドとして使用された場合、Python の通常の関数と同様に動作します。partialmethod コンストラクタにargskeywords が渡されるよりも前に、self 引数が最初の位置引数として挿入されます。

以下はプログラム例です:

>>>classCell:...def__init__(self):...self._alive=False...@property...defalive(self):...returnself._alive...defset_state(self,state):...self._alive=bool(state)...set_alive=partialmethod(set_state,True)...set_dead=partialmethod(set_state,False)...>>>c=Cell()>>>c.aliveFalse>>>c.set_alive()>>>c.aliveTrue

Added in version 3.4.

functools.reduce(function,iterable,[initial,]/)

Applyfunction of two arguments cumulatively to the items ofiterable, fromleft to right, so as to reduce the iterable to a single value. For example,reduce(lambdax,y:x+y,[1,2,3,4,5]) calculates((((1+2)+3)+4)+5).The left argument,x, is the accumulated value and the right argument,y, isthe update value from theiterable. If the optionalinitial is present,it is placed before the items of the iterable in the calculation, and serves asa default when the iterable is empty. Ifinitial is not given anditerable contains only one item, the first item is returned.

およそ次と等価です:

initial_missing=object()defreduce(function,iterable,initial=initial_missing,/):it=iter(iterable)ifinitialisinitial_missing:value=next(it)else:value=initialforelementinit:value=function(value,element)returnvalue

全ての中間値を返すイテレータについてはitertools.accumulate() を参照してください。

@functools.singledispatch

関数をシングルディスパッチジェネリック関数 に変換します。

To define a generic function, decorate it with the@singledispatchdecorator. When defining a function using@singledispatch, note that thedispatch happens on the type of the first argument:

>>>fromfunctoolsimportsingledispatch>>>@singledispatch...deffun(arg,verbose=False):...ifverbose:...print("Let me just say,",end=" ")...print(arg)

To add overloaded implementations to the function, use theregister()attribute of the generic function, which can be used as a decorator. Forfunctions annotated with types, the decorator will infer the type of thefirst argument automatically:

>>>@fun.register...def_(arg:int,verbose=False):...ifverbose:...print("Strength in numbers, eh?",end=" ")...print(arg)...>>>@fun.register...def_(arg:list,verbose=False):...ifverbose:...print("Enumerate this:")...fori,eleminenumerate(arg):...print(i,elem)

types.UnionType andtyping.Union can also be used:

>>>@fun.register...def_(arg:int|float,verbose=False):...ifverbose:...print("Strength in numbers, eh?",end=" ")...print(arg)...>>>fromtypingimportUnion>>>@fun.register...def_(arg:Union[list,set],verbose=False):...ifverbose:...print("Enumerate this:")...fori,eleminenumerate(arg):...print(i,elem)...

型アノテーションを使っていないコードについては、デコレータに適切な型引数を明示的に渡せます:

>>>@fun.register(complex)...def_(arg,verbose=False):...ifverbose:...print("Better than complicated.",end=" ")...print(arg.real,arg.imag)...

For code that dispatches on a collections type (e.g.,list), but wantsto typehint the items of the collection (e.g.,list[int]), thedispatch type should be passed explicitly to the decorator itself with thetypehint going into the function definition:

>>>@fun.register(list)...def_(arg:list[int],verbose=False):...ifverbose:...print("Enumerate this:")...fori,eleminenumerate(arg):...print(i,elem)

注釈

At runtime the function will dispatch on an instance of a list regardlessof the type contained within the list i.e.[1,2,3] will bedispatched the same as["foo","bar","baz"]. The annotationprovided in this example is for static type checkers only and has noruntime impact.

To enable registeringlambdas and pre-existing functions,theregister() attribute can also be used in a functional form:

>>>defnothing(arg,verbose=False):...print("Nothing.")...>>>fun.register(type(None),nothing)

Theregister() attribute returns the undecorated function. Thisenables decorator stacking,pickling, and the creationof unit tests for each variant independently:

>>>@fun.register(float)...@fun.register(Decimal)...deffun_num(arg,verbose=False):...ifverbose:...print("Half of your number:",end=" ")...print(arg/2)...>>>fun_numisfunFalse

汎用関数は、呼び出されると 1 つ目の引数の型でディスパッチします:

>>>fun("Hello, world.")Hello, world.>>>fun("test.",verbose=True)Let me just say, test.>>>fun(42,verbose=True)Strength in numbers, eh? 42>>>fun(['spam','spam','eggs','spam'],verbose=True)Enumerate this:0 spam1 spam2 eggs3 spam>>>fun(None)Nothing.>>>fun(1.23)0.615

特定の型について登録された実装が存在しない場合、その型のメソッド解決順序が、汎用の実装をさらに検索するために使用されます。@singledispatch でデコレートされた元の関数は基底のobject 型に登録されます。これは、他によりよい実装が見つからないことを意味します。

抽象基底クラス (abstract base class) に対して実装が登録されると、基底クラスの仮想サブクラスに対してもその実装がディスパッチされます:

>>>fromcollections.abcimportMapping>>>@fun.register...def_(arg:Mapping,verbose=False):...ifverbose:...print("Keys & Values")...forkey,valueinarg.items():...print(key,"=>",value)...>>>fun({"a":"b"})a => b

指定された型に対して、汎用関数がどの実装を選択するかを確認するには、dispatch() 属性を使用します:

>>>fun.dispatch(float)<function fun_num at 0x1035a2840>>>>fun.dispatch(dict)# note: default implementation<function fun at 0x103fe0000>

登録されたすべての実装にアクセスするには、読み出し専用のregistry 属性を使用します:

>>>fun.registry.keys()dict_keys([<class 'NoneType'>, <class 'int'>, <class 'object'>,          <class 'decimal.Decimal'>, <class 'list'>,          <class 'float'>])>>>fun.registry[float]<function fun_num at 0x1035a2840>>>>fun.registry[object]<function fun at 0x103fe0000>

Added in version 3.4.

バージョン 3.7 で変更:Theregister() attribute now supports using type annotations.

バージョン 3.11 で変更:Theregister() attribute now supportstypes.UnionTypeandtyping.Union as type annotations.

classfunctools.singledispatchmethod(func)

メソッドをシングルディスパッチジェネリック関数 に変換します。

To define a generic method, decorate it with the@singledispatchmethoddecorator. When defining a function using@singledispatchmethod, notethat the dispatch happens on the type of the first non-self or non-clsargument:

classNegator:@singledispatchmethoddefneg(self,arg):raiseNotImplementedError("Cannot negate a")@neg.registerdef_(self,arg:int):return-arg@neg.registerdef_(self,arg:bool):returnnotarg

@singledispatchmethod@classmethod など他のデコレータとの入れ子構造をサポートします。dispatcher.register を可能にするためには、singledispatchmethod は入れ子構造の中で最も外側 のデコレータでなければなりません。このNegator クラスの例では、クラスのインスタンスにではなく、クラスにneg メソッドが紐付きます:

classNegator:@singledispatchmethod@classmethoddefneg(cls,arg):raiseNotImplementedError("Cannot negate a")@neg.register@classmethoddef_(cls,arg:int):return-arg@neg.register@classmethoddef_(cls,arg:bool):returnnotarg

同様のパターンが他の似たようなデコレータに対しても適用できます:@staticmethod,@abstractmethod など。

Added in version 3.8.

functools.update_wrapper(wrapper,wrapped,assigned=WRAPPER_ASSIGNMENTS,updated=WRAPPER_UPDATES)

Update awrapper function to look like thewrapped function. The optionalarguments are tuples to specify which attributes of the original function areassigned directly to the matching attributes on the wrapper function and whichattributes of the wrapper function are updated with the corresponding attributesfrom the original function. The default values for these arguments are themodule level constantsWRAPPER_ASSIGNMENTS (which assigns to the wrapperfunction's__module__,__name__,__qualname__,__annotations__,__type_params__, and__doc__, thedocumentation string) andWRAPPER_UPDATES (which updates the wrapperfunction's__dict__, i.e. the instance dictionary).

内観や別の目的 (例えば、lru_cache() のようなキャッシュするデコレータの回避) のために元の関数にアクセスできるように、この関数はラップされている関数を参照するラッパーに自動的に__wrapped__ 属性を追加します。

この関数は主に関数を包んでラッパーを返すデコレータ 関数の中で使われるよう意図されています。もしラッパー関数がアップデートされないとすると、返される関数のメタデータは元の関数の定義ではなくラッパー関数の定義を反映してしまい、これは通常あまり有益ではありません。

update_wrapper() は、関数以外の呼び出し可能オブジェクトにも使えます。assigned またはupdated で指名され、ラップされるオブジェクトに存在しない属性は、すべて無視されます (すなわち、ラッパー関数にそれらの属性を設定しようとは試みられません)。しかし、updated で指名された属性がラッパー関数自身に存在しないならAttributeError が送出されます。

バージョン 3.2 で変更:The__wrapped__ attribute is now automatically added.The__annotations__ attribute is now copied by default.Missing attributes no longer trigger anAttributeError.

バージョン 3.4 で変更:ラップされた関数が__wrapped__ を定義していない場合でも、__wrapped__ が常にラップされた関数を参照するようになりました。(bpo-17482 を参照)

バージョン 3.12 で変更:The__type_params__ attribute is now copied by default.

@functools.wraps(wrapped,assigned=WRAPPER_ASSIGNMENTS,updated=WRAPPER_UPDATES)

これはラッパー関数を定義するときにupdate_wrapper() を関数デコレータとして呼び出す便宜関数です。これはpartial(update_wrapper,wrapped=wrapped,assigned=assigned,updated=updated) と等価です。例えば:

>>>fromfunctoolsimportwraps>>>defmy_decorator(f):...@wraps(f)...defwrapper(*args,**kwds):...print('Calling decorated function')...returnf(*args,**kwds)...returnwrapper...>>>@my_decorator...defexample():..."""Docstring"""...print('Called example function')...>>>example()Calling decorated functionCalled example function>>>example.__name__'example'>>>example.__doc__'Docstring'

Without the use of this decorator factory, the name of the example functionwould have been'wrapper', and the docstring of the originalexample()would have been lost.

partial オブジェクト

partial オブジェクトは、partial() 関数によって作られる呼び出し可能オブジェクトです。オブジェクトには読み出し専用の属性が三つあります:

partial.func

呼び出し可能オブジェクトまたは関数です。partial オブジェクトの呼び出しは新しい引数とキーワードと共にfunc に転送されます。

partial.args

最左の位置引数で、partial オブジェクトの呼び出し時にその呼び出しの際の位置引数の前に追加されます。

partial.keywords

partial オブジェクトの呼び出し時に渡されるキーワード引数です。

partial objects are likefunction objectsin that they are callable, weak referenceable, and can have attributes.There are some important differences. For instance, the__name__ andfunction.__doc__ attributesare not created automatically. Also,partial objects defined inclasses behave like static methods and do not transform into bound methodsduring instance attribute look-up.