天天看點

Python 3.9 新特性:任意表達式可作為裝飾器!Do stuff with the list of buttons...Do stuff with the list of buttons...Identity function hack:eval hack:

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

一個月前(2月20日),一則新的 PEP 沒有受到任何阻礙就被官方采納了,這麼快的速度,似乎并不多見。

然而,更為高效率的是,僅在半個月内,它的實作就被合入了代碼倉。也就是說,我們最快有望在 3 天後(3月23日)釋出的 3.9.0 alpha 5 版本中看到它!

Python 3.9 的釋出計劃:

這個 PEP 就是 PEP-614:放寬對裝飾器的文法限制。

目前裝飾器的文法為:

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE

PEP-614 提議将其簡化為:

decorator: '@' namedexpr_test NEWLINE

我已經把 PEP 全文翻譯出來了,Github 位址:

http://dwz.date/RV9

放寬對裝飾器的限制,這對之前的用法沒有影響,但至于會帶來哪些新的好處,我還不知道有哪些現實的例子。

下面是 PEP 翻譯後的核心内容摘錄,先跟大家一睹為快吧:

--------------摘錄分割線----------------

概要

Python 目前要求所有裝飾器都由 dotted name 組成,可選地帶一個調用。本 PEP 提議消除這些限制,并允許任何有效的表達式作為裝飾器。

(譯注:dotted name,指的是裝飾器在“@”符号後是“xxx”或“xxx.yyy”這種格式。沒有很好地譯法,故未譯。)

動機

在最初引入裝飾器時,Guido表示對其文法作限制是一種偏好,而不是因為技術的要求:

我對此有一種直覺。我不确定它來自哪裡,但我就是有……是以,盡管将來将文法更改為 @test 相當容易,但我仍想堅持使用更受限的形式,除非給出了真正的使用 @test 會增加可讀性的用例。

盡管在實踐中很少遇到問題,但是多年來,BPO問題和郵件清單文章不斷出現,要求去除限制。最近的一封郵件(它促成了本提案)提供了一段很好的使用 PyQt5 庫的示例代碼,如果放寬現有的限制,它将變得更具可讀性、道地性和可維護性。

稍作修改的示例:

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():

...
           

目前,這些裝飾必須重寫成這樣(譯注:上方是假想的最優寫法,但 Python 還不支援,隻能用下方的啰嗦寫法):

button_0 = buttons[0]

@button_0.clicked.connect

...
           

button_1 = buttons[1]

@button_1.clicked.connect

...           

此外,目前的文法太過寬松,以至于無法将更複雜的裝飾器表達式結合在一起。也就是說,目前的限制并沒有像預期的那樣去禁止任意複雜的表達式,而是使它們變得更醜陋且效率低下:

Identity function hack:

def _(x):

return x
           

@_(buttons[0].clicked.connect)

...
           

eval hack:

@eval("buttons[1].clicked.connect")

...           

原理

允許任意表達式

在相當長的一段時間内,允許任意有效表達式的決定(而不僅僅是放寬目前的限制,如允許取下标),已被視為裝飾器文法發展的下一個順理成章的步驟。正如Guido 在另一個郵件清單讨論中所說:

我覺得強制限制它沒有什麼道理,因為它已不再是一個普通的表達式。

若對文法進行特殊設定以允許某些有用的用法,隻會使目前情況複雜化,并且幾乎能肯定此過程會在将來的某個時間重複。此外,這種文法上的改變的目的之一是阻止使用上述的 eval 和反模式的 identity-function 之類的誘惑。

簡而言之:如果要删除一些限制,我們應該删除所有限制。

什麼算一個“表達式”

在本文檔中,“表達式”一詞的用法與《Python語言參考》中定義的相同。可以概括為“任何在 if、elif 和 while 塊中測試為有效的内容”。

這與可能更流行的定義稍有不同,後者可以概括為“任何作為有效字元串輸入給 eval 的内容”。

前一個“表達式”的定義更友善,因為它非常貼合我們的需求,并且可以重用被現有語言結構所允許的文法。與其它定義相比,它有兩個細微的差異:

1、元組必須加括号

這是基于 Guido 在同一封郵件中的洞察。緊接着前面的引述:

但是我不會允許逗号,決不可能贊成這樣:

@f, g

def pooh(): ...

确實,它可能甚至導緻沒有經驗的讀者得出結論,認為正在使用多個裝飾器,就像它們被堆疊了一樣。這裡要求加括号,可以使意圖變得清晰,而無需施加進一步的限制和複雜文法。

2、指派表達式不需括号

在這裡,文法的選擇是明确的。PEP 572解釋了為什麼需要在頂級表達式語句的周圍加上括号:

加入此規則是為了簡化使用者在指派語句和指派表達式之間的選擇——沒有令兩者都生效的文法位置。

由于指派語句在此處無效,是以指派表達式就不必帶括号。

(譯注:指派表達式,即 Assignment Expressions 或 Named Expressions,是 Python 3.8 引入的新特性,就是它引入了新的“:=”海象操作符。)

-----------------正文分割線---------------

PEP 的全文翻譯已收錄在 Github 的《PEP中文翻譯計劃》中,目前已有 20+ 篇 PEP 翻譯,歡迎感興趣的同學查閱&參與翻譯。

附錄:

PEP614英文:

https://www.python.org/dev/peps/pep-0614/

PEP614中文:

PEP中文翻譯計劃:

https://github.com/chinesehuazhou/peps-cn

原文位址

https://www.cnblogs.com/pythonista/p/12533284.html