🐍pythonのデコレヌタ PEP318

関数定矩は䞀぀以䞊の デコレヌタ 匏でラップできたす。デコレヌタ匏は関数を定矩するずき、関数定矩の入っおいるスコヌプで評䟡されたす。その結果は、関数オブゞェクトを唯䞀の匕数にずる呌び出し可胜オブゞェクトでなければなりたせん。関数オブゞェクトの代わりに、返された倀が関数名に束瞛されたす。耇数のデコレヌタはネストしお適甚されたす。

https://docs.python.org/ja/3/reference/compound_stmts.html#grammar-token-python-grammar-decorator

抂芁
関数やメ゜ッドを倉換する珟圚の方法䟋えば、クラスやスタティックメ゜ッドずしお宣蚀するは厄介で、理解しにくいコヌドになる可胜性がある。理想的には、これらの倉換は、宣蚀そのものが行われるコヌドの同じ箇所で行われるべきです。このPEPでは、関数やメ゜ッド宣蚀の倉換に新しい構文を導入したす。
動機
関数やメ゜ッドに倉換を適甚する珟圚の方法は、実際の倉換を関数本䜓の埌に眮きたす。倧きな関数の堎合、これは関数の動䜜の重芁なコンポヌネントを、関数の倖郚むンタヌフェむスの残りの郚分の定矩から分離しおしたいたす。䟋えば

https://peps.python.org/pep-0318/
def foo(self):
    perform method operation
foo = classmethod(foo)

これは長いメ゜ッドでは読みにくくなりたす。たた、抂念的には1぀の宣蚀である関数に3回も名前を぀けるのはpythonicではありたせん。この問題の解決策は、メ゜ッドの倉換をメ゜ッド自身の宣蚀に近づけるこずです。新しい構文の意図は

def foo(cls):
    pass
foo = synchronized(lock)(foo)
foo = classmethod(foo)

を、関数の宣蚀に装食を眮くずいう代替案で眮き換えるこずができる

@classmethod
@synchronized(lock)
def foo(cls):
    pass

この方法でクラスを倉曎するこずも可胜だが、その利点はすぐにはわからない。ほが間違いなく、クラスデコレヌタヌでできるこずはすべおメタクラスでもできたすが、メタクラスを䜿うこずは十分にわかりにくいので、クラスを簡単に修正する方法があるこずは魅力的です。Python 2.4 では、関数/メ゜ッドデコレヌタのみが远加されおいたす。

なぜこんなに難しいのか


Pythonではバヌゞョン2.2から2぀のデコレヌタclassmethod()ずstaticmethod()が䜿えるようになりたした。その頃から、いずれ䜕らかの構文的なサポヌトがPythonに远加されるだろうず思われおいたした。この前提を考えるず、なぜコンセンサスを埗るのが難しいのか䞍思議に思うかもしれたせん。comp.lang.python ず python-dev メヌリングリストの䞡方で、関数デコレヌタをどのように実装するのがベストなのか、議論が亀わされおきたした。なぜそうしなければならないかずいう明確な理由はありたせんが、いく぀かの問題が最も意芋が分かれおいるようです。

意図の宣蚀」がどこに属するかに぀いおの意芋の盞違。

関数の定矩の最埌で装食や倉換を行うのは最適ではないずいう点では、ほが党員が同意しおいる。それ以䞊に、この情報をどこに眮くべきかに぀いおの明確なコンセンサスはないようだ。
構文䞊の制玄 Pythonは構文的に単玔な蚀語であり、(芖芚的にも蚀語パヌサに関しおも) "物事を台無しにする "こずなく䜕ができお䜕ができないかに぀いお、かなり匷い制玄がありたす。この抂念を初めお知った人たちが、"ああ、そうだ、䜕をやっおいるのかわかった "ず思うように、この情報を構造化する明癜な方法はない。可胜だず思われる最善の方法は、新しいナヌザヌが構文が意味するものに぀いお、荒唐無皜な間違ったメンタル・モデルを䜜らないようにするこずである。
コンセプトに察する党䜓的な䞍慣れさ。代数孊あるいは基本的な算数を䞀通り知っおいる人や、他のプログラミング蚀語を少なくずも1぀䜿ったこずがある人にずっおは、Pythonの倚くは盎感的です。Pythonでデコレヌタの抂念に出䌚う前に、デコレヌタの抂念に觊れたこずがある人はほずんどいないでしょう。この抂念を捉える匷力な既存のミヌムがないのです。
䞀般的に構文の議論は、他の䜕よりも倚くの論争を匕き起こすようです。PEP 308に関連した䞉項挔算子の議論もその䞀䟋です。

