先日、PEP 614 (Relaxing Grammar Restrictions On Decorators) が Final になったというコミットを見かけました。
そこで、今回は PEP 614 を読んでみようと思います。
概要
-
これまでデコレータに利用できるのは
dotted_name
と呼ばれる、.
つきの名前のみだった -
そのため、配列アクセスや辞書アクセスといった「式」の類はデコレータには使えなかった
buttons = [QPushButton(f'Button {i}') for i in range(10)] @buttons[0].clicked.connect # => NG def spam(): ...
-
文法を拡張して、デコレータに「式」を受け付けるようにした
-
Python 3.9 から利用できます。
アプローチ
いままでの文法が
decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
だったのを
decorator: '@' namedexpr_test NEWLINE
に変更しました。以上。
って、それだと分かりづらいですね。
namedexpr_test
は Python の式(expression)を指す文法要素です。
式に該当するのは以下のものです (6. 式 (expression) — Python 3.8.3 ドキュメント より)。
- 6.1. 算術変換 (arithmetic conversion)
- 6.2. アトム、原子的要素 (atom)
- 6.2.1. 識別子 (identifier、または名前 (name))
- 6.2.2. リテラル
- 6.2.3. 丸括弧形式 (parenthesized form)
- 6.2.4. リスト、集合、辞書の表示
- 6.2.5. リスト表示
- 6.2.6. 集合表示
- 6.2.7. 辞書表示
- 6.2.8. ジェネレータ式
- 6.2.9. Yield 式
- 6.2.9.1. ジェネレータ-イテレータメソッド
- 6.2.9.2. 使用例
- 6.2.9.3. 非同期ジェネレータ関数 (asynchronous generator function)
- 6.2.9.4. 非同期ジェネレータイテレータメソッド
- 6.3. プライマリ
- 6.3.1. 属性参照
- 6.3.2. 添字表記 (subscription)
- 6.3.3. スライス表記 (slicing)
- 6.3.4. 呼び出し (call)
- 6.4. Await 式
- 6.5. べき乗演算 (power operator)
- 6.6. 単項算術演算とビット単位演算 (unary arithmetic and bitwise operation)
- 6.7. 二項算術演算 (binary arithmetic operation)
- 6.8. シフト演算 (shifting operation)
- 6.9. ビット単位演算の二項演算 (binary bitwise operation)
- 6.10. 比較
- 6.10.1. 値の比較
- 6.10.2. 所属検査演算
- 6.10.3. 同一性の比較
- 6.11. ブール演算 (boolean operation)
- 6.12. 代入式
- 6.13. 条件式 (Conditional Expressions)
- 6.14. ラムダ (lambda)
- 6.15. 式のリスト
いろいろありますね。これらがデコレータに利用できるようになったというわけです。
定義場所によっては使えないものもある(await とか)ことには注意してください。
例
デコレータに lambda 式を使ってみたり...
>>> @lambda f: f
... def foo(): pass
...
三項演算子的な if else を使ってみたり...
>>> x = lambda f: f
>>> y = lambda f: f
>>> @x if True else y
... def foo(): pass
...
もちろん、配列も使えます。
>>> deco = [lambda f: f]
>>> @deco[0]
... def foo(): pass
...
感想
-
いままで dotted_name で困っていなかったので、嬉しさがあまりピンとこない
-
デコレータの配列や辞書で嬉しいことがあるのかも…?
-
すごく気持ち悪いコードが書けてしまうので、容量用法には注意が必要です。
>>> @x := staticmethod # 代入式 (3.9 より) ... def foo(): pass ...