Novidades do Python 3.7

Paulo Scardine
Python Weekly Brazil
5 min readJun 29, 2018

Acabou de sair a versão 3.7 do Python — conforme prometido no post sobre data classes segue um resumo das novidades que achei mais interessantes.

PEP 557: Data Classes

Já fiz um post detalhado sobre o assunto então vou apenas dizer que este recurso é uma forma mais concisa a prática de criar objetos para armazenar dados em properties (estilo Javascript) que é mais conveniente do que Named Tuples —em termos de “poder de fogo” fica no meio do caminho entre Named Tuples e o módulo attrs que na minha opinião equilibrou bem simplicidade e funcionalidade. Se você usa Named Tuples definitivamente vai querer experimentar Data Classes. Para maiores detalhes veja meu artigo anterior ou beba direto na fonte lendo a PEP 557.

PEP 562: Module Attributes Dinâmicos

Com objetos você pode sobrescrever o método __getattr__ de forma a criar propriedades dinâmicas, mas até agora não existia uma forma de fazer a mesma coisa para módulos. É bastante útil quando você muda a API do módulo:

No exemplo acima, se você tentar usar lib.funcao_antiga(‘foo’, ‘bar’) vai emitir um deprecation warning. Tem mais coisas, como poder definir uma função __dir__() para personalizar o resultado de import lib; dir(lib). Para beber direto na fonte veja a PEP 562.

PEP 553: Built-in breakpoint()

Se você usa o debugger do Python, provavelmente já escreveu alguma coisa como:

Se você quiser usar outro debugger, por exemplo, o ipdb que é o debugger do IPython, tem que mudar a linha para import ipdb; ipdb.set_trace() e se quiser remover o breakpoint tem que comentar essa linha. Já com o novo builtin do Python 3.7 você só precisa fazer o seguinte:

Para desativar o breakpoint() você pode setar a variável de ambiente PYTHONBREAKPOINT=0. E se quiser mudar para outro debugger, por exemplo, o PuDB (um debugger visual para linha de comando) você faz o seguinte:

O comando breakpoint() se encarrega de importar o módulo pudb e chamar a função set_trace() (obviamente o PuDB precisa estar instalado). Legal, não? Veja a PEP 553 bem como a documentação das funçõesbreakpoint() esys.breakpointhook() para maiores detalhes.

PEP 560 e PEP 563: Melhorias nas Anotações de Tipo

Type hinting e type annotations tem estado em constante desenvolvimento através da série Python 3. O typing system do Python está bem estável, mas o Python 3.7 tras algumas melhorias: performance, core support, e forward references.

Python ainda é uma linguagem dinamicamente tipada, ou seja, não faz nenhuma verificação de tipo em runtime (a menos que você esteja usando um pacote como oenforce). Dessa forma, adicionar type hints teoricamente não deve ter nenhum impacto na performance, certo?

Errado! Se você estiver carregando o módulo typing, este é um dos módulos mais lentos da biblioteca padrão do Python. A PEP 560 implementa boa parte do suporte proporcionado pelo módulo typing no core do Python 3.7, o que torna esse módulo muito mais rápido. Você não precisa saber dos detalhes a menos que esteja trabalhando no desenvolvimento do Python 4, então simplesmente relaxe e desfrute da performance melhorada.

Uma das minhas respostas mais bem votadas do StackOverflow é sobre como declarar que um método retorna a própria classe da qual ele faz parte. Até o Python 3.6, se você tentar declarar que o método retorna a própria classe vai tomar um NameErrorna cara:

class Position:

def __init__(self, x: int, y: int):
self.x = x
self.y = y

def __add__(self, other: Position) -> Position:
return Position(self.x + other.x, self.y + other.y)

Até antes do 3.7 você tinha que usar uma string:

class Position:
...
def __add__(self, other: 'Position') -> 'Position':
...

Já no Python 3.7 você pode usar o seguinte:

from __future__ import annotations

class Position:
def __add__(self, other: Position) -> Position:
...

Esse vai passar a ser o comportamento default no Python 4. Se estiver interessado nos detalhes veja PEP 484, PEP 563 e PEP 560.

Otimizações

A cada nova versão da série 3 temos sido brindados com novas otimizações. A versão 3.7 não é diferente e traz algumas melhorias significativas:

  • Redução do overhead na chamada de muitos métodos da biblioteca padrão.
  • Chamadas de método estão 20% mais rápidas no geral!
  • O tempo de espera na inicialização do Python foi reduzido entre 10 e 30%.
  • O módulo typing está 7 vezes mais rápido.

Muitas outras otimizações especializadas foram incluidas, para maiores detalhes veja esta lista. Resumindo, Python 3.7 é rápido. Simplesmente, é a versão do CPython mais rápida até hoje então vamos acabar de vez com o mito de que o Python 3 é mais lento que o Python 2 — isso é uma grande mentira.

Outras Novidades Interessantes

Tem algumas outras coisas dignas de nota que talvez eu entre em detalhes em um outro post:

  • o módulo time novas funções de maior precisão descritas na PEP 564.
  • a nova implementação dos dicts na versão 3.6 passou a preservar a ordem de inserção (antes disso a ordem das chaves era aleatória) mas na versão 3.7 a preservação da ordem de inserção das chaves passou a ser uma garantida na especificação da linguagem.
  • async” and “await” passaram a ser palavras reservadas (keywords) e o módulo asyncio ganhou um face lift razoável, incluindo o suporte para context variables (veja abaixo) e melhorias na performance. Incluindo o novo asyncio.run() que dispensa a criação explícita de um event loop.
  • se você usa threads concorrentes, o Python 3.7 traz o suporte para variáveis de contexto (parecido com Thread-Local Storage).
  • o novo módulo importlib.resources da biblioteca padrão facilita o empacotamento de uma aplicação Python dispensando que você mantenha o caminho para recursos do programa dinamicamente.
  • novas flags-X interessantes nas opções de linha de comando do interpretador Python, em expecial a -X importtime que mostra quanto tempo a aplicação está demorando nos imports.

E ai, vale a pena fazer upgrade?

Eu penso que sim, vale a pena só pelas melhorias de performance. Lógico, fazer upgrade de software de produção dá trabalho e exige muito teste, mas se a sua conta de nuvem é alta a mudança pode economizar alguns milhares de dólares por ano.

Apesar de muitas melhorias estarem disponíveis na forma de backports para a versão 3.6, acho que é um pouco cedo para tornar o Python 3.7 uma dependência do seu projeto.

Um grande abraço e até a semana que vem.

--

--