背景


珟状では構文サポヌトが望たしいずいうのが䞀般的な意芋です。Guido は第10回 Python カンファレンスの DevDay 基調講挔でデコレヌタの構文サポヌトに぀いお蚀及したした。Michael Hudsonはカンファレンスの盎埌にpython-devでこのトピックを取り䞊げ、最初の括匧付き構文はGareth McCaughanによるcomp.lang.pythonでの以前の提案によるものだずしたした。

クラス定矩ず関数定矩は構文的に䌌おいるので、クラス装食は明らかな次のステップのように思えたすが、Guido はただ玍埗しおおらず、クラス装食は Python 2.4 にはほずんどないでしょう。

この議論は2002幎2月から2004幎7月たでpython-devで継続されたした。䜕癟もの投皿がなされ、人々は倚くの可胜な構文のバリ゚ヌションを提案したした。Guidoは提案のリストをEuroPython 2004に持っお行き、そこで議論が行われたした。その埌、圌はJavaスタむルの@decorator構文を持぀こずに決め、2.4a2で初めお登堎したした。Barry Warsaw はこれを 'pie-decorator' 構文ず名付けたした。これは、デコレヌタ構文ず同時期に起こった Pie-thon Parrot shootout にちなんでおり、たた @ が少しパむに䌌おいるからです。Guido は Python-dev で、华䞋された(倚くの)フォヌムに関するこの蚘事を含め、圌のケヌスを抂説したした。

デコレヌタヌ」ずいう名前に぀いお


この特集に「デコレヌタヌ」ずいう名前を遞んだこずに぀いおは、倚くの䞍満がある。䞻なものは、この名前がGoFブックでの䜿い方ず䞀貫しおいないずいうこずです。decorator'ずいう名前は、おそらくコンパむラの分野での䜿甚、぀たりシンタックスツリヌを歩きながら泚釈を぀けるこずに由来しおいるのだろう。もっずいい名前があるかもしれない。

蚭蚈目暙


新しい構文は

ナヌザヌ定矩の callable や、既存の組み蟌み関数 classmethod() や staticmethod() を含む、任意のラッパヌで動䜜するこず。この芁件は、デコレヌタ構文がラッパヌコンストラクタぞの匕数の受け枡しをサポヌトしなければならないこずも意味したす。
定矩ごずに耇数のラッパヌを扱うこずができたす。
䜕が起こっおいるのかが䞀目瞭然であるこず。少なくずも、新しいナヌザヌが自分のコヌドを曞くずきに、それを無芖しおも倧䞈倫なように䞀目瞭然であるこず。
䞀床説明すれば...芚えやすい」構文であるこず。
将来の拡匵を難しくしない
入力が簡単であるこず。この構文を䜿うプログラムは、非垞に頻繁にこの構文を䜿うこずが予想される。
コヌドを玠早くスキャンするこずを難しくしないこず。すべおの定矩、特定の定矩、あるいは関数が受け付ける匕数を怜玢するのは、䟝然ずしお簡単でなければならない。
蚀語䟝存の゚ディタヌや他の "おもちゃのパヌサヌツヌル "のような二次的なサポヌトツヌルを䞍必芁に耇雑にしない。
将来のコンパむラがデコレヌタを最適化できるようにする。PythonのJITコンパむラがいずれ登堎するこずを期埅するず、デコレヌタの構文を関数定矩の前に眮く必芁がありたす。
珟圚は隠されおいる関数の末尟から、もっず目に぀きやすい前方ぞ移動したす。
Andrew Kuchling氏のブログには、動機ず䜿甚䟋に関する倚くの議論ぞのリンクがある。特に泚目すべきはJim Hugininのナヌスケヌスのリストだ。

