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

一個月前(2月20日),一則新的 PEP 沒有受到任何阻礙就被官方採納了,這麼快的速度,彷佛並很少見。html

然而,更爲高效率的是,僅在半個月內,它的實現就被合入了代碼倉。也就是說,咱們最快有望在 3 天后(3月23日)發佈的 3.9.0 alpha 5 版本中看到它!python

Python 3.9 的發佈計劃:git

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

當前裝飾器的語法爲:express

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
複製代碼

PEP-614 提議將其簡化爲:ide

decorator: '@' namedexpr_test NEWLINE
複製代碼

我已經把 PEP 全文翻譯出來了,Github 地址:dwz.date/RV9測試

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

下面是 PEP 翻譯後的核心內容摘錄,先跟你們一睹爲快吧:idea

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

概要

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

# Do stuff with the list of buttons...
複製代碼

當前,這些裝飾必須重寫成這樣(譯註:上方是假想的最優寫法,但 Python 還不支持,只能用下方的囉嗦寫法):

button_0 = buttons[0]

@button_0.clicked.connect
def spam():
    ...

button_1 = buttons[1]

@button_1.clicked.connect
def eggs():
    ...
複製代碼

此外,當前的語法太過寬鬆,以致於沒法將更復雜的裝飾器表達式結合在一塊兒。也就是說,當前的限制並無像預期的那樣去禁止任意複雜的表達式,而是使它們變得更醜陋且效率低下:

# Identity function hack:

def _(x):
    return x

@_(buttons[0].clicked.connect)
def spam():
    ...

# eval hack:

@eval("buttons[1].clicked.connect")
def eggs():
    ...
複製代碼

原理

容許任意表達式

在至關長的一段時間內,容許任意有效表達式的決定(而不只僅是放寬當前的限制,如容許取下標),已被視爲裝飾器語法發展的下一個瓜熟蒂落的步驟。正如Guido 在另外一個郵件列表討論中所說

我以爲強制約束它沒有什麼道理,由於它已再也不是一個普通的表達式。

若對語法進行特殊設置以容許某些有用的用法,只會使當前狀況複雜化,而且幾乎能確定此過程會在未來的某個時間重複。此外,這種語法上的改變的目的之一是阻止使用上述的 eval 和反模式的 identity-function 之類的誘惑。

簡而言之:若是要刪除一些限制,咱們應該刪除全部限制。

什麼算一個「表達式」

在本文檔中,「表達式」一詞的用法與《Python語言參考》中定義的相同。能夠歸納爲「任何在 if、elif 和 while 塊中測試爲有效的內容」。

這與可能更流行的定義稍有不一樣,後者能夠歸納爲「任何做爲有效字符串輸入給 eval 的內容」。

前一個「表達式」的定義更方便,由於它很是貼合咱們的需求,而且能夠重用被現有語言結構所容許的語法。與其它定義相比,它有兩個細微的差別:

一、元組必須加括號

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

可是我不會容許逗號,決不可能同意這樣:

@f, g
def pooh(): ...
複製代碼

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

二、賦值表達式不需括號

在這裏,語法的選擇是明確的。PEP 572解釋了爲何須要在頂級表達式語句的周圍加上括號:

加入此規則是爲了簡化用戶在賦值語句和賦值表達式之間的選擇——沒有令二者都生效的語法位置。

因爲賦值語句在此處無效,所以賦值表達式就沒必要帶括號。

(譯註:賦值表達式,即 Assignment Expressions 或 Named Expressions,是 Python 3.8 引入的新特性,就是它引入了新的「:=」海象操做符。)

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

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

附錄:

PEP614英文:www.python.org/dev/peps/pe…

PEP614中文:dwz.date/RV9

PEP中文翻譯計劃:github.com/chinesehuaz…

相關文章
相關標籤/搜索