1. 程式人生 > >Python 3.9 新特性:任意表達式可作為裝飾器!

Python 3.9 新特性:任意表達式可作為裝飾器!

一個月前(2月20日),一則新的 PEP 沒有受到任何阻礙就被官方採納了,這麼快的速度,似乎並不多見。 然而,更為高效率的是,僅在半個月內,它的實現就被合入了程式碼倉。也就是說,我們最快有望在 3 天后(3月23日)釋出的 3.9.0 alpha 5 版本中看到它! Python 3.9 的釋出計劃: ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gd0eie2o07j20ig0gpmyc.jpg) 這個 PEP 就是 **PEP-614:放寬對裝飾器的語法限制。** 當前裝飾器的語法為: ```python decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE ``` PEP-614 提議將其簡化為: ```python decorator: '@' namedexpr_test NEWLINE ``` 我已經把 PEP 全文翻譯出來了,Github 地址:http://dwz.date/RV9 放寬對裝飾器的限制,這對之前的用法沒有影響,但至於會帶來哪些新的好處,我還不知道有哪些現實的例子。 下面是 PEP 翻譯後的核心內容摘錄,先跟大家一睹為快吧: --------------摘錄分割線---------------- ### 概要 Python 當前要求所有裝飾器都由 dotted name 組成,可選地帶一個呼叫。本 PEP 提議消除這些限制,並允許任何有效的表示式作為裝飾器。 (譯註:dotted name,指的是裝飾器在“@”符號後是“xxx”或“xxx.yyy”這種格式。沒有很好地譯法,故未譯。) ### 動機 在最初引入裝飾器時,[Guido表示](https://mail.python.org/archives/list/python-dev%40python.org/message/P3JD24UFFPZUUDANOAI6GZAPIGY4CVK7)對其語法作限制是一種偏好,而不是因為技術的要求: > 我對此有一種直覺。我不確定它來自哪裡,但我就是有……因此,儘管將來將語法更改為 @test 相當容易,但我仍想堅持使用更受限的形式,除非給出了真正的使用 @test 會增加可讀性的用例。 儘管在實踐中很少遇到問題,但是多年來,[BPO問題](https://bugs.python.org/issue19660)和[郵件列表帖子](https://mail.python.org/archives/list/python-ideas%40python.org/thread/UQOCJH3KOPBP7P3AVNS3OYBGZPR3V2WO/%23CAOXYF4GV76AFJNCYSYMQTBM7CIPPH5M#CAOXYF4GV76AFJNCYSYMQTBM7CIPPH5M)不斷出現,要求去除限制。[最近的一封郵件](https://mail.python.org/archives/list/python-ideas%40python.org/thread/WOWD4P323DYDIGUQVWMESDWUG6QOW4MP)(它[促成了本提案](https://mail.python.org/archives/list/python-ideas%40python.org/message/FKE7ZFGUDCU5WVOE2QTD5XGMCNCOMETV))提供了一段很好的使用 `PyQt5` 庫的示例程式碼,如果放寬現有的限制,它將變得更具可讀性、地道性和可維護性。 稍作修改的示例: ```python buttons = [QPushButton(f'Button {i}') for i in range(10)] # Do stuff with the list of buttons... @buttons[0].clicked.connect def spam(): ... @buttons[1].clicked.connect def eggs(): ... # Do stuff with the list of buttons... ``` 當前,這些裝飾必須重寫成這樣(譯註:上方是假想的最優寫法,但 Python 還不支援,只能用下方的囉嗦寫法): ```python button_0 = buttons[0] @button_0.clicked.connect def spam(): ... button_1 = buttons[1] @button_1.clicked.connect def eggs(): ... ``` 此外,當前的語法太過寬鬆,以至於無法將更復雜的裝飾器表示式結合在一起。也就是說,當前的限制並沒有像預期的那樣去禁止任意複雜的表示式,而是使它們變得更醜陋且效率低下: ```python # Identity function hack: def _(x): return x @_(buttons[0].clicked.connect) def spam(): ... # eval hack: @eval("buttons[1].clicked.connect") def eggs(): ... ``` ### 原理 #### 允許任意表達式 在相當長的一段時間內,允許任意有效表示式的決定(而不僅僅是放寬當前的限制,如允許取下標),已被視為裝飾器語法發展的下一個順理成章的步驟。正如[Guido 在另一個郵件列表討論中所說](https://mail.python.org/archives/list/python-ideas%40python.org/message/CAOXYF4GV76AFJNCYSYMQTBM7CIPPH5M): > 我覺得強制約束它沒有什麼道理,因為它已不再是一個普通的表示式。 若對語法進行特殊設定以允許某些有用的用法,只會使當前情況複雜化,並且幾乎能肯定此過程會在將來的某個時間重複。此外,這種語法上的改變的目的之一是阻止使用上述的 eval 和反模式的 identity-function 之類的誘惑。 簡而言之:如果要刪除一些限制,我們應該刪除所有限制。 #### 什麼算一個“表示式” 在本文件中,“表示式”一詞的用法與《[Python語言參考](https://docs.python.org/3.9/reference/expressions.html%23grammar-token-expression#grammar-token-expression)》中定義的相同。可以概括為“任何在 if、elif 和 while 塊中測試為有效的內容”。 這與可能更流行的[定義](https://docs.python.org/3/glossary.html%23term-expression#term-expression)稍有不同,後者可以概括為“任何作為有效字串輸入給 eval 的內容”。 前一個“表示式”的定義更方便,因為它非常貼合我們的需求,並且可以重用被現有語言結構所允許的語法。與其它定義相比,它有兩個細微的差異: ##### 1、元組必須加括號 這是基於 Guido 在同一封郵件中的洞察。緊接著前面的引述: > 但是我不會允許逗號,決不可能贊成這樣: > > ```python > @f, g > def pooh(): ... > ``` 確實,它可能甚至導致沒有經驗的讀者得出結論,認為正在使用多個裝飾器,就像它們被堆疊了一樣。這裡要求加括號,可以使意圖變得清晰,而無需施加進一步的限制和複雜語法。 ##### 2、賦值表示式不需括號 在這裡,語法的選擇是明確的。[PEP 572](https://www.python.org/dev/peps/pep-0572)解釋了為什麼需要在頂級表示式語句的周圍加上括號: > 加入此規則是為了簡化使用者在賦值語句和賦值表示式之間的選擇——沒有令兩者都生效的語法位置。 由於賦值語句在此處無效,因此賦值表示式就不必帶括號。 (譯註:賦值表示式,即 Assignment Expressions 或 Named Expressions,是 Python 3.8 引入的新特性,就是它引入了新的“:=”海象操作符。) -----------------正文分割線--------------- PEP 的全文翻譯已收錄在 Github 的《[PEP中文翻譯計劃](https://github.com/chinesehuazhou/peps-cn)》中,目前已有 20+ 篇 PEP 翻譯,歡迎感興趣的同學查閱&參與翻譯。 附錄: PEP614英文:[https://www.python.org/dev/peps/pep-0614/](https://www.python.org/dev/peps/pep-0614/) PEP614中文:[http://dwz.date/RV9](http://dwz.date/RV9) PEP中文翻譯計劃:[https://github.com/chinesehuazhou/peps-cn](https://github.com/chinesehuazhou/p