PEP 572 foi aceita, inacreditável!

Até achei que fosse uma pegadinha e olhei no calendário para ver se não era primeiro de abril. Mas parece que a PEP 572 foi mesmo aceita pelo BDFL:

Thank you all. I will accept the PEP as is. I am happy to accept *clarification* updates to the PEP if people care to submit them as PRs to the peps repo (https://github.com/python/peps), and that could even (to some extent) include summaries of discussion we’ve had, or outright rejected ideas. But even without any of those I think the PEP is very clear so I will not wait very long (maybe a week). — GvR

Por que o alvoroço? Na maioria das linguagens C-like você pode fazer uma atribuição dentro da condição de um loop. Por exemplo, você pode abrir o console javascript do navegador agora e fazer:

var x = 0; while ((x = x + 1) < 10) console.log(x);

O resultado deve ser alguma coisa como:

1
2
3
4
5
6
7
8
9
<- undefined

Mas se você tentar o equivalente em Python:

x = 0
while (x = x + 1) < 10: print(x)

O resultado vai ser o seguinte:

File "<ipython-input-16-0edd449ba07d>", line 1
while (x = x + 1) < 10: print(x)
^
SyntaxError: invalid syntax

Isso porque em JavaScript a operação de atribuição é uma expressão (expression) e em Python é uma declaração (statement). A cláusula de condição em um loop é uma expressão. Segundo a documentação:

Note that in Python, unlike C, assignment cannot occur inside expressions. C programmers may grumble about this, but it avoids a common class of problems encountered in C programs: typing = in an expression when ==was intended.

É por isso que em Python você praticamente só vê uma expressão while escrita como while True —é tão raro ver uma condição diferente de True em loops while no Python que normalmente a gente considera um code-smell.

Faz anos que muita gente pede uma expressão de atribuição e o Guido van Rossum sempre foi contra, pelas razões acima… Até agora! Porque no Python 3.8 você vai poder fazer o seguinte:

x = 0
while (x := x + 1) < 10: print(x)

Notou o novo operador de atribuição? É “:=”, dois-pontos seguido de igual. Revisitando o nosso loop while clássico, claro, um while True:

while True:
old = total
total += term
if old == total:
return total
term *= mx2 / (i*(i+1))
i += 2

Agora o mesmo loop poderia ser escrito como:

while total != (total := total + term):
term *= mx2 / (i*(i+1))
i += 2
return total

O que você acha? Por memos que a gente sinta falta de “atribuição como expression” na linguagem, temos que admitir que fica mais conciso.

Só falta agora o Guido aceitar a sintaxe opcional que usa chaves em vez de espaços para delimitar blocos de código:

from __future__ import braces
def double(arg) {
return 2 * arg
}

Um grande abraço e atá a próxima.

PS:

A declaração from __future__ import braces é um Easter-egg clássico em Python:

from __future__ import braces
File "<ipython-input-17-2aebb3fc8ecf>", line 1
from __future__ import braces
^
SyntaxError: not a chance
^^^^^^^^^^^^

Sem chance! Quer dizer, até agora, mas quem sabe…