Python 2.4a2で実装されおいる関数デコレヌタヌの珟圚の構文は以䞋の通りです

@dec2
@dec1
def func(arg1, arg2, ...):
    pass

は、だいたい次ず等䟡です

def func(arg1, arg2, ...):
    pass
func = dec2(dec1(func))

を倉数funcに代入する必芁はない。デコレヌタヌは関数宣蚀の近くにある。蚘号は、ここで䜕か新しいこずが起こっおいるこずを明らかにしおいる。

適甚順序䞋から䞊の根拠は、関数適甚の通垞の順序ず䞀臎しおいるからである。数孊では、関数の合成(g o f)(x)はg(f(x))ず蚳される。Pythonでは、@g @f def foo()はfoo=g(f(foo))ずなる。

デコレヌタヌ・ステヌトメントが受け入れるこずができるものは限られおおり、任意の匏は機胜しない。グむドは盎感的にこれを奜んだ。

珟圚の構文では、デコレヌタヌ宣蚀でデコレヌタヌを返す関数を呌び出すこずもできる

@decomaker(argA, argB, ...)
def func(arg1, arg2, ...):
    pass

は、だいたい次ず等䟡です

func = decomaker(argA, argB, ...)(func)

デコレヌタヌを返す関数を持぀根拠は、@蚘号の埌を匏ずみなすこずができ構文的には単なる関数に限定されるが、その匏が返すものは䜕でも呌び出されるからである。宣蚀匕数を参照。

なぜ@なのか


Javaでは、最初はJavadocコメントの目印ずしお、その埌Java 1.5でPythonのデコレヌタヌに䌌たアノテヌションに@を䜿った歎史がある。Pythonで@がトヌクンずしお䜿われおいなかったずいうこずは、そのようなコヌドが以前のバヌゞョンのPythonで解析される可胜性がないずいうこずでもあり、埮劙な意味䞊のバグに぀ながる可胜性がありたす。たた、䜕がデコレヌタヌで䜕がデコレヌタヌでないかずいう曖昧さが取り陀かれたこずも意味したす。ずはいえ、@はただかなり恣意的な遞択です。代わりにを䜿うこずを提案する人もいる。

デコレヌタを指定するためにリストのような構文を䜿う構文オプションに぀いおは、 いく぀かの遞択肢が提案された [...|]、[...]、そしお<...>である。

Pythonのデコレヌタは関数型プログラミングのコンセプトずいく぀かの類䌌点がありたす。具䜓的には以䞋の点が挙げられたす。

  1. 高階関数 (Higher-Order Functions):
    デコレヌタは関数を匕数ずしお受け取り、新しい関数を返す高階関数の䞀皮です。関数型プログラミングでも、高階関数は基本的な抂念の䞀぀です。

  2. 関数の合成 (Function Composition):
    デコレヌタを䜿甚するず、関数の前埌に远加の凊理を組み蟌むこずができたす。これは関数を合成するこずで新しい機胜を持たせる、関数型プログラミングの抂念に類䌌しおいたす。

  3. むミュヌタビリティ (Immutability):
    デコレヌタは既存の関数を倉曎するのではなく、新しい関数を䜜成したす。これは関数型プログラミングで重芖されるむミュヌタビリティの考え方に合臎したす。

  4. デコレヌタチェヌン (Decorator Chain):
    耇数のデコレヌタをチェヌンするこずで、関数に察しお耇数の修食を適甚できたす。これも関数型プログラミングの関数合成の考え方に䌌おいたす。

これらの点から、Pythonのデコレヌタは関数型プログラミングのコンセプトず密接に関連しおいるず蚀えたす。

お願い臎したす