Skip to content

Instantly share code, notes, and snippets.

@scardine
Created July 14, 2018 15:35
Show Gist options
  • Save scardine/5163cd8c675e05d06dbb7a75082e2b8c to your computer and use it in GitHub Desktop.
Save scardine/5163cd8c675e05d06dbb7a75082e2b8c to your computer and use it in GitHub Desktop.
Jupyter Notebook for my talk at JustPython
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Novidades do Python 3.7"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"sys.version"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## [PEP 557](https://www.python.org/dev/peps/pep-0557/): Data Classes\n",
"\n",
"Você gosta dos objetos de JavaScript?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"p = {x: 1, y: 2}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"p.x"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"p.y"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Em Python é mais chato:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"p = {\"x\": 1, \"y\": 2}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"p.x"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"p[\"x\"]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Para fazer algo mais parecido com os objetos de JavaScript em Python:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class Point(object):\n",
" def __init__(self, x, y):\n",
" self.x = x\n",
" self.y = y\n",
" \n",
"point = Point(1, 2)\n",
"point"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A representação default é bem feia... Pra melhorar um pouco tem que implementar o método `__repr__`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class Point(object):\n",
" def __init__(self, x, y):\n",
" self.x = x\n",
" self.y = y\n",
" def __repr__(self):\n",
" return f\"Point(x={self.x}, y={self.y})\"\n",
" \n",
"point = Point(1, 2)\n",
"point"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Melhorou um pouco. Vamos testar o operador lógico de igualdade:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"point_a = Point(1, 2)\n",
"point_b = Point(1, 2)\n",
"point_a == point_b"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Novamente precisamos implementar outro magic method (`__eq__`) pra fazer funcionar:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class Point(object):\n",
" def __init__(self, x, y):\n",
" self.x = x\n",
" self.y = y\n",
" def __repr__(self):\n",
" return f\"Point(x={self.x}, y={self.y})\"\n",
" def __eq__(self, other):\n",
" return self.x == other.x and self.y == other.y\n",
" \n",
"point_a = Point(1, 2)\n",
"point_b = Point(1, 2)\n",
"point_a == point_b"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vamos fazer um dicionário de pontos:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"{point_a: 1, point_b: 2}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from hashlib import sha256\n",
"\n",
"class Point(object):\n",
" def __init__(self, x, y):\n",
" self.x = x\n",
" self.y = y\n",
" def __repr__(self):\n",
" return f\"Point(x={self.x}, y={self.y})\"\n",
" def __eq__(self, other):\n",
" return self.x == other.x and self.y == other.y\n",
" def __hash__(self):\n",
" return int(sha256(f\"{self.x},{self.y}\".encode('ascii')).hexdigest(), 16)\n",
" \n",
"point_a = Point(1, 2)\n",
"point_b = Point(2, 1)\n",
"\n",
"{point_a: 1, point_b: 2}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from collections import namedtuple\n",
"\n",
"Point = namedtuple('Point', ['x', 'y'])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"point_a = Point(1, 2)\n",
"point_b = Point(1, 2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# representação\n",
"point_a, point_b"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# igualdade\n",
"point_a == point_b"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# identidade\n",
"{point_a: 1, point_b: 2}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Parece que tudo funciona! Será?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class Point3D(Point):\n",
" def __init__(self, x, y, z):\n",
" super().__init__(x, y)\n",
" self.z = z\n",
" def __repr__(self):\n",
" return f\"Point(x={self.x}, y={self.y}, z={self.z})\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Point3D(1, 2, 3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Entram as Data Classes:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from dataclasses import dataclass\n",
"\n",
"@dataclass\n",
"class Point(object):\n",
" x: int\n",
" y: int"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"@dataclass\n",
"class Point3D(Point):\n",
" z: int"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## [PEP 562](http://www.python.org/dev/peps/pep-0562): Module Attributes Dinâmicos"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Todo mundo sabe que podemos implementar atributos dinâmicos implementando `__getattr__`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class Foo(object):\n",
" def __getattr__(self, name):\n",
" return f\"{name.title()} de Foo é Fola.\"\n",
" \n",
"f = Foo()\n",
"\n",
"f.bar"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora podemos fazer a mesma coisa ao nível de módulos:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# lib.py\n",
"\n",
"from warnings import warn\n",
"\n",
"deprecated_names = [\"funcao_antiga\", ...]\n",
"\n",
"def _funcao_antiga_obsoleta(arg, other):\n",
" ...\n",
"\n",
"def __getattr__(name):\n",
" if name in deprecated_names:\n",
" warn(f\"{name} está obsoleta\", DeprecationWarning)\n",
" return globals()[f\"{name}_obsoleta\"]\n",
" raise AttributeError(f\"module {__name__} não possui um atributo {name}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## [PEP 553](http://www.python.org/dev/peps/pep-0553): Built-in breakpoint()\n",
"\n",
"Já usou o debugger do Python?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def divide(a, b):\n",
" breakpoint()\n",
" return a / b"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"divide(1, 0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"os.environ['PYTHONBREAKPOINT'] = \"pdb\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## [PEP 560](http://www.python.org/dev/peps/pep-0560) e [PEP 563](http://www.python.org/dev/peps/pep-0563): Melhorias nas Anotações de Tipo"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# import annotations\n",
"\n",
"class Point:\n",
"\n",
" def __init__(self, x: int, y: int):\n",
" self.x = x\n",
" self.y = y\n",
"\n",
" def __add__(self, other: Point) -> Point:\n",
" return Point(self.x + other.x, self.y + other.y)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Outras Novidades\n",
"\n",
"Otimizações:\n",
"\n",
"* redução do overhead na chamada de muitos métodos da biblioteca padrão.\n",
"* chamadas de método estão 20% mais rápidas no geral!\n",
"* o tempo de espera na inicialização do Python foi reduzido entre 10 e 30%.\n",
"* o módulo typing está 7 vezes mais rápido.\n",
"\n",
"Miscelanea:\n",
"\n",
"* o módulo time novas funções de maior precisão descritas na [PEP 564](http://www.python.org/dev/peps/pep-0564).\n",
"* 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.\n",
"* “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.\n",
"* se você usa threads concorrentes, o Python 3.7 traz o suporte para variáveis de contexto (parecido com Thread-Local Storage).\n",
"* 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.\n",
"* 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.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.0b1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment