├── ned ├── imgs │ ├── leo1.png │ ├── leo2.png │ ├── leo3.png │ ├── leo4.png │ ├── leo5.png │ ├── ned1.png │ ├── ned10.png │ ├── ned11.png │ ├── ned12.png │ ├── ned13.png │ ├── ned14.png │ ├── ned15.png │ ├── ned16.png │ ├── ned2.png │ ├── ned3.png │ ├── ned4.png │ ├── ned5.png │ ├── ned6.png │ ├── ned7.png │ ├── ned8.png │ └── ned9.png ├── README.md ├── names-and-values-01.ipynb └── names-and-values-02.ipynb ├── fluent └── README.md ├── web-persistence ├── README.md ├── web-services.ipynb └── persistence-serialization.ipynb ├── alunos ├── README.md ├── closures01.ipynb ├── lambda01.ipynb ├── functors02.ipynb ├── functors01.ipynb └── closures02.ipynb ├── README.md ├── oop ├── README.md ├── extra │ ├── monkey-patching.ipynb │ └── .ipynb_checkpoints │ │ └── monkey-patching-checkpoint.ipynb └── examples │ ├── tv-remote.ipynb │ ├── bank-account.ipynb │ └── address-book.ipynb └── RegexOne.ipynb /ned/imgs/leo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/leo1.png -------------------------------------------------------------------------------- /ned/imgs/leo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/leo2.png -------------------------------------------------------------------------------- /ned/imgs/leo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/leo3.png -------------------------------------------------------------------------------- /ned/imgs/leo4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/leo4.png -------------------------------------------------------------------------------- /ned/imgs/leo5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/leo5.png -------------------------------------------------------------------------------- /ned/imgs/ned1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned1.png -------------------------------------------------------------------------------- /ned/imgs/ned10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned10.png -------------------------------------------------------------------------------- /ned/imgs/ned11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned11.png -------------------------------------------------------------------------------- /ned/imgs/ned12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned12.png -------------------------------------------------------------------------------- /ned/imgs/ned13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned13.png -------------------------------------------------------------------------------- /ned/imgs/ned14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned14.png -------------------------------------------------------------------------------- /ned/imgs/ned15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned15.png -------------------------------------------------------------------------------- /ned/imgs/ned16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned16.png -------------------------------------------------------------------------------- /ned/imgs/ned2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned2.png -------------------------------------------------------------------------------- /ned/imgs/ned3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned3.png -------------------------------------------------------------------------------- /ned/imgs/ned4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned4.png -------------------------------------------------------------------------------- /ned/imgs/ned5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned5.png -------------------------------------------------------------------------------- /ned/imgs/ned6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned6.png -------------------------------------------------------------------------------- /ned/imgs/ned7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned7.png -------------------------------------------------------------------------------- /ned/imgs/ned8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned8.png -------------------------------------------------------------------------------- /ned/imgs/ned9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leobezerra/python-hero/master/ned/imgs/ned9.png -------------------------------------------------------------------------------- /fluent/README.md: -------------------------------------------------------------------------------- 1 | # "Python Fluente" 2 | 3 | Esta série de notebooks foi criada a partir da adaptação dos capítulos do livro de mesmo nome de Luciano Ramalho. 4 | 5 | * [Procedimentos como objetos](fluent01.ipynb) 6 | 7 | ### Disclaimer 8 | * Autor: Leonardo Bezerra 9 | -------------------------------------------------------------------------------- /ned/README.md: -------------------------------------------------------------------------------- 1 | # "Facts and myths about Python names and values" 2 | 3 | Esta série de notebooks foi criada a partir da adaptação do post de mesmo nome de Ned Batchelder. 4 | 5 | * [Parte 01](names-and-values-01.ipynb) 6 | * [Parte 02](names-and-values-02.ipynb) 7 | 8 | ### Disclaimer 9 | * Autor: Leonardo Bezerra 10 | -------------------------------------------------------------------------------- /web-persistence/README.md: -------------------------------------------------------------------------------- 1 | # "Decoradores e Persitência" 2 | 3 | Esta série de notebooks foi criada a partir da adaptação de um minicurso de Flask com bancos de dados não-relacionais de Lucas Castro. 4 | 5 | * [Web services com Flask](web-services.ipynb) 6 | * [Persistência e serialização](persistence-serialization.ipynb) 7 | 8 | ### Disclaimer 9 | * Autor: Leonardo Bezerra 10 | -------------------------------------------------------------------------------- /alunos/README.md: -------------------------------------------------------------------------------- 1 | # "Procedimentos como objetos" 2 | 3 | Esta série de notebooks foi criada pelos alunos de Linguagem de programação 2 (2018.2, turma 03) do Bacharelado em Tecnologia da Informação da UFRN. 4 | 5 | * [Funções anônimas](lambda01.ipynb) 6 | * [Closure 01](closures01.ipynb) 7 | * [Closure 02](closures02.ipynb) 8 | * [Functors 01](functors01.ipynb) 9 | * [Functors 02](functors02.ipynb) 10 | 11 | ### Disclaimer 12 | * Autor: Leonardo Bezerra 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Hero 2 | 3 | Este repositório reúne notebooks adaptados a partir de palestras ou posts sobre Python encontrados na web. 4 | 5 | * ["Facts and myths about Python names and values", de Ned Batchelder](ned/) 6 | * ["Using regular expressions in Python 3", do site RegexOne](RegexOne.ipynb) 7 | * ["Fluent Python", de Luciano Ramalho](fluent/) 8 | * ["Decoradores e persistência", de Lucas Castro](web-persistence/) 9 | * ["Procedimentos como objetos", dos alunos de LP2 (2018.2, T03)](alunos/) 10 | * ["Programação orientada a objetos", do site python-course.eu](oop/) 11 | 12 | Extra 13 | * ["Monkey patching"](oop/extra/monkey-patching.ipynb) 14 | 15 | ### Disclaimer 16 | * Autor: Leonardo Bezerra 17 | -------------------------------------------------------------------------------- /oop/README.md: -------------------------------------------------------------------------------- 1 | # "Programação orientada a objetos" 2 | 3 | Esta série de notebooks foi criada a partir da adaptação do Python 3 Tutorial do site [python-course.eu](https://www.python-course.eu/python3_object_oriented_programming.php). 4 | 5 | * [Abstração de dados, encapsulamento de dados e ocultação da informação](oop01.ipynb) 6 | * [Escopo de instância versus escopo de classe](oop02.ipynb) 7 | * [Herança e polimorfismo](oop03.ipynb) 8 | * [O que vem antes de padrões de projeto](oop04.ipynb) 9 | 10 | Práticas de POO 11 | * [Agenda de contatos](examples/address-book.ipynb) 12 | * [Controle remoto](examples/tv-remote.ipynb) 13 | * [Conta e agência bancária](examples/bank-account.ipynb) 14 | 15 | ### Disclaimer 16 | * Autor: Leonardo Bezerra 17 | -------------------------------------------------------------------------------- /web-persistence/web-services.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Decoradores e persistência" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Este notebook é parte da série \"Decoradores e persistência\", adaptada de um minicurso ofertado por [Lucas Castro](https://br.linkedin.com/in/lucasmcastro), da [Evolux](https://evolux.net.br)." 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Web services com Flask" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "Flask é um microframework que permite criar caminhos para receber requisições Web, tratá-las e respondê-las como se deseja.\n", 29 | "\n", 30 | "Com Flask, criar um serviço web é muito simples usando decoradores." 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "### Instanciando um objeto Flask" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "O primeiro passo para criar um serviço web com Flask é importar a classe ```Flask``` do módulo ```flask``` e instanciar um objeto desta classe. \n", 45 | "\n", 46 | "* **Obs**: o parâmetro especial ```name``` é a forma como o interpretador Python identifica o nome do script sendo executado. Por conveção, criamos o objeto Flask com o nome do próprio script para facilitar identificação posterior." 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "metadata": { 53 | "collapsed": true 54 | }, 55 | "outputs": [], 56 | "source": [ 57 | "from flask import Flask\n", 58 | "app = Flask(__name__)" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": {}, 64 | "source": [ 65 | "### Criando caminhos de requisição e procedimentos para tratá-las" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "Criar uma caminho para receber requisições é bastante simples: basta decorar um procedimento usando o método decorador ```Flask.route()```.\n", 73 | "\n", 74 | "O procedimento (ou método decorado) passa a ser vinculado ao caminho de requisição criado, sendo usado para tratar estas requisições.\n", 75 | "\n", 76 | "Veja alguns exemplos:" 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "metadata": {}, 82 | "source": [ 83 | "* Um *hello world* simples:" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": null, 89 | "metadata": { 90 | "collapsed": true 91 | }, 92 | "outputs": [], 93 | "source": [ 94 | "@app.route('/')\n", 95 | "def hello_world():\n", 96 | " return 'Hello, World!'" 97 | ] 98 | }, 99 | { 100 | "cell_type": "markdown", 101 | "metadata": {}, 102 | "source": [ 103 | "* Um gerador de números aleatórios:" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": null, 109 | "metadata": { 110 | "collapsed": true 111 | }, 112 | "outputs": [], 113 | "source": [ 114 | "from random import randint\n", 115 | "@app.route(\"/random\")\n", 116 | "def hello_random():\n", 117 | " return str(randint(1,60))" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "* Um *hello world* personalizado:" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": null, 130 | "metadata": { 131 | "collapsed": true 132 | }, 133 | "outputs": [], 134 | "source": [ 135 | "@app.route('/hello/')\n", 136 | "def hello(name=None):\n", 137 | " return \"Hello {}\".format(name)" 138 | ] 139 | }, 140 | { 141 | "cell_type": "markdown", 142 | "metadata": {}, 143 | "source": [ 144 | "Note que o caminho acima foi personalizado para aceitar um parâmetro ```name```. \n", 145 | "\n", 146 | "Há outras formas de receber parâmetros de entrada com Flask, mas certamente este é o mais simples." 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "metadata": {}, 152 | "source": [ 153 | "### Criando serviços web mais complexos" 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "metadata": {}, 159 | "source": [ 160 | "Uma característica de serviços web é que eles costumam consumir de outros serviços.\n", 161 | "\n", 162 | "Em Python isto pode ser feito usando, por exemplo, o método ```get``` da biblioteca ```requests```.\n", 163 | "\n", 164 | "Veja um exemplo abaixo que recebe um CEP, consulta um serviço web e informa o endereço associado a este CEP:" 165 | ] 166 | }, 167 | { 168 | "cell_type": "code", 169 | "execution_count": null, 170 | "metadata": { 171 | "collapsed": false 172 | }, 173 | "outputs": [], 174 | "source": [ 175 | "import urllib\n", 176 | "from requests import get\n", 177 | "@app.route('/cep/')\n", 178 | "def buscarCep(cep=None):\n", 179 | " url = \"http://cep.republicavirtual.com.br/web_cep.php?cep=\"+ cep +\"&formato=query_string\"\n", 180 | " result = get(url).text\n", 181 | " fresult = urllib.parse.parse_qs(result)\n", 182 | " return \"
\".join((\n", 183 | " \" \".join((fresult['tipo_logradouro'][0], fresult['logradouro'][0], fresult['bairro'][0])),\n", 184 | " \"/\".join((fresult['cidade'][0], fresult['uf'][0])),\n", 185 | " ))" 186 | ] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": {}, 191 | "source": [ 192 | "### Colocando o serviço no ar (deploy)" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "Para fazer deploy do seu serviço, basta utilizar o método ```Flask.run()```.\n", 200 | "\n", 201 | "* **Obs**: Note que este método é bloqueante. Isto significa que ao executá-lo, seu notebook irá ficar preso na execução deste método. Para encerrá-lo após testar os serviços, clique no botão *Stop*." 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": null, 207 | "metadata": { 208 | "collapsed": false, 209 | "scrolled": true 210 | }, 211 | "outputs": [], 212 | "source": [ 213 | "app.run()" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": null, 219 | "metadata": { 220 | "collapsed": true 221 | }, 222 | "outputs": [], 223 | "source": [] 224 | } 225 | ], 226 | "metadata": { 227 | "kernelspec": { 228 | "display_name": "Python 3", 229 | "language": "python", 230 | "name": "python3" 231 | }, 232 | "language_info": { 233 | "codemirror_mode": { 234 | "name": "ipython", 235 | "version": 3 236 | }, 237 | "file_extension": ".py", 238 | "mimetype": "text/x-python", 239 | "name": "python", 240 | "nbconvert_exporter": "python", 241 | "pygments_lexer": "ipython3", 242 | "version": "3.5.2" 243 | } 244 | }, 245 | "nbformat": 4, 246 | "nbformat_minor": 1 247 | } 248 | -------------------------------------------------------------------------------- /oop/extra/monkey-patching.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Monkey patching" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "O escopo local de uma instância também envolve métodos. \n", 15 | "\n", 16 | "Em Python, é possível ir sobrescrever métodos através do *monkey patching*.\n", 17 | "\n", 18 | "Nos casos mais simples, o monkey patching é uma simples substituição de um método de instância por outro.\n", 19 | "\n", 20 | "**Não cobriremos aqui a criação de novos métodos ou o monkey patching de métodos mágicos, mas fique à vontade para pesquisá-los :)**" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "metadata": {}, 26 | "source": [ 27 | "### Fazendo patch em um método" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": {}, 33 | "source": [ 34 | "Vamos usar o exemplo abaixo para mostrar como monkey patching funciona:" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 1, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "class Person:\n", 44 | " def __init__(self, name):\n", 45 | " self.name = name\n", 46 | " \n", 47 | " def __str__(self):\n", 48 | " return self.name\n", 49 | " \n", 50 | " def hello(self):\n", 51 | " print(\"Hello\")" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 2, 57 | "metadata": {}, 58 | "outputs": [ 59 | { 60 | "name": "stdout", 61 | "output_type": "stream", 62 | "text": [ 63 | "Hello\n" 64 | ] 65 | } 66 | ], 67 | "source": [ 68 | "ze = Person(\"Zé\")\n", 69 | "ze.hello()" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": {}, 75 | "source": [ 76 | "Vamos criar um atributo com o sobrenome do Zé:" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 3, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "ze.surname = \"Ramalho\"" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 4, 91 | "metadata": { 92 | "scrolled": true 93 | }, 94 | "outputs": [ 95 | { 96 | "name": "stdout", 97 | "output_type": "stream", 98 | "text": [ 99 | "Hello\n" 100 | ] 101 | } 102 | ], 103 | "source": [ 104 | "ze.hello()" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": {}, 110 | "source": [ 111 | "Infelizmente, nosso objeto não consegue tirar proveito do novo atributo. \n", 112 | "\n", 113 | "Vamos tentar mudar o método `hello` pra que ele considere ambos os atributos:" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": 5, 119 | "metadata": {}, 120 | "outputs": [], 121 | "source": [ 122 | "def fullname(obj):\n", 123 | " return f\"Hi, I'm {obj.name} {obj.surname}\"" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": 6, 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "ze.hello = fullname" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": 7, 138 | "metadata": {}, 139 | "outputs": [ 140 | { 141 | "ename": "TypeError", 142 | "evalue": "fullname() missing 1 required positional argument: 'obj'", 143 | "output_type": "error", 144 | "traceback": [ 145 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 146 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 147 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mze\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhello\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 148 | "\u001b[0;31mTypeError\u001b[0m: fullname() missing 1 required positional argument: 'obj'" 149 | ] 150 | } 151 | ], 152 | "source": [ 153 | "ze.hello()" 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "metadata": {}, 159 | "source": [ 160 | "O problema em fazer monkey patch diretamente através de uma instância é que o interpretador não considera que deve passar a referência à instância como parâmetro.\n", 161 | "\n", 162 | "O que fazemos é aplicar o patch acessando o método pela classe:" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": 8, 168 | "metadata": {}, 169 | "outputs": [], 170 | "source": [ 171 | "Person.hello = fullname" 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": 9, 177 | "metadata": { 178 | "scrolled": true 179 | }, 180 | "outputs": [ 181 | { 182 | "ename": "TypeError", 183 | "evalue": "fullname() missing 1 required positional argument: 'obj'", 184 | "output_type": "error", 185 | "traceback": [ 186 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 187 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 188 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mze\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhello\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 189 | "\u001b[0;31mTypeError\u001b[0m: fullname() missing 1 required positional argument: 'obj'" 190 | ] 191 | } 192 | ], 193 | "source": [ 194 | "ze.hello()" 195 | ] 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "metadata": {}, 200 | "source": [ 201 | "Isto não resolve o problema do Zé, mas os novos objetos instanciados a partir de agora poderão usar a nova versão do método:" 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": 10, 207 | "metadata": {}, 208 | "outputs": [], 209 | "source": [ 210 | "zezo = Person(\"Zezo\")\n", 211 | "zezo.surname = \"Safadão\"" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 11, 217 | "metadata": {}, 218 | "outputs": [ 219 | { 220 | "data": { 221 | "text/plain": [ 222 | "\"Hi, I'm Zezo Safadão\"" 223 | ] 224 | }, 225 | "execution_count": 11, 226 | "metadata": {}, 227 | "output_type": "execute_result" 228 | } 229 | ], 230 | "source": [ 231 | "zezo.hello()" 232 | ] 233 | }, 234 | { 235 | "cell_type": "markdown", 236 | "metadata": {}, 237 | "source": [ 238 | "**O *monkey patching* é uma característica avançada de linguagens dinâmicas. Esse mini-tutorial serviu apenas para dizer que isso existe - com o tempo e pesquisa você aprenderá quando, como e se usá-lo ;)**" 239 | ] 240 | } 241 | ], 242 | "metadata": { 243 | "kernelspec": { 244 | "display_name": "Python 3", 245 | "language": "python", 246 | "name": "python3" 247 | }, 248 | "language_info": { 249 | "codemirror_mode": { 250 | "name": "ipython", 251 | "version": 3 252 | }, 253 | "file_extension": ".py", 254 | "mimetype": "text/x-python", 255 | "name": "python", 256 | "nbconvert_exporter": "python", 257 | "pygments_lexer": "ipython3", 258 | "version": "3.7.0" 259 | } 260 | }, 261 | "nbformat": 4, 262 | "nbformat_minor": 1 263 | } 264 | -------------------------------------------------------------------------------- /oop/extra/.ipynb_checkpoints/monkey-patching-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Monkey patching" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "O escopo local de uma instância também envolve métodos. \n", 15 | "\n", 16 | "Em Python, é possível ir sobrescrever métodos através do *monkey patching*.\n", 17 | "\n", 18 | "Nos casos mais simples, o monkey patching é uma simples substituição de um método de instância por outro.\n", 19 | "\n", 20 | "**Não cobriremos aqui a criação de novos métodos ou o monkey patching de métodos mágicos, mas fique à vontade para pesquisá-los :)**" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "metadata": {}, 26 | "source": [ 27 | "### Fazendo patch em um método" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": {}, 33 | "source": [ 34 | "Vamos usar o exemplo abaixo para mostrar como monkey patching funciona:" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 1, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "class Person:\n", 44 | " def __init__(self, name):\n", 45 | " self.name = name\n", 46 | " \n", 47 | " def __str__(self):\n", 48 | " return self.name\n", 49 | " \n", 50 | " def hello(self):\n", 51 | " print(\"Hello\")" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 2, 57 | "metadata": {}, 58 | "outputs": [ 59 | { 60 | "name": "stdout", 61 | "output_type": "stream", 62 | "text": [ 63 | "Hello\n" 64 | ] 65 | } 66 | ], 67 | "source": [ 68 | "ze = Person(\"Zé\")\n", 69 | "ze.hello()" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": {}, 75 | "source": [ 76 | "Vamos criar um atributo com o sobrenome do Zé:" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 3, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "ze.surname = \"Ramalho\"" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 4, 91 | "metadata": { 92 | "scrolled": true 93 | }, 94 | "outputs": [ 95 | { 96 | "name": "stdout", 97 | "output_type": "stream", 98 | "text": [ 99 | "Hello\n" 100 | ] 101 | } 102 | ], 103 | "source": [ 104 | "ze.hello()" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": {}, 110 | "source": [ 111 | "Infelizmente, nosso objeto não consegue tirar proveito do novo atributo. \n", 112 | "\n", 113 | "Vamos tentar mudar o método `hello` pra que ele considere ambos os atributos:" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": 5, 119 | "metadata": {}, 120 | "outputs": [], 121 | "source": [ 122 | "def fullname(obj):\n", 123 | " return f\"Hi, I'm {obj.name} {obj.surname}\"" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": 6, 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "ze.hello = fullname" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": 7, 138 | "metadata": {}, 139 | "outputs": [ 140 | { 141 | "ename": "TypeError", 142 | "evalue": "fullname() missing 1 required positional argument: 'obj'", 143 | "output_type": "error", 144 | "traceback": [ 145 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 146 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 147 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mze\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhello\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 148 | "\u001b[0;31mTypeError\u001b[0m: fullname() missing 1 required positional argument: 'obj'" 149 | ] 150 | } 151 | ], 152 | "source": [ 153 | "ze.hello()" 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "metadata": {}, 159 | "source": [ 160 | "O problema em fazer monkey patch diretamente através de uma instância é que o interpretador não considera que deve passar a referência à instância como parâmetro.\n", 161 | "\n", 162 | "O que fazemos é aplicar o patch acessando o método pela classe:" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": 8, 168 | "metadata": {}, 169 | "outputs": [], 170 | "source": [ 171 | "Person.hello = fullname" 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": 9, 177 | "metadata": { 178 | "scrolled": true 179 | }, 180 | "outputs": [ 181 | { 182 | "ename": "TypeError", 183 | "evalue": "fullname() missing 1 required positional argument: 'obj'", 184 | "output_type": "error", 185 | "traceback": [ 186 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 187 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 188 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mze\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhello\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 189 | "\u001b[0;31mTypeError\u001b[0m: fullname() missing 1 required positional argument: 'obj'" 190 | ] 191 | } 192 | ], 193 | "source": [ 194 | "ze.hello()" 195 | ] 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "metadata": {}, 200 | "source": [ 201 | "Isto não resolve o problema do Zé, mas os novos objetos instanciados a partir de agora poderão usar a nova versão do método:" 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": 10, 207 | "metadata": {}, 208 | "outputs": [], 209 | "source": [ 210 | "zezo = Person(\"Zezo\")\n", 211 | "zezo.surname = \"Safadão\"" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 11, 217 | "metadata": {}, 218 | "outputs": [ 219 | { 220 | "data": { 221 | "text/plain": [ 222 | "\"Hi, I'm Zezo Safadão\"" 223 | ] 224 | }, 225 | "execution_count": 11, 226 | "metadata": {}, 227 | "output_type": "execute_result" 228 | } 229 | ], 230 | "source": [ 231 | "zezo.hello()" 232 | ] 233 | }, 234 | { 235 | "cell_type": "markdown", 236 | "metadata": {}, 237 | "source": [ 238 | "**O *monkey patching* é uma característica avançada de linguagens dinâmicas. Esse mini-tutorial serviu apenas para dizer que isso existe - com o tempo e pesquisa você aprenderá quando, como e se usá-lo ;)**" 239 | ] 240 | } 241 | ], 242 | "metadata": { 243 | "kernelspec": { 244 | "display_name": "Python 3", 245 | "language": "python", 246 | "name": "python3" 247 | }, 248 | "language_info": { 249 | "codemirror_mode": { 250 | "name": "ipython", 251 | "version": 3 252 | }, 253 | "file_extension": ".py", 254 | "mimetype": "text/x-python", 255 | "name": "python", 256 | "nbconvert_exporter": "python", 257 | "pygments_lexer": "ipython3", 258 | "version": "3.7.0" 259 | } 260 | }, 261 | "nbformat": 4, 262 | "nbformat_minor": 1 263 | } 264 | -------------------------------------------------------------------------------- /alunos/closures01.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "trabalhoLP2.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [], 9 | "collapsed_sections": [] 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "metadata": { 19 | "id": "zMXymiL1d2-G", 20 | "colab_type": "text" 21 | }, 22 | "cell_type": "markdown", 23 | "source": [ 24 | "# Closure\n", 25 | "\n", 26 | "Quando temos **Nested Functions**, ou seja, funções dentro das outras, podemos analisar melhor que as funções mais abaixo tem acesso as variáveis do escopo fechado das funções acima.\n", 27 | "\n", 28 | "### Exemplo\n", 29 | "\n", 30 | "**Fonte ** : https://www.learnpython.org/en/Closures" 31 | ] 32 | }, 33 | { 34 | "metadata": { 35 | "id": "LLkhqawWfGZG", 36 | "colab_type": "code", 37 | "outputId": "93a01926-d118-45ff-e259-d2cdea6994d1", 38 | "colab": { 39 | "base_uri": "https://localhost:8080/", 40 | "height": 35 41 | } 42 | }, 43 | "cell_type": "code", 44 | "source": [ 45 | "def transmit_to_space(message):\n", 46 | " \"This is the enclosing function\"\n", 47 | " def data_transmitter():\n", 48 | " \"The nested function\"\n", 49 | " print(message)\n", 50 | "\n", 51 | " data_transmitter()\n", 52 | "\n", 53 | "transmit_to_space(\"Test message\")" 54 | ], 55 | "execution_count": 0, 56 | "outputs": [ 57 | { 58 | "output_type": "stream", 59 | "text": [ 60 | "Test message\n" 61 | ], 62 | "name": "stdout" 63 | } 64 | ] 65 | }, 66 | { 67 | "metadata": { 68 | "id": "oPIaqO-Ufe4N", 69 | "colab_type": "text" 70 | }, 71 | "cell_type": "markdown", 72 | "source": [ 73 | "No exemplo acima note que a variavel \"message\" é printada apenas no metodo *data_transmitter()* sendo acessada do método imediatamente acima. Veja que, a variável é acessada e manuseada pelos métodos de forma sequencial,ou seja, um usa a variavel com as alterações que o método anterior fez, porém quando as funções mais acima começam a serem executadas, elas usaram a variavel com as alterações feitas apenas até o ponto em que são chamadas, ignorando alterações feitas em métodos mais \"ao fundo\"." 74 | ] 75 | }, 76 | { 77 | "metadata": { 78 | "id": "0AjHW-Vin4l2", 79 | "colab_type": "code", 80 | "outputId": "2a96a205-bc02-4092-d3d4-6809bb25f353", 81 | "colab": { 82 | "base_uri": "https://localhost:8080/", 83 | "height": 52 84 | } 85 | }, 86 | "cell_type": "code", 87 | "source": [ 88 | "def print_msg(number):\n", 89 | " def printer():\n", 90 | " number=3\n", 91 | " print(number)\n", 92 | " printer()\n", 93 | " print(number)\n", 94 | "\n", 95 | "print_msg(9)" 96 | ], 97 | "execution_count": 0, 98 | "outputs": [ 99 | { 100 | "output_type": "stream", 101 | "text": [ 102 | "3\n", 103 | "9\n" 104 | ], 105 | "name": "stdout" 106 | } 107 | ] 108 | }, 109 | { 110 | "metadata": { 111 | "id": "hZL0O1WZn20s", 112 | "colab_type": "text" 113 | }, 114 | "cell_type": "markdown", 115 | "source": [ 116 | "Note que no escopo mais acima *number* tem valor 9, porém dentro de *printer()* é dado a ela valor 3, agora note que no segudo *print(number)* pertencente a *print_msg(number)* é mostrado o valor 9, ou seja, a alteração feita no escopo mais ao fundo foi descartada quando subimos o escopo da função. Agora ao se usar **nonlocal** na variavel o método tem outro comportamento. Veja a seguir :" 117 | ] 118 | }, 119 | { 120 | "metadata": { 121 | "id": "ic1GAl6XiJBb", 122 | "colab_type": "text" 123 | }, 124 | "cell_type": "markdown", 125 | "source": [ 126 | "### Exemplo\n", 127 | "\n", 128 | "**Fonte**: https://www.learnpython.org/en/Closures " 129 | ] 130 | }, 131 | { 132 | "metadata": { 133 | "id": "moeje4Wwi3bO", 134 | "colab_type": "code", 135 | "outputId": "c99a4f32-a397-4d87-9906-c6b6658725ac", 136 | "colab": { 137 | "base_uri": "https://localhost:8080/", 138 | "height": 52 139 | } 140 | }, 141 | "cell_type": "code", 142 | "source": [ 143 | "def print_msg(number):\n", 144 | " def printer():\n", 145 | " \"Here we are using the nonlocal keyword\"\n", 146 | " nonlocal number\n", 147 | " number=3\n", 148 | " print(number)\n", 149 | " printer()\n", 150 | " print(number)\n", 151 | "\n", 152 | "print_msg(9)" 153 | ], 154 | "execution_count": 0, 155 | "outputs": [ 156 | { 157 | "output_type": "stream", 158 | "text": [ 159 | "3\n", 160 | "3\n" 161 | ], 162 | "name": "stdout" 163 | } 164 | ] 165 | }, 166 | { 167 | "metadata": { 168 | "id": "GswX_IfQk6q8", 169 | "colab_type": "text" 170 | }, 171 | "cell_type": "markdown", 172 | "source": [ 173 | "Agora usando **nonlocal** note que as mudanças feitas nos escopos das funções mais abaixo, altera a variavel nos escopos mais acima, permitindo uma maior flexibilidade no uso da variável." 174 | ] 175 | }, 176 | { 177 | "metadata": { 178 | "id": "6tqbUyR2faWL", 179 | "colab_type": "text" 180 | }, 181 | "cell_type": "markdown", 182 | "source": [ 183 | "# Variáveis Livres" 184 | ] 185 | }, 186 | { 187 | "metadata": { 188 | "id": "LGw9Vz2JecLC", 189 | "colab_type": "text" 190 | }, 191 | "cell_type": "markdown", 192 | "source": [ 193 | "Váriaveis livres são variaveis que não estam definidas no escopo global nem dentro de uma closure, ou seja, se uma variável é usada em um escopo, mas não é definida lá, ela é uma variável livre .\n" 194 | ] 195 | }, 196 | { 197 | "metadata": { 198 | "id": "CQ3WHkr-ef61", 199 | "colab_type": "code", 200 | "outputId": "94ab2ce9-3582-4db8-d264-fc5710e958b6", 201 | "colab": { 202 | "base_uri": "https://localhost:8080/", 203 | "height": 34 204 | } 205 | }, 206 | "cell_type": "code", 207 | "source": [ 208 | "def funcao():\n", 209 | " variavel = 3 \n", 210 | " def closure():\n", 211 | " return variavel\n", 212 | " return closure\n", 213 | " \n", 214 | "x = funcao()\n", 215 | "del funcao\n", 216 | "print(x())\n", 217 | " " 218 | ], 219 | "execution_count": 0, 220 | "outputs": [ 221 | { 222 | "output_type": "stream", 223 | "text": [ 224 | "3\n" 225 | ], 226 | "name": "stdout" 227 | } 228 | ] 229 | }, 230 | { 231 | "metadata": { 232 | "id": "CL_zW8NtaQFT", 233 | "colab_type": "code", 234 | "colab": {} 235 | }, 236 | "cell_type": "code", 237 | "source": [ 238 | "" 239 | ], 240 | "execution_count": 0, 241 | "outputs": [] 242 | } 243 | ] 244 | } -------------------------------------------------------------------------------- /alunos/lambda01.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "Lambda.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [], 9 | "collapsed_sections": [] 10 | } 11 | }, 12 | "cells": [ 13 | { 14 | "metadata": { 15 | "id": "52EZPQFizWWI", 16 | "colab_type": "text" 17 | }, 18 | "cell_type": "markdown", 19 | "source": [ 20 | "**Componentes**: André Ricardo, Erildo Júnior, Gabriel Estevam.\n", 21 | "\n" 22 | ] 23 | }, 24 | { 25 | "metadata": { 26 | "id": "3CJyWex3zlQq", 27 | "colab_type": "text" 28 | }, 29 | "cell_type": "markdown", 30 | "source": [ 31 | "# **Lambda**\n", 32 | "\n", 33 | "\n", 34 | "Lambda são funções anônimas que aceitam argumentos, os quais são opcionais, e que suportam apenas uma expressão. \n", 35 | "\n", 36 | "Ao executar lambda, Python retorna uma função ao invés de atribuí-la à um nome como acontece com o *def*, sendo por esse motivo declaradas como anônimas.\n", 37 | "\n", 38 | "\n" 39 | ] 40 | }, 41 | { 42 | "metadata": { 43 | "id": "cCdt6cLP0ONE", 44 | "colab_type": "text" 45 | }, 46 | "cell_type": "markdown", 47 | "source": [ 48 | "As funções lambda são declaradas da seguinte maneira:\n", 49 | "\n", 50 | "\n", 51 | ">***função = lambda argumentos : expressão utilizando os argumentos***\n", 52 | "\n", 53 | "\n", 54 | "Para melhor entendimento, observe o exemplo abaixo:" 55 | ] 56 | }, 57 | { 58 | "metadata": { 59 | "id": "Y5q7LvFDo0SK", 60 | "colab_type": "code", 61 | "colab": { 62 | "base_uri": "https://localhost:8080/", 63 | "height": 88 64 | }, 65 | "outputId": "472945b6-1f25-45ba-b056-3aab5f9502e8" 66 | }, 67 | "cell_type": "code", 68 | "source": [ 69 | "x = lambda a : a + a\n", 70 | "\n", 71 | "print (x(2)) \n", 72 | "print (x(3))\n", 73 | "print (x(4))\n", 74 | "print (x(100))" 75 | ], 76 | "execution_count": 2, 77 | "outputs": [ 78 | { 79 | "output_type": "stream", 80 | "text": [ 81 | "4\n", 82 | "6\n", 83 | "8\n", 84 | "200\n" 85 | ], 86 | "name": "stdout" 87 | } 88 | ] 89 | }, 90 | { 91 | "metadata": { 92 | "id": "nVL8i7zO1t4V", 93 | "colab_type": "code", 94 | "colab": { 95 | "base_uri": "https://localhost:8080/", 96 | "height": 88 97 | }, 98 | "outputId": "ecb97798-f53a-4747-fbe8-38f92e2cd235" 99 | }, 100 | "cell_type": "code", 101 | "source": [ 102 | "x = lambda a, b : a * b\n", 103 | "\n", 104 | "print (x(2, 3)) \n", 105 | "print (x(3, 4))\n", 106 | "print (x(4, 5))\n", 107 | "print (x(100, 1000))" 108 | ], 109 | "execution_count": 4, 110 | "outputs": [ 111 | { 112 | "output_type": "stream", 113 | "text": [ 114 | "6\n", 115 | "12\n", 116 | "20\n", 117 | "100000\n" 118 | ], 119 | "name": "stdout" 120 | } 121 | ] 122 | }, 123 | { 124 | "metadata": { 125 | "id": "jsfgNEkG1gMW", 126 | "colab_type": "text" 127 | }, 128 | "cell_type": "markdown", 129 | "source": [ 130 | "Funções lambda são utilizadas na declaração de funções que não são complexas o suficiente para o uso da *def*, sendo, normalmente, pensadas como funções de uma linha só. \n", 131 | "\n", 132 | "Para isto, observe o exemplo abaixo, onde é mostrado o tamanho de cada palavra em uma lista de string." 133 | ] 134 | }, 135 | { 136 | "metadata": { 137 | "id": "6NsU1tq635zV", 138 | "colab_type": "code", 139 | "colab": { 140 | "base_uri": "https://localhost:8080/", 141 | "height": 35 142 | }, 143 | "outputId": "ec34b295-b7e1-4e7d-f3d3-612143e20487" 144 | }, 145 | "cell_type": "code", 146 | "source": [ 147 | "#utilizando def\n", 148 | "\n", 149 | "def tamanho(palavras):\n", 150 | " return [len(i) for i in palavras]\n", 151 | " \n", 152 | "paises = ['Espanha', 'Libano', 'Eua','', 'Nigeria', 'Argentina', 'Omã']\n", 153 | " \n", 154 | "print tamanho(paises)" 155 | ], 156 | "execution_count": 6, 157 | "outputs": [ 158 | { 159 | "output_type": "stream", 160 | "text": [ 161 | "[7, 6, 3, 0, 7, 9, 4]\n" 162 | ], 163 | "name": "stdout" 164 | } 165 | ] 166 | }, 167 | { 168 | "metadata": { 169 | "id": "ZsSbTr-p1CQK", 170 | "colab_type": "code", 171 | "colab": { 172 | "base_uri": "https://localhost:8080/", 173 | "height": 35 174 | }, 175 | "outputId": "38484ac1-39d9-4d4d-d76a-fe9d70c35c15" 176 | }, 177 | "cell_type": "code", 178 | "source": [ 179 | "#utilizando lambda\n", 180 | "\n", 181 | "size = lambda palavras: [len(i) for i in palavras]\n", 182 | "\n", 183 | "print size(paises)" 184 | ], 185 | "execution_count": 8, 186 | "outputs": [ 187 | { 188 | "output_type": "stream", 189 | "text": [ 190 | "[7, 6, 3, 0, 7, 9, 4]\n" 191 | ], 192 | "name": "stdout" 193 | } 194 | ] 195 | }, 196 | { 197 | "metadata": { 198 | "id": "7dJgNYyi7nZh", 199 | "colab_type": "text" 200 | }, 201 | "cell_type": "markdown", 202 | "source": [ 203 | "Agora, serão mostrados outros exemplos onde lambda pode ser utilizado." 204 | ] 205 | }, 206 | { 207 | "metadata": { 208 | "id": "xdkYfQQ97l1a", 209 | "colab_type": "code", 210 | "colab": { 211 | "base_uri": "https://localhost:8080/", 212 | "height": 34 213 | }, 214 | "outputId": "673593f1-1e0f-47c3-fd8d-85816ae6efd9" 215 | }, 216 | "cell_type": "code", 217 | "source": [ 218 | "#ordenação de uma lista de tuplas baseada no seu segundo elemento\n", 219 | "from operator import itemgetter\n", 220 | "lista = [(0, 1), (5, 8), (10, 10), (19, -10)]\n", 221 | "#lista.sort(key=lambda x: x[1])\n", 222 | "lista.sort(key=itemgetter(1))\n", 223 | "print (lista)" 224 | ], 225 | "execution_count": 2, 226 | "outputs": [ 227 | { 228 | "output_type": "stream", 229 | "text": [ 230 | "[(19, -10), (0, 1), (5, 8), (10, 10)]\n" 231 | ], 232 | "name": "stdout" 233 | } 234 | ] 235 | }, 236 | { 237 | "metadata": { 238 | "id": "_j1TJTFF-rbH", 239 | "colab_type": "code", 240 | "colab": { 241 | "base_uri": "https://localhost:8080/", 242 | "height": 35 243 | }, 244 | "outputId": "778afb41-fa06-4b3c-f989-14ba1ed909d4" 245 | }, 246 | "cell_type": "code", 247 | "source": [ 248 | "#se replace for \"True\", ele subtitui os espaços por '_', senão imprime do jeito que é.\n", 249 | "\n", 250 | "replace = True\n", 251 | "func = replace and (lambda s: s.replace(' ', '_')) or (lambda s: s)\n", 252 | " \n", 253 | "phrase = 'Look at the sky, blue mama'\n", 254 | " \n", 255 | "print func(phrase)" 256 | ], 257 | "execution_count": 14, 258 | "outputs": [ 259 | { 260 | "output_type": "stream", 261 | "text": [ 262 | "Look_at_the_sky,_blue_mama\n" 263 | ], 264 | "name": "stdout" 265 | } 266 | ] 267 | }, 268 | { 269 | "metadata": { 270 | "id": "Ge5S6Mw49_4d", 271 | "colab_type": "code", 272 | "colab": { 273 | "base_uri": "https://localhost:8080/", 274 | "height": 68 275 | }, 276 | "outputId": "0e61c820-72b6-498a-bad5-5bf6514af1b3" 277 | }, 278 | "cell_type": "code", 279 | "source": [ 280 | "#função que retorna uma função de multiṕlicação\n", 281 | "\n", 282 | "def minha_funcao(n):\n", 283 | " return lambda a : a * n\n", 284 | "\n", 285 | "duplicador = minha_funcao(2)\n", 286 | "triplicador = minha_funcao(3)\n", 287 | "\n", 288 | "print(duplicador(10))\n", 289 | "print(triplicador(10))\n", 290 | "\n", 291 | "n = 4\n", 292 | "print(duplicador(10))" 293 | ], 294 | "execution_count": 1, 295 | "outputs": [ 296 | { 297 | "output_type": "stream", 298 | "text": [ 299 | "20\n", 300 | "30\n", 301 | "20\n" 302 | ], 303 | "name": "stdout" 304 | } 305 | ] 306 | }, 307 | { 308 | "metadata": { 309 | "id": "Ud7AKR-u-cme", 310 | "colab_type": "code", 311 | "colab": { 312 | "base_uri": "https://localhost:8080/", 313 | "height": 71 314 | }, 315 | "outputId": "56dc6a2e-c3fe-4e9a-dca3-582c3c4b15d6" 316 | }, 317 | "cell_type": "code", 318 | "source": [ 319 | "#Dicionário que retorna a função pedida\n", 320 | "\n", 321 | "acao = {\n", 322 | " 'soma': lambda x, y: x + y,\n", 323 | " 'subt': lambda x, y: x - y,\n", 324 | " 'mult': lambda x, y: x * y,\n", 325 | "}\n", 326 | " \n", 327 | "func = acao['soma']\n", 328 | "func2 = acao['subt']\n", 329 | "func3 = acao['mult']\n", 330 | " \n", 331 | "print func(100, 100)\n", 332 | "print func2(20, 10)\n", 333 | "print func3(10, 10)" 334 | ], 335 | "execution_count": 13, 336 | "outputs": [ 337 | { 338 | "output_type": "stream", 339 | "text": [ 340 | "200\n", 341 | "10\n", 342 | "100\n" 343 | ], 344 | "name": "stdout" 345 | } 346 | ] 347 | } 348 | ] 349 | } -------------------------------------------------------------------------------- /alunos/functors02.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "It4mZPwgzuJ8" 8 | }, 9 | "source": [ 10 | "# FUNCTORS\n", 11 | "\n", 12 | "#### Autores: Chianc Leocadio, Daniel Leiros, Vitor Henrique\n", 13 | "\n", 14 | "Um functor é um objeto que pode ser chamado, portanto, em termos de Python, esse é um método especial. Ele é utilizado para abstrair/esconder a implementação do código de maneira que , por exemplo, seja possível tratar implicitamente o uso de um procedimento para diferentes tipos de entrada.\n", 15 | "\n", 16 | "O uso de functors possibilita uma mudança na estratégia interna de implementação de um código sem que pertube com o código do lado do usuário. \n" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": { 22 | "colab_type": "text", 23 | "id": "OBJRozlb7VrE" 24 | }, 25 | "source": [ 26 | "### Exemplo 1\n", 27 | " O exemplo a seguir evidencia uma simples operação baseada na noção de functors, onde o objeto é chamado e realiza operações de soma em sequência. " 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 0, 33 | "metadata": { 34 | "colab": {}, 35 | "colab_type": "code", 36 | "collapsed": true, 37 | "id": "eJ2hbhAE7hEl" 38 | }, 39 | "outputs": [], 40 | "source": [ 41 | "class Acumulador(object):\n", 42 | " def __init__(self, num=0):\n", 43 | " self.num = num\n", 44 | " def __call__(self, x):\n", 45 | " self.num += x\n", 46 | " return self.num\n", 47 | " " 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 11, 53 | "metadata": { 54 | "colab": { 55 | "base_uri": "https://localhost:8080/", 56 | "height": 88 57 | }, 58 | "colab_type": "code", 59 | "collapsed": false, 60 | "id": "nm77rG46dncB", 61 | "outputId": "a61f002a-4d5c-450d-9797-34a8873ac320" 62 | }, 63 | "outputs": [ 64 | { 65 | "name": "stdout", 66 | "output_type": "stream", 67 | "text": [ 68 | "9\n", 69 | "11\n", 70 | "20\n", 71 | "60\n" 72 | ] 73 | } 74 | ], 75 | "source": [ 76 | "# Cria uma instância e inicializa com num = 4\n", 77 | "acc = Acumulador(4)\n", 78 | "# recupera 4 e soma 5\n", 79 | "print(acc(5)) # 9\n", 80 | "# recupera 9 e soma 2\n", 81 | "print(acc(2)) # 11\n", 82 | "# recupera 11 e soma 9\n", 83 | "print(acc(9)) # 20\n", 84 | "# aumentando a complexidade...\n", 85 | "print(acc(acc(10))) # 60" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": { 91 | "colab_type": "text", 92 | "id": "eWctYp-r4qmi" 93 | }, 94 | "source": [ 95 | "### Exemplo 2\n", 96 | "\n", 97 | "Neste próximo exemplo criamos uma instância do functor \"strip\" inicializando-o com o valor \",;:.!?\". Sempre que a instância é chamada, ela retorna a string com os caracteres de pontuação removidos. " 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 0, 103 | "metadata": { 104 | "colab": {}, 105 | "colab_type": "code", 106 | "collapsed": true, 107 | "id": "4DZ5Hfue5SHg" 108 | }, 109 | "outputs": [], 110 | "source": [ 111 | "class strip(object):\n", 112 | " def __init__(self,characters):\n", 113 | " self.characters = characters\n", 114 | " def __call__(self, string):\n", 115 | " return string.strip(self.characters)" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 3, 121 | "metadata": { 122 | "colab": { 123 | "base_uri": "https://localhost:8080/", 124 | "height": 35 125 | }, 126 | "colab_type": "code", 127 | "collapsed": false, 128 | "id": "JMDpULXj56ZF", 129 | "outputId": "442a6989-fe6a-4b10-9298-b3a16b54654d" 130 | }, 131 | "outputs": [ 132 | { 133 | "data": { 134 | "text/plain": [ 135 | "'Hello World'" 136 | ] 137 | }, 138 | "execution_count": 3, 139 | "metadata": { 140 | "tags": [] 141 | }, 142 | "output_type": "execute_result" 143 | } 144 | ], 145 | "source": [ 146 | "strip_ponctuation = strip(\",;:.!?\")\n", 147 | "strip_ponctuation(\"Hello World!\")" 148 | ] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": { 153 | "colab_type": "text", 154 | "id": "kh69yLks4LT_" 155 | }, 156 | "source": [ 157 | "### Exemplos 3\n", 158 | "\n", 159 | "O exemplo a seguir mostra como é possível criar uma classe Functor que utilize tipos de ordenação diferentes para listas dos tipos `int` e `float` quando for chamada pela classe Caller." 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": 0, 165 | "metadata": { 166 | "colab": {}, 167 | "colab_type": "code", 168 | "collapsed": true, 169 | "id": "P0KHcu0fztpc" 170 | }, 171 | "outputs": [], 172 | "source": [ 173 | "class Functor(object):\n", 174 | " def __init__(self, n = 10):\n", 175 | " self.n = n\n", 176 | " \n", 177 | " def __call__(self,x):\n", 178 | " x_first = x[0]\n", 179 | " if type(x_first) is int:\n", 180 | " self.__mergeSort(x,0,len(x)-1)\n", 181 | " return x\n", 182 | " elif type(x_first) is float:\n", 183 | " self.__heapSort(x)\n", 184 | " return x\n", 185 | " \n", 186 | " def __merge(self,arr, l, m, r): \n", 187 | " n1 = m - l + 1\n", 188 | " n2 = r- m \n", 189 | " \n", 190 | " L = [0]*(n1) \n", 191 | " R = [0]*(n2) \n", 192 | " \n", 193 | " for i in range(0 , n1): \n", 194 | " L[i] = arr[l + i] \n", 195 | "\n", 196 | " for j in range(0 , n2): \n", 197 | " R[j] = arr[m + 1 + j]\n", 198 | " \n", 199 | " i = 0 \n", 200 | " j = 0 \n", 201 | " k = l\n", 202 | " \n", 203 | " while i < n1 and j < n2 : \n", 204 | " if L[i] <= R[j]: \n", 205 | " arr[k] = L[i] \n", 206 | " i += 1\n", 207 | " else: \n", 208 | " arr[k] = R[j] \n", 209 | " j += 1\n", 210 | " k += 1\n", 211 | "\n", 212 | " while i < n1: \n", 213 | " arr[k] = L[i] \n", 214 | " i += 1\n", 215 | " k += 1\n", 216 | "\n", 217 | " while j < n2: \n", 218 | " arr[k] = R[j] \n", 219 | " j += 1\n", 220 | " k += 1 \n", 221 | " \n", 222 | " def __mergeSort(self,arr,l,r):\n", 223 | " if l < r: \n", 224 | " m = int((l+(r-1))/2)\n", 225 | " \n", 226 | " self.__mergeSort(arr, l, m) \n", 227 | " self.__mergeSort(arr, m+1, r) \n", 228 | " self.__merge(arr, l, m, r) \n", 229 | " \n", 230 | " def __heap(self,arr,n,i):\n", 231 | " largest = i \n", 232 | " l = 2 * i + 1 \n", 233 | " r = 2 * i + 2 \n", 234 | " \n", 235 | " if l < n and arr[i] < arr[l]: \n", 236 | " largest = l \n", 237 | " \n", 238 | " if r < n and arr[largest] < arr[r]: \n", 239 | " largest = r \n", 240 | "\n", 241 | " if largest != i: \n", 242 | " arr[i],arr[largest] = arr[largest],arr[i] \n", 243 | " self.__heap(arr, n, largest)\n", 244 | " \n", 245 | " def __heapSort(self,arr):\n", 246 | " n = len(arr)\n", 247 | " for i in range(n,-1,-1):\n", 248 | " self.__heap(arr,n,i)\n", 249 | " \n", 250 | " for i in range(n-1, 0, -1): \n", 251 | " arr[i], arr[0] = arr[0], arr[i] \n", 252 | " self.__heap(arr, i, 0)\n", 253 | " \n", 254 | "\n", 255 | " \n", 256 | " " 257 | ] 258 | }, 259 | { 260 | "cell_type": "code", 261 | "execution_count": 0, 262 | "metadata": { 263 | "colab": {}, 264 | "colab_type": "code", 265 | "collapsed": true, 266 | "id": "O_xpwbz9_gvG" 267 | }, 268 | "outputs": [], 269 | "source": [ 270 | "class Caller(object):\n", 271 | " def __init__(self):\n", 272 | " self.sort = Functor()\n", 273 | " def doS(self,x):\n", 274 | " return self.sort(x)\n", 275 | " " 276 | ] 277 | }, 278 | { 279 | "cell_type": "code", 280 | "execution_count": 0, 281 | "metadata": { 282 | "colab": {}, 283 | "colab_type": "code", 284 | "collapsed": true, 285 | "id": "a5aNTM5e_iBb" 286 | }, 287 | "outputs": [], 288 | "source": [ 289 | "Call = Caller()" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": 7, 295 | "metadata": { 296 | "colab": { 297 | "base_uri": "https://localhost:8080/", 298 | "height": 35 299 | }, 300 | "colab_type": "code", 301 | "collapsed": false, 302 | "id": "6hWil2WG_vh9", 303 | "outputId": "c61b5b0f-5c54-41cc-c45c-92fc53c74c81" 304 | }, 305 | "outputs": [ 306 | { 307 | "data": { 308 | "text/plain": [ 309 | "[-99, -1, 0, 1, 2, 3]" 310 | ] 311 | }, 312 | "execution_count": 7, 313 | "metadata": { 314 | "tags": [] 315 | }, 316 | "output_type": "execute_result" 317 | } 318 | ], 319 | "source": [ 320 | "Call.doS([1,3,2,0,-1,-99])" 321 | ] 322 | }, 323 | { 324 | "cell_type": "code", 325 | "execution_count": 8, 326 | "metadata": { 327 | "colab": { 328 | "base_uri": "https://localhost:8080/", 329 | "height": 35 330 | }, 331 | "colab_type": "code", 332 | "collapsed": false, 333 | "id": "xrHpGKYAAA_g", 334 | "outputId": "a372470f-625c-4ce4-a126-3f9d895cb7be" 335 | }, 336 | "outputs": [ 337 | { 338 | "data": { 339 | "text/plain": [ 340 | "[1.7, 1.93343, 3.4, 90.3]" 341 | ] 342 | }, 343 | "execution_count": 8, 344 | "metadata": { 345 | "tags": [] 346 | }, 347 | "output_type": "execute_result" 348 | } 349 | ], 350 | "source": [ 351 | "Call.doS([1.93343,1.7,90.3,3.4])" 352 | ] 353 | }, 354 | { 355 | "cell_type": "markdown", 356 | "metadata": { 357 | "colab_type": "text", 358 | "id": "zwPO9GXX6vE6" 359 | }, 360 | "source": [ 361 | "## Discussões\n", 362 | "\n", 363 | "* Poderíamos conseguir trabalhar com a mesma ideia de abstração através de uma função simples ou lambda, mas isso iria impedir o armazenamento de um estado ou executar um processamento mais complexo.\n", 364 | "\n", 365 | "* A habilidade de um functor de capturar estados usando uma classe é muito versátil e poderosa, mas às vezes é mais do que realmente precisamos." 366 | ] 367 | }, 368 | { 369 | "cell_type": "markdown", 370 | "metadata": { 371 | "colab_type": "text", 372 | "id": "_6CeUyPdzqSM" 373 | }, 374 | "source": [ 375 | "## Referências\n", 376 | "\n", 377 | "Esse notebook foi construído mediante consulta a estas referências:\n", 378 | "\n", 379 | "* https://www.geeksforgeeks.org/functors-use-python/.\n", 380 | "* SUMMERFIELD, MARK. Advanced Python 3 Programming Techniques.\n", 381 | "\n", 382 | "\n" 383 | ] 384 | } 385 | ], 386 | "metadata": { 387 | "colab": { 388 | "collapsed_sections": [], 389 | "name": "Functors-final.ipynb", 390 | "provenance": [], 391 | "version": "0.3.2" 392 | }, 393 | "kernelspec": { 394 | "display_name": "Python 3", 395 | "language": "python", 396 | "name": "python3" 397 | }, 398 | "language_info": { 399 | "codemirror_mode": { 400 | "name": "ipython", 401 | "version": 3 402 | }, 403 | "file_extension": ".py", 404 | "mimetype": "text/x-python", 405 | "name": "python", 406 | "nbconvert_exporter": "python", 407 | "pygments_lexer": "ipython3", 408 | "version": "3.5.2" 409 | } 410 | }, 411 | "nbformat": 4, 412 | "nbformat_minor": 0 413 | } 414 | -------------------------------------------------------------------------------- /web-persistence/persistence-serialization.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Decoradores e persistência" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Este notebook é parte da série \"Decoradores e persistência\", adaptada de um minicurso ofertado por [Lucas Castro](https://br.linkedin.com/in/lucasmcastro), da [Evolux](https://evolux.net.br)." 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Persistência" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "A execução de programas e scripts geralmente acontece na memória RAM, uma forma de armazenamento volátil que se perde execuções ou cada vez que o computador é reiniciado.\n", 29 | "\n", 30 | "Para que um dado **persista**, é necessário armazená-lo em disco. No entanto, gerenciar arquivos diretamente não é a única solução possível (nem a mais prática). Para isto, geralmente usamos **bancos de dados**.\n", 31 | "\n", 32 | "Existem diferentes tipos de bancos de dados - neste notebook vamos ver apenas um modelo bastante simples, denominado **chave-valor**. Em poucas palavras, um banco chave-valor armazena um valor associado uma chave -- toda indexação para busca, inserção e remoção é feita sobre as chaves.\n", 33 | "\n", 34 | "Como linguagens de programação geralmente trabalham com valores complexos, é necessário usar padrões de **serialização** para converter um objeto complexo em um valor único e depois reconstruí-lo." 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "## Serialização" 42 | ] 43 | }, 44 | { 45 | "cell_type": "markdown", 46 | "metadata": {}, 47 | "source": [ 48 | "Python oferece suporte nativo a diferentes padrões de serialização, cada um com suas vantagens e desvantagens." 49 | ] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "metadata": {}, 54 | "source": [ 55 | "### JSON" 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "metadata": {}, 61 | "source": [ 62 | "Um dos padrões mais usados atualmente na web é o **JSON** (*JavaScript Object Notation*), que pode ser usado com os procedimentos da biblioteca ```json```." 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": {}, 68 | "source": [ 69 | "* ```dumps``` converte um objeto para o formato JSON e o armazena como uma string.\n", 70 | "* ```loads``` lê uma string contendo um objeto no formato JSON e retorna um objeto. " 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": 1, 76 | "metadata": { 77 | "collapsed": true 78 | }, 79 | "outputs": [], 80 | "source": [ 81 | "from json import dumps, loads" 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": 2, 87 | "metadata": { 88 | "collapsed": false 89 | }, 90 | "outputs": [], 91 | "source": [ 92 | "test_dict = {\"Logradouro\": \"Campus universitário\", \"Número\": \"S/N\", \"Bairro\": \"Lagoa Nova\"}" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 3, 98 | "metadata": { 99 | "collapsed": false 100 | }, 101 | "outputs": [ 102 | { 103 | "name": "stdout", 104 | "output_type": "stream", 105 | "text": [ 106 | "{\"Bairro\": \"Lagoa Nova\", \"Logradouro\": \"Campus universit\\u00e1rio\", \"N\\u00famero\": \"S/N\"}\n" 107 | ] 108 | } 109 | ], 110 | "source": [ 111 | "string = dumps(test_dict)\n", 112 | "print(string)" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 4, 118 | "metadata": { 119 | "collapsed": false 120 | }, 121 | "outputs": [ 122 | { 123 | "data": { 124 | "text/plain": [ 125 | "True" 126 | ] 127 | }, 128 | "execution_count": 4, 129 | "metadata": {}, 130 | "output_type": "execute_result" 131 | } 132 | ], 133 | "source": [ 134 | "json_dict = loads(string)\n", 135 | "test_dict == json_dict" 136 | ] 137 | }, 138 | { 139 | "cell_type": "markdown", 140 | "metadata": {}, 141 | "source": [ 142 | "* ```load``` e ```dump``` funcionam de forma análoga aos procedimentos anteriores, mas servem para persistência em arquivos." 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": 5, 148 | "metadata": { 149 | "collapsed": true 150 | }, 151 | "outputs": [], 152 | "source": [ 153 | "from json import dump, load" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 6, 159 | "metadata": { 160 | "collapsed": false 161 | }, 162 | "outputs": [], 163 | "source": [ 164 | "with open(\"dump.json\", \"w\", encoding=\"utf-8\") as f:\n", 165 | " dump(test_dict, f)" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": 7, 171 | "metadata": { 172 | "collapsed": false 173 | }, 174 | "outputs": [], 175 | "source": [ 176 | "with open(\"dump.json\", encoding=\"utf-8\") as f:\n", 177 | " read_dict = load(f)" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 8, 183 | "metadata": { 184 | "collapsed": false, 185 | "scrolled": true 186 | }, 187 | "outputs": [ 188 | { 189 | "data": { 190 | "text/plain": [ 191 | "True" 192 | ] 193 | }, 194 | "execution_count": 8, 195 | "metadata": {}, 196 | "output_type": "execute_result" 197 | } 198 | ], 199 | "source": [ 200 | "test_dict == read_dict" 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": 10, 206 | "metadata": { 207 | "collapsed": false 208 | }, 209 | "outputs": [ 210 | { 211 | "data": { 212 | "text/plain": [ 213 | "[0, 1, 2, 3, 4]" 214 | ] 215 | }, 216 | "execution_count": 10, 217 | "metadata": {}, 218 | "output_type": "execute_result" 219 | } 220 | ], 221 | "source": [ 222 | "loads(dumps([0,1,2,3,4]))" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": 12, 228 | "metadata": { 229 | "collapsed": false 230 | }, 231 | "outputs": [ 232 | { 233 | "data": { 234 | "text/plain": [ 235 | "'Uma string [ contendo ] isso'" 236 | ] 237 | }, 238 | "execution_count": 12, 239 | "metadata": {}, 240 | "output_type": "execute_result" 241 | } 242 | ], 243 | "source": [ 244 | "loads(dumps(\"Uma string [ contendo ] isso\"))" 245 | ] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "metadata": {}, 250 | "source": [ 251 | "### Pickle\n", 252 | "\n", 253 | "Uma outra biblioteca padrão do Python para serialização de objetos é a ```pickle```, que serializa objetos para bytes e vice-versa.\n", 254 | "\n", 255 | "Os procedimentos desta biblioteca seguem a mesma interface dos procedimentos da biblioteca ```json```." 256 | ] 257 | }, 258 | { 259 | "cell_type": "markdown", 260 | "metadata": {}, 261 | "source": [ 262 | "* ```dumps``` converte um objeto para um formato compreendido pelo interpretador Python e o armazena como bytes.\n", 263 | "* ```loads``` lê uma string contendo um objeto em um formato compreendido pelo interpretador Python e retorna um objeto. " 264 | ] 265 | }, 266 | { 267 | "cell_type": "code", 268 | "execution_count": 13, 269 | "metadata": { 270 | "collapsed": true 271 | }, 272 | "outputs": [], 273 | "source": [ 274 | "from pickle import loads, dumps" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": 14, 280 | "metadata": { 281 | "collapsed": false, 282 | "scrolled": true 283 | }, 284 | "outputs": [ 285 | { 286 | "name": "stdout", 287 | "output_type": "stream", 288 | "text": [ 289 | "b'\\x80\\x03}q\\x00(X\\x06\\x00\\x00\\x00Bairroq\\x01X\\n\\x00\\x00\\x00Lagoa Novaq\\x02X\\n\\x00\\x00\\x00Logradouroq\\x03X\\x15\\x00\\x00\\x00Campus universit\\xc3\\xa1rioq\\x04X\\x07\\x00\\x00\\x00N\\xc3\\xbameroq\\x05X\\x03\\x00\\x00\\x00S/Nq\\x06u.'\n" 290 | ] 291 | } 292 | ], 293 | "source": [ 294 | "string = dumps(test_dict)\n", 295 | "print(string)" 296 | ] 297 | }, 298 | { 299 | "cell_type": "code", 300 | "execution_count": 15, 301 | "metadata": { 302 | "collapsed": false, 303 | "scrolled": true 304 | }, 305 | "outputs": [ 306 | { 307 | "data": { 308 | "text/plain": [ 309 | "True" 310 | ] 311 | }, 312 | "execution_count": 15, 313 | "metadata": {}, 314 | "output_type": "execute_result" 315 | } 316 | ], 317 | "source": [ 318 | "pickle_dict = loads(string)\n", 319 | "test_dict == pickle_dict" 320 | ] 321 | }, 322 | { 323 | "cell_type": "markdown", 324 | "metadata": {}, 325 | "source": [ 326 | "* **Obs**: há pessoas que desencorajam o uso da biblioteca ```pickle``` em favor da biblioteca ```json```. Veja este post: https://www.benfrederickson.com/dont-pickle-your-data/" 327 | ] 328 | }, 329 | { 330 | "cell_type": "markdown", 331 | "metadata": {}, 332 | "source": [ 333 | "## Persistindo com Redis" 334 | ] 335 | }, 336 | { 337 | "cell_type": "markdown", 338 | "metadata": {}, 339 | "source": [ 340 | "Uma vez que você entenda o conceito de serialização, se torna bastante simples utilizar um banco de dados chave valor.\n", 341 | "\n", 342 | "Neste notebook, nós vamos usar o banco [Redis](https://redis.io), que você precisa instalar separadamente.\n", 343 | "\n", 344 | "Existem várias bibliotecas para integrar Python a Redis. Aqui nós usaremos a biblioteca ```redis```, que pode ser instalada via ```pip```." 345 | ] 346 | }, 347 | { 348 | "cell_type": "markdown", 349 | "metadata": {}, 350 | "source": [ 351 | "### Gerenciando a comunicação com o banco" 352 | ] 353 | }, 354 | { 355 | "cell_type": "markdown", 356 | "metadata": {}, 357 | "source": [ 358 | "Assim como é necessário um handler (gerenciador) para se comunicar com um arquivo, é necessário ter um handler para se comunicar com um banco de dados. \n", 359 | "\n", 360 | "A classe StrictRedis permite criar um handler para comunicação com o Redis. Para isto, é necessário informar o servidor (```host```), porta de comunicação (```port```) e o banco que se deseja acessar (```db```):" 361 | ] 362 | }, 363 | { 364 | "cell_type": "code", 365 | "execution_count": 16, 366 | "metadata": { 367 | "collapsed": true 368 | }, 369 | "outputs": [], 370 | "source": [ 371 | "from redis import StrictRedis" 372 | ] 373 | }, 374 | { 375 | "cell_type": "code", 376 | "execution_count": 17, 377 | "metadata": { 378 | "collapsed": false 379 | }, 380 | "outputs": [], 381 | "source": [ 382 | "r = StrictRedis(host='localhost', port=6379, db=0)" 383 | ] 384 | }, 385 | { 386 | "cell_type": "markdown", 387 | "metadata": {}, 388 | "source": [ 389 | "### Persistindo e recuperando um dado" 390 | ] 391 | }, 392 | { 393 | "cell_type": "markdown", 394 | "metadata": {}, 395 | "source": [ 396 | "Um objeto StrictHandler possui os métodos ```set``` e ```get``` para persistir e recuperar um dado, respectivamente.\n", 397 | "\n", 398 | "Ambos exigem que uma chave de identificação do valor seja informada:" 399 | ] 400 | }, 401 | { 402 | "cell_type": "code", 403 | "execution_count": 18, 404 | "metadata": { 405 | "collapsed": false 406 | }, 407 | "outputs": [ 408 | { 409 | "data": { 410 | "text/plain": [ 411 | "True" 412 | ] 413 | }, 414 | "execution_count": 18, 415 | "metadata": {}, 416 | "output_type": "execute_result" 417 | } 418 | ], 419 | "source": [ 420 | "r.set('minha_chave', dumps(test_dict))" 421 | ] 422 | }, 423 | { 424 | "cell_type": "code", 425 | "execution_count": 19, 426 | "metadata": { 427 | "collapsed": false 428 | }, 429 | "outputs": [ 430 | { 431 | "data": { 432 | "text/plain": [ 433 | "True" 434 | ] 435 | }, 436 | "execution_count": 19, 437 | "metadata": {}, 438 | "output_type": "execute_result" 439 | } 440 | ], 441 | "source": [ 442 | "redis_dict = loads(r.get(\"minha_chave\"))\n", 443 | "test_dict == redis_dict" 444 | ] 445 | }, 446 | { 447 | "cell_type": "markdown", 448 | "metadata": {}, 449 | "source": [ 450 | "Note que no exemplo acima o objeto foi persistido usando os procedimento ```dumps``` e ```loads``` da biblioteca ```pickle```. \n", 451 | "\n", 452 | "Também seria possível persistir o objeto usando os procedimentos ```dumps``` e ```loads``` da biblioteca ```json```. \n", 453 | "\n", 454 | "No entanto, como o método ```get``` retorna um objeto ```bytes```, é necessário convertê-lo para ```str``` antes de usar o procedimento ```loads```. \n", 455 | "\n", 456 | "Isto pode ser feito com o método ```bytes.decode()```." 457 | ] 458 | }, 459 | { 460 | "cell_type": "code", 461 | "execution_count": 20, 462 | "metadata": { 463 | "collapsed": true 464 | }, 465 | "outputs": [], 466 | "source": [ 467 | "from json import dumps, loads" 468 | ] 469 | }, 470 | { 471 | "cell_type": "code", 472 | "execution_count": 21, 473 | "metadata": { 474 | "collapsed": false 475 | }, 476 | "outputs": [ 477 | { 478 | "data": { 479 | "text/plain": [ 480 | "True" 481 | ] 482 | }, 483 | "execution_count": 21, 484 | "metadata": {}, 485 | "output_type": "execute_result" 486 | } 487 | ], 488 | "source": [ 489 | "r.set('minha_chave', dumps(test_dict))" 490 | ] 491 | }, 492 | { 493 | "cell_type": "code", 494 | "execution_count": 22, 495 | "metadata": { 496 | "collapsed": false 497 | }, 498 | "outputs": [ 499 | { 500 | "data": { 501 | "text/plain": [ 502 | "True" 503 | ] 504 | }, 505 | "execution_count": 22, 506 | "metadata": {}, 507 | "output_type": "execute_result" 508 | } 509 | ], 510 | "source": [ 511 | "redis_dict = loads(r.get(\"minha_chave\").decode())\n", 512 | "test_dict == redis_dict" 513 | ] 514 | }, 515 | { 516 | "cell_type": "code", 517 | "execution_count": null, 518 | "metadata": { 519 | "collapsed": true 520 | }, 521 | "outputs": [], 522 | "source": [] 523 | } 524 | ], 525 | "metadata": { 526 | "kernelspec": { 527 | "display_name": "Python 3", 528 | "language": "python", 529 | "name": "python3" 530 | }, 531 | "language_info": { 532 | "codemirror_mode": { 533 | "name": "ipython", 534 | "version": 3 535 | }, 536 | "file_extension": ".py", 537 | "mimetype": "text/x-python", 538 | "name": "python", 539 | "nbconvert_exporter": "python", 540 | "pygments_lexer": "ipython3", 541 | "version": "3.5.2" 542 | } 543 | }, 544 | "nbformat": 4, 545 | "nbformat_minor": 1 546 | } 547 | -------------------------------------------------------------------------------- /oop/examples/tv-remote.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "class MediaDevice:\n", 10 | " states = {\"standby\": \"Stand-by\", \"playing\": \"Playing\"}\n", 11 | " \n", 12 | " def __init__(self, volume=0, media_list=[]):\n", 13 | " self.state = \"standby\"\n", 14 | " self.volume = volume\n", 15 | " self.media_list = list(media_list)\n", 16 | " self.media = 0\n", 17 | " \n", 18 | " def __str__(self):\n", 19 | " classname = type(self)\n", 20 | " if self.state == \"standby\":\n", 21 | " return classname.states[self.state]\n", 22 | " else:\n", 23 | " return f\"{classname.states[self.state]} {self.media_list[self.media]} (option {self.media}) at volume {self.volume}\"\n", 24 | " \n", 25 | " def play(self):\n", 26 | " self.state = \"playing\"\n", 27 | "\n", 28 | " def stop(self):\n", 29 | " self.state = \"standby\"\n", 30 | " \n", 31 | " @property\n", 32 | " def volume(self):\n", 33 | " return self.__volume\n", 34 | "\n", 35 | " @volume.setter\n", 36 | " def volume(self, volume):\n", 37 | " if 0 <= volume <= 100:\n", 38 | " self.__volume = volume\n", 39 | " else:\n", 40 | " raise ValueError(\"Invalid volume value\")\n", 41 | " \n", 42 | " @property\n", 43 | " def media(self):\n", 44 | " return self.__media\n", 45 | "\n", 46 | " @media.setter\n", 47 | " def media(self, media):\n", 48 | " if 0 <= media < len(self.media_list): \n", 49 | " self.__media = media\n", 50 | " else:\n", 51 | " raise ValueError(\"Invalid media choice\")" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 2, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "tv_aberta = MediaDevice(media_list=[\"Band\", \"TVU\", \"Record\", \"Globo\", \"SBT\", \"MTV\"])" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": 3, 66 | "metadata": { 67 | "scrolled": false 68 | }, 69 | "outputs": [ 70 | { 71 | "name": "stdout", 72 | "output_type": "stream", 73 | "text": [ 74 | "Stand-by\n" 75 | ] 76 | } 77 | ], 78 | "source": [ 79 | "print(tv_aberta)" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": 4, 85 | "metadata": {}, 86 | "outputs": [], 87 | "source": [ 88 | "tv_aberta.play()" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 5, 94 | "metadata": { 95 | "scrolled": true 96 | }, 97 | "outputs": [ 98 | { 99 | "name": "stdout", 100 | "output_type": "stream", 101 | "text": [ 102 | "Playing Band (option 0) at volume 0\n" 103 | ] 104 | } 105 | ], 106 | "source": [ 107 | "print(tv_aberta)" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": 6, 113 | "metadata": {}, 114 | "outputs": [ 115 | { 116 | "ename": "ValueError", 117 | "evalue": "Invalid volume value", 118 | "output_type": "error", 119 | "traceback": [ 120 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 121 | "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", 122 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtv_aberta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvolume\u001b[0m \u001b[0;34m-=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 123 | "\u001b[0;32m\u001b[0m in \u001b[0;36mvolume\u001b[0;34m(self, volume)\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__volume\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvolume\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 32\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Invalid volume value\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 33\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 34\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mproperty\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 124 | "\u001b[0;31mValueError\u001b[0m: Invalid volume value" 125 | ] 126 | } 127 | ], 128 | "source": [ 129 | "tv_aberta.volume -= 1" 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": 7, 135 | "metadata": { 136 | "scrolled": true 137 | }, 138 | "outputs": [ 139 | { 140 | "ename": "ValueError", 141 | "evalue": "Invalid volume value", 142 | "output_type": "error", 143 | "traceback": [ 144 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 145 | "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", 146 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtv_aberta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvolume\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;36m101\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 147 | "\u001b[0;32m\u001b[0m in \u001b[0;36mvolume\u001b[0;34m(self, volume)\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__volume\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvolume\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 32\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Invalid volume value\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 33\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 34\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mproperty\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 148 | "\u001b[0;31mValueError\u001b[0m: Invalid volume value" 149 | ] 150 | } 151 | ], 152 | "source": [ 153 | "tv_aberta.volume += 101" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 8, 159 | "metadata": {}, 160 | "outputs": [], 161 | "source": [ 162 | "tv_aberta.volume += 1" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": 9, 168 | "metadata": {}, 169 | "outputs": [ 170 | { 171 | "name": "stdout", 172 | "output_type": "stream", 173 | "text": [ 174 | "Playing Band (option 0) at volume 1\n" 175 | ] 176 | } 177 | ], 178 | "source": [ 179 | "print(tv_aberta)" 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": 10, 185 | "metadata": {}, 186 | "outputs": [], 187 | "source": [ 188 | "tv_aberta.volume -= 1" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 11, 194 | "metadata": {}, 195 | "outputs": [ 196 | { 197 | "name": "stdout", 198 | "output_type": "stream", 199 | "text": [ 200 | "Playing Band (option 0) at volume 0\n" 201 | ] 202 | } 203 | ], 204 | "source": [ 205 | "print(tv_aberta)" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": 12, 211 | "metadata": { 212 | "scrolled": true 213 | }, 214 | "outputs": [ 215 | { 216 | "ename": "ValueError", 217 | "evalue": "Invalid media choice", 218 | "output_type": "error", 219 | "traceback": [ 220 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 221 | "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", 222 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtv_aberta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmedia\u001b[0m \u001b[0;34m-=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 223 | "\u001b[0;32m\u001b[0m in \u001b[0;36mmedia\u001b[0;34m(self, media)\u001b[0m\n\u001b[1;32m 41\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__media\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmedia\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 42\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 43\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Invalid media choice\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 224 | "\u001b[0;31mValueError\u001b[0m: Invalid media choice" 225 | ] 226 | } 227 | ], 228 | "source": [ 229 | "tv_aberta.media -= 1" 230 | ] 231 | }, 232 | { 233 | "cell_type": "code", 234 | "execution_count": 13, 235 | "metadata": {}, 236 | "outputs": [], 237 | "source": [ 238 | "tv_aberta.media += 5" 239 | ] 240 | }, 241 | { 242 | "cell_type": "code", 243 | "execution_count": 14, 244 | "metadata": {}, 245 | "outputs": [ 246 | { 247 | "name": "stdout", 248 | "output_type": "stream", 249 | "text": [ 250 | "Playing MTV (option 5) at volume 0\n" 251 | ] 252 | } 253 | ], 254 | "source": [ 255 | "print(tv_aberta)" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": 15, 261 | "metadata": {}, 262 | "outputs": [ 263 | { 264 | "ename": "ValueError", 265 | "evalue": "Invalid media choice", 266 | "output_type": "error", 267 | "traceback": [ 268 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 269 | "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", 270 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtv_aberta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmedia\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 271 | "\u001b[0;32m\u001b[0m in \u001b[0;36mmedia\u001b[0;34m(self, media)\u001b[0m\n\u001b[1;32m 41\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__media\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmedia\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 42\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 43\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Invalid media choice\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 272 | "\u001b[0;31mValueError\u001b[0m: Invalid media choice" 273 | ] 274 | } 275 | ], 276 | "source": [ 277 | "tv_aberta.media += 1" 278 | ] 279 | }, 280 | { 281 | "cell_type": "code", 282 | "execution_count": 16, 283 | "metadata": {}, 284 | "outputs": [ 285 | { 286 | "name": "stdout", 287 | "output_type": "stream", 288 | "text": [ 289 | "Playing MTV (option 5) at volume 0\n" 290 | ] 291 | } 292 | ], 293 | "source": [ 294 | "print(tv_aberta)" 295 | ] 296 | }, 297 | { 298 | "cell_type": "code", 299 | "execution_count": 17, 300 | "metadata": {}, 301 | "outputs": [], 302 | "source": [ 303 | "class RemoteControl:\n", 304 | " def __init__(self, device):\n", 305 | " self.device = device\n", 306 | " \n", 307 | " def pair(self, device):\n", 308 | " self.device = device\n", 309 | " \n", 310 | " def volume_up(self):\n", 311 | " self.device.volume += 1\n", 312 | " \n", 313 | " def volume_down(self):\n", 314 | " self.device.volume -= 1\n", 315 | " \n", 316 | " def next_media(self):\n", 317 | " self.device.media += 1\n", 318 | " \n", 319 | " def prev_media(self):\n", 320 | " self.device.media -= 1\n", 321 | " \n", 322 | " def change_media(self, media):\n", 323 | " self.device.media = media\n", 324 | " \n", 325 | " def info(self):\n", 326 | " print(self.device)" 327 | ] 328 | }, 329 | { 330 | "cell_type": "code", 331 | "execution_count": 18, 332 | "metadata": {}, 333 | "outputs": [], 334 | "source": [ 335 | "tv_remote = RemoteControl(tv_aberta)" 336 | ] 337 | }, 338 | { 339 | "cell_type": "code", 340 | "execution_count": 19, 341 | "metadata": {}, 342 | "outputs": [ 343 | { 344 | "name": "stdout", 345 | "output_type": "stream", 346 | "text": [ 347 | "Playing MTV (option 5) at volume 0\n" 348 | ] 349 | } 350 | ], 351 | "source": [ 352 | "tv_remote.info()" 353 | ] 354 | }, 355 | { 356 | "cell_type": "code", 357 | "execution_count": 20, 358 | "metadata": {}, 359 | "outputs": [ 360 | { 361 | "name": "stdout", 362 | "output_type": "stream", 363 | "text": [ 364 | "Playing MTV (option 5) at volume 1\n", 365 | "Playing MTV (option 5) at volume 2\n", 366 | "Playing MTV (option 5) at volume 3\n" 367 | ] 368 | } 369 | ], 370 | "source": [ 371 | "for i in range(3):\n", 372 | " tv_remote.volume_up()\n", 373 | " tv_remote.info()" 374 | ] 375 | }, 376 | { 377 | "cell_type": "code", 378 | "execution_count": 21, 379 | "metadata": {}, 380 | "outputs": [ 381 | { 382 | "name": "stdout", 383 | "output_type": "stream", 384 | "text": [ 385 | "Playing MTV (option 5) at volume 2\n", 386 | "Playing MTV (option 5) at volume 1\n" 387 | ] 388 | } 389 | ], 390 | "source": [ 391 | "for i in range(2):\n", 392 | " tv_remote.volume_down()\n", 393 | " tv_remote.info()" 394 | ] 395 | }, 396 | { 397 | "cell_type": "code", 398 | "execution_count": 22, 399 | "metadata": {}, 400 | "outputs": [ 401 | { 402 | "name": "stdout", 403 | "output_type": "stream", 404 | "text": [ 405 | "Playing SBT (option 4) at volume 1\n", 406 | "Playing Globo (option 3) at volume 1\n", 407 | "Playing Record (option 2) at volume 1\n", 408 | "Playing TVU (option 1) at volume 1\n" 409 | ] 410 | } 411 | ], 412 | "source": [ 413 | "for i in range(4):\n", 414 | " tv_remote.prev_media()\n", 415 | " tv_remote.info()" 416 | ] 417 | }, 418 | { 419 | "cell_type": "code", 420 | "execution_count": 23, 421 | "metadata": {}, 422 | "outputs": [ 423 | { 424 | "name": "stdout", 425 | "output_type": "stream", 426 | "text": [ 427 | "Playing Record (option 2) at volume 1\n", 428 | "Playing Globo (option 3) at volume 1\n" 429 | ] 430 | } 431 | ], 432 | "source": [ 433 | "for i in range(2):\n", 434 | " tv_remote.next_media()\n", 435 | " tv_remote.info()" 436 | ] 437 | }, 438 | { 439 | "cell_type": "code", 440 | "execution_count": 24, 441 | "metadata": {}, 442 | "outputs": [ 443 | { 444 | "name": "stdout", 445 | "output_type": "stream", 446 | "text": [ 447 | "Playing TVU (option 1) at volume 1\n", 448 | "Playing Band (option 0) at volume 1\n", 449 | "Playing Band (option 0) at volume 1\n" 450 | ] 451 | } 452 | ], 453 | "source": [ 454 | "from random import randint\n", 455 | "for i in range(3):\n", 456 | " tv_remote.change_media(randint(0,5))\n", 457 | " tv_remote.info()" 458 | ] 459 | } 460 | ], 461 | "metadata": { 462 | "kernelspec": { 463 | "display_name": "Python 3", 464 | "language": "python", 465 | "name": "python3" 466 | }, 467 | "language_info": { 468 | "codemirror_mode": { 469 | "name": "ipython", 470 | "version": 3 471 | }, 472 | "file_extension": ".py", 473 | "mimetype": "text/x-python", 474 | "name": "python", 475 | "nbconvert_exporter": "python", 476 | "pygments_lexer": "ipython3", 477 | "version": "3.7.0" 478 | } 479 | }, 480 | "nbformat": 4, 481 | "nbformat_minor": 2 482 | } 483 | -------------------------------------------------------------------------------- /RegexOne.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Using Regular Expressions in Python 3\n", 8 | "\n", 9 | "Este notebook é uma adaptação da [segunda parte](https://regexone.com/references/python) do [curso sobre expressões regulares]([RegexOne](https://regexone.com/lesson) do site [RegexOne](https://regexone.com).\n", 10 | "\n", 11 | "Python dá suporte a expressões regulares através da biblioteca padrão ```re```, disponibilizada em todas as instalações Python. Note que diferentes linguagens apresentam sintaxes variadas para expressões regulares. Aqui, vamos usar a sintaxe do Python, que tenta seguir o padrão [PCRE](https://www.pcre.org/)." 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": {}, 17 | "source": [ 18 | "## Strings cruas do Python (raw strings)\n", 19 | "\n", 20 | "Ao escrever expressões regulares em Python, é recomendável usar *raw strings* no lugar das strings tradicionais do Python (```str```). *Raw strings* começam com o prefixo especial **r**, que indica ao interpretador Python que ignore caracteres especiais.\n", 21 | "\n", 22 | "Na prática, isto significa que uma *raw string* como ```r\"\\n\"``` pode ser usada para buscar por uma quebra de linha. Usando strings normais, seria necessário o uso de caracteres de escape para que o caracter ```\\n``` fosse interpretado corretamente (```\"\\\\n\"```), tornando as expressões regulares menos legíveis." 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 1, 28 | "metadata": { 29 | "collapsed": false 30 | }, 31 | "outputs": [ 32 | { 33 | "name": "stdout", 34 | "output_type": "stream", 35 | "text": [ 36 | "Teste: \n", 37 | "\n", 38 | "Teste: \\n\n", 39 | "Teste: \\n\n" 40 | ] 41 | } 42 | ], 43 | "source": [ 44 | "a = \"\\n\"\n", 45 | "print(\"Teste:\", a)\n", 46 | "b = r\"\\n\"\n", 47 | "print(\"Teste:\", b)\n", 48 | "c = \"\\\\n\"\n", 49 | "print(\"Teste:\", c)" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "## Casando uma string\n", 57 | "\n", 58 | "O pacote ```re``` disponibiliza vários procedimentos. Para testar se uma expressão regular casa com uma string (**match**), podemos usar os procedimentos ```search()```, ```match()``` ou ```fullmatch()```:\n", 59 | "\n", 60 | "* **search**: Percorre a string para ver se alguma de suas substrings casa com a expressão passada.\n", 61 | "```python\n", 62 | "result = search(pattern, input_str, flags=0)\n", 63 | "```\n", 64 | "* **match**: Tenta casar a expressão passada com o início da string.\n", 65 | "```python\n", 66 | "result = match(pattern, input_str, flags=0)\n", 67 | "```\n", 68 | "* **fullmatch**: Tenta casar a expressão passada com a string inteira.\n", 69 | "```python\n", 70 | "result = fullmatch(pattern, input_str, flags=0)\n", 71 | "```\n", 72 | "\n", 73 | "Seja qual for o procedimento usado, o casamento bem sucedido da expressão retorna um objeto MatchObject, que contém informações sobre a (sub)string casada. Caso não haja casamento, a referência ```None``` é retornada.\n", 74 | "\n", 75 | "Note que mesmo o procedimento ```search()``` para de percorrer a string quando um casamento ocorre. Assim, esses métodos devem ser usados para verificar se uma string corresponde a uma expressão regular e não para extrair substrings de um texto.\n", 76 | "\n", 77 | "### Exemplo" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "### Exemplo\n", 85 | "\n", 86 | "Vamos usar uma expressão regular para casar uma data:" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 2, 92 | "metadata": { 93 | "collapsed": false, 94 | "scrolled": true 95 | }, 96 | "outputs": [ 97 | { 98 | "name": "stdout", 99 | "output_type": "stream", 100 | "text": [ 101 | "O padrão regex casa com a string informada! :)\n" 102 | ] 103 | } 104 | ], 105 | "source": [ 106 | "from re import search\n", 107 | "\n", 108 | "regex = r\"(\\d+) de ([a-zA-Z]+)\"\n", 109 | "if search(regex, \"Hoje é 24 de junho\"):\n", 110 | " print(\"O padrão regex casa com a string informada! :)\")\n", 111 | "else:\n", 112 | " print(\"O padrão regex não casa com a string informada. :(\")" 113 | ] 114 | }, 115 | { 116 | "cell_type": "markdown", 117 | "metadata": {}, 118 | "source": [ 119 | "Também é possível usar os métodos do objeto ```MatchObject``` retornado para mais informações:\n", 120 | "- os métodos ```start()``` e ```end()``` informam o início e o fim da primeira substring que casa com a expressão informada.\n", 121 | "- o método ```group()``` retorna o casamento inteiro e os grupos capturados." 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 3, 127 | "metadata": { 128 | "collapsed": false 129 | }, 130 | "outputs": [ 131 | { 132 | "name": "stdout", 133 | "output_type": "stream", 134 | "text": [ 135 | "Casamento da substring [7, 18)\n" 136 | ] 137 | } 138 | ], 139 | "source": [ 140 | "result = search(regex, \"Hoje é 24 de junho\")\n", 141 | "print(\"Casamento da substring [%s, %s)\" % (result.start(), result.end()))" 142 | ] 143 | }, 144 | { 145 | "cell_type": "markdown", 146 | "metadata": {}, 147 | "source": [ 148 | "Os grupos capturados são acessados a partir do índice 1. O índice 0 se refere ao casamento inteiro. \n", 149 | "* ```result.group(0)``` sempre retorna a substring inteira.\n", 150 | "* ```result.group(1), result.group(2), ...``` retornam os grupos capturados, contados da esquerda para a direita.\n", 151 | "* ```result.group()``` é equivalente a ```result.group(0)```" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 4, 157 | "metadata": { 158 | "collapsed": false 159 | }, 160 | "outputs": [ 161 | { 162 | "name": "stdout", 163 | "output_type": "stream", 164 | "text": [ 165 | "Casamento: 24 de junho\n", 166 | "Dia: 24\n", 167 | "Mês: junho\n" 168 | ] 169 | } 170 | ], 171 | "source": [ 172 | "print(\"Casamento: %s\" % (result.group(0)))\n", 173 | "print(\"Dia: %s\" % (result.group(1)))\n", 174 | "print(\"Mês: %s\" % (result.group(2)))" 175 | ] 176 | }, 177 | { 178 | "cell_type": "markdown", 179 | "metadata": {}, 180 | "source": [ 181 | "## Capturando grupos\n", 182 | "\n", 183 | "Para extrair informações de um texto, podemos usar os procedimentos ```findall()``` ou ```finditer()```:\n", 184 | "\n", 185 | "* **findall**: Quando a expressão apresenta grupos, retorna uma lista contendo todos os dados capturados. Caso contrário, retorna uma lista contendo todos os casamentos efetuados.\n", 186 | "```python\n", 187 | "matchList = findall(pattern, input_str, flags=0)\n", 188 | "```\n", 189 | "* **finditer**: Idêntico a findall(), porém retorna uma lista de referências para objetos MatchObject. \n", 190 | "```python\n", 191 | "matchList = re.finditer(pattern, input_str, flags=0)\n", 192 | "```" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "### Exemplo\n", 200 | "\n", 201 | "Vamos usar uma expressão regular para casar algumas datas:}" 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": 5, 207 | "metadata": { 208 | "collapsed": false 209 | }, 210 | "outputs": [ 211 | { 212 | "name": "stdout", 213 | "output_type": "stream", 214 | "text": [ 215 | "Casamento: 09 de abril\n", 216 | "Casamento: 23 de fevereiro\n", 217 | "Casamento: 01 de setembro\n" 218 | ] 219 | } 220 | ], 221 | "source": [ 222 | "from re import findall, finditer\n", 223 | "\n", 224 | "regex = r\"\\d+ de [a-zA-Z]+\"\n", 225 | "matches = findall(regex, \"Minha mãe nasceu em 09 de abril. Eu nasci em 23 de fevereiro. Minha filha nasceu em 01 de setembro.\")\n", 226 | "for match in matches:\n", 227 | " print(\"Casamento: %s\" % (match)) " 228 | ] 229 | }, 230 | { 231 | "cell_type": "markdown", 232 | "metadata": {}, 233 | "source": [ 234 | "Para capturar o mês específico de cada data, podemos usar um grupo:" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 6, 240 | "metadata": { 241 | "collapsed": false 242 | }, 243 | "outputs": [ 244 | { 245 | "name": "stdout", 246 | "output_type": "stream", 247 | "text": [ 248 | "Casamento: abril\n", 249 | "Casamento: fevereiro\n", 250 | "Casamento: setembro\n" 251 | ] 252 | } 253 | ], 254 | "source": [ 255 | "regex = r\"\\d+ de ([a-zA-Z]+)\"\n", 256 | "matches = findall(regex, \"Minha mãe nasceu em 09 de abril. Eu nasci em 23 de fevereiro. Minha filha nasceu em 01 de setembro.\")\n", 257 | "for match in matches:\n", 258 | " print(\"Casamento: %s\" % (match))" 259 | ] 260 | }, 261 | { 262 | "cell_type": "markdown", 263 | "metadata": {}, 264 | "source": [ 265 | "Se precisamors de mais informações sobre cada casamento (ou grupo), usamos ```finditer()```:" 266 | ] 267 | }, 268 | { 269 | "cell_type": "code", 270 | "execution_count": 7, 271 | "metadata": { 272 | "collapsed": false 273 | }, 274 | "outputs": [ 275 | { 276 | "name": "stdout", 277 | "output_type": "stream", 278 | "text": [ 279 | "Casamento: [20, 31)\n", 280 | "Casamento: [45, 60)\n", 281 | "Casamento: [84, 98)\n" 282 | ] 283 | } 284 | ], 285 | "source": [ 286 | "regex = r\"\\d+ de ([a-zA-Z]+)\"\n", 287 | "matches = finditer(regex, \"Minha mãe nasceu em 09 de abril. Eu nasci em 23 de fevereiro. Minha filha nasceu em 01 de setembro.\")\n", 288 | "for match in matches:\n", 289 | " print(\"Casamento: [%s, %s)\" % (match.start(), match.end()))" 290 | ] 291 | }, 292 | { 293 | "cell_type": "markdown", 294 | "metadata": {}, 295 | "source": [ 296 | "## Buscando e substituindo" 297 | ] 298 | }, 299 | { 300 | "cell_type": "markdown", 301 | "metadata": {}, 302 | "source": [ 303 | "Outra tarefa comum é buscar e substituir uma parte de uma string usando expressões regulares. \n", 304 | "\n", 305 | "Um exemplo comum é alterar um delimitador usado em um arquivo de dados tabulados.\n", 306 | "\n", 307 | "Em Python, podemos usar o procedimento ```sub()``` para isso:\n", 308 | "```python\n", 309 | "replacedString = sub(pattern, replacement_pattern, input_str, count, flags=0)\n", 310 | "```\n", 311 | "\n", 312 | "O argumento opcional ```count``` determina o número máximo de substituições a serem feitas. Caso seu valor seja nulo ou negativo, todas as ocorrências encontradas são substituídas." 313 | ] 314 | }, 315 | { 316 | "cell_type": "markdown", 317 | "metadata": {}, 318 | "source": [ 319 | "### Exemplo\n", 320 | "\n", 321 | "Vamos tentar inverter a ordem do dia e do mês na frase anterior. Note que o padrão de substituição também é escrito como uma *raw_string*:" 322 | ] 323 | }, 324 | { 325 | "cell_type": "code", 326 | "execution_count": 8, 327 | "metadata": { 328 | "collapsed": false 329 | }, 330 | "outputs": [ 331 | { 332 | "name": "stdout", 333 | "output_type": "stream", 334 | "text": [ 335 | "Minha mãe nasceu em abril, no dia 09. Eu nasci em fevereiro, no dia 23. Minha filha nasceu em setembro, no dia 01.\n" 336 | ] 337 | } 338 | ], 339 | "source": [ 340 | "from re import sub\n", 341 | "\n", 342 | "regex = r\"(\\d+) de ([a-zA-Z]+)\"\n", 343 | "ordem = sub(regex, r\"\\2, no dia \\1\", \"Minha mãe nasceu em 09 de abril. Eu nasci em 23 de fevereiro. Minha filha nasceu em 01 de setembro.\")\n", 344 | "print(ordem)" 345 | ] 346 | }, 347 | { 348 | "cell_type": "code", 349 | "execution_count": 9, 350 | "metadata": { 351 | "collapsed": false 352 | }, 353 | "outputs": [ 354 | { 355 | "name": "stdout", 356 | "output_type": "stream", 357 | "text": [ 358 | "Minha mãe nasceu em abril, no dia 09.\n", 359 | "Eu nasci em fevereiro, no dia 23.\n", 360 | "Minha filha nasceu em setembro, no dia 01.\n" 361 | ] 362 | } 363 | ], 364 | "source": [ 365 | "print(sub(r\"\\.\\s\", r\".\\n\", ordem))" 366 | ] 367 | }, 368 | { 369 | "cell_type": "markdown", 370 | "metadata": {}, 371 | "source": [ 372 | "## Flags\n", 373 | "\n", 374 | "Todos os procedimentos do módulo ```re``` vistos acima aceitam flags como parâmetros opcionais.\n", 375 | "\n", 376 | "A maior parte das flags disponíveis podem ser especificadas diretamente nas expressões regulares, mas em alguns casos pode ser útil utilizá-las como parâmetros:\n", 377 | "\n", 378 | "* ```IGNORECASE``` faz o padrão se tornar insensível a caso.\n", 379 | "* ```MULTILINE``` é necessário quando a string apresenta quebras de linha (```\\n```). Com esta flag, os metacaracteres de início (```^```) e fim (```$```) passam a ser analisados por linha.\n", 380 | "* ```DOTALL``` faz com que o metacaracter ```.``` case com qualquer caracter, incluindo a quebra de linha (```\\n```)." 381 | ] 382 | }, 383 | { 384 | "cell_type": "markdown", 385 | "metadata": {}, 386 | "source": [ 387 | "## Compilando expressões para ter performance" 388 | ] 389 | }, 390 | { 391 | "cell_type": "markdown", 392 | "metadata": {}, 393 | "source": [ 394 | "Criar uma nova expressão regular em Python cada vez que se deseja casar strings é uma abordagem pouco eficiente.\n", 395 | "\n", 396 | "Nesse caso, é recomendado que se compile a expressão regular antes de processar as strings alvo:\n", 397 | "\n", 398 | "```regexObject = compile(pattern, flags=0)```\n", 399 | "\n", 400 | "Este procedimento cria um objeto do tipo RegexObject.\n", 401 | "\n", 402 | "Esta classe implementa como métodos todos os procedimentos descritos neste notebook, mas você não precisa mais passar sua expressão regular como parâmetro a cada chamada (nem eventuais flags)." 403 | ] 404 | }, 405 | { 406 | "cell_type": "markdown", 407 | "metadata": {}, 408 | "source": [ 409 | "### Exemplo\n", 410 | "\n", 411 | "Vamos criar uma expressão e extrair informações:" 412 | ] 413 | }, 414 | { 415 | "cell_type": "code", 416 | "execution_count": 10, 417 | "metadata": { 418 | "collapsed": false, 419 | "scrolled": true 420 | }, 421 | "outputs": [ 422 | { 423 | "name": "stdout", 424 | "output_type": "stream", 425 | "text": [ 426 | "0 11\n" 427 | ] 428 | } 429 | ], 430 | "source": [ 431 | "from re import compile\n", 432 | "regex = compile(r\"(\\w+) World\")\n", 433 | "result = regex.search(\"Hello World é o mais fácil\")\n", 434 | "if result:\n", 435 | " print(result.start(), result.end())" 436 | ] 437 | }, 438 | { 439 | "cell_type": "markdown", 440 | "metadata": {}, 441 | "source": [ 442 | "Usando o mesmo objeto, vamos imprimir todos os grupos capturados:" 443 | ] 444 | }, 445 | { 446 | "cell_type": "code", 447 | "execution_count": 11, 448 | "metadata": { 449 | "collapsed": false 450 | }, 451 | "outputs": [ 452 | { 453 | "name": "stdout", 454 | "output_type": "stream", 455 | "text": [ 456 | "Hello\n", 457 | "Ciao\n" 458 | ] 459 | } 460 | ], 461 | "source": [ 462 | "for result in regex.findall(\"Hello World, Ciao World\"):\n", 463 | " print(result)" 464 | ] 465 | }, 466 | { 467 | "cell_type": "markdown", 468 | "metadata": {}, 469 | "source": [ 470 | "Por último, vamos substituir Mundo por Terra:" 471 | ] 472 | }, 473 | { 474 | "cell_type": "code", 475 | "execution_count": 12, 476 | "metadata": { 477 | "collapsed": false 478 | }, 479 | "outputs": [ 480 | { 481 | "name": "stdout", 482 | "output_type": "stream", 483 | "text": [ 484 | "Hello Earth\n" 485 | ] 486 | } 487 | ], 488 | "source": [ 489 | "print(regex.sub(r\"\\1 Earth\", \"Hello World\"))" 490 | ] 491 | } 492 | ], 493 | "metadata": { 494 | "kernelspec": { 495 | "display_name": "Python 3", 496 | "language": "python", 497 | "name": "python3" 498 | }, 499 | "language_info": { 500 | "codemirror_mode": { 501 | "name": "ipython", 502 | "version": 3 503 | }, 504 | "file_extension": ".py", 505 | "mimetype": "text/x-python", 506 | "name": "python", 507 | "nbconvert_exporter": "python", 508 | "pygments_lexer": "ipython3", 509 | "version": "3.5.2" 510 | } 511 | }, 512 | "nbformat": 4, 513 | "nbformat_minor": 1 514 | } 515 | -------------------------------------------------------------------------------- /ned/names-and-values-01.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Fatos e mitos sobre referências e objetos em Python" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Este notebook é a primeira parte de uma adaptação do post [\"Facts and myths about Python names and values\"](https://nedbatchelder.com/text/names.html), de Ned Batchelder." 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "### Fato: Nomes se referem a objetos." 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "Como em muitas linguagens de programação, uma **associação** em Python associa um nome (lado esquerdo da associação) com um objeto (lado direito da associação). Em Python, dizemos que nomes se referem a objetos, ou que um nome é uma referência a um objeto." 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 1, 34 | "metadata": { 35 | "collapsed": true 36 | }, 37 | "outputs": [], 38 | "source": [ 39 | "x = 23" 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "metadata": {}, 45 | "source": [ 46 | "Agora o nome **x** se refere ao objeto 23. Da próxima vez que usarmos o nome **x** (exceto do lado esquerdo de uma associação), receberemos o objeto 23:" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 2, 52 | "metadata": { 53 | "collapsed": false 54 | }, 55 | "outputs": [ 56 | { 57 | "name": "stdout", 58 | "output_type": "stream", 59 | "text": [ 60 | "25\n" 61 | ] 62 | } 63 | ], 64 | "source": [ 65 | "print(x + 2)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "No diagrama abaixo, o retângulo cinza parecido com uma etiqueta é um nome, com uma seta apontando para seu objeto associado. Aqui, o nome **x** se refere ao inteiro **23**:" 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "metadata": { 78 | "collapsed": true 79 | }, 80 | "source": [ 81 | "" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": {}, 87 | "source": [ 88 | "### Fato: Muitos nomes podem se referir ao mesmo objeto." 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": {}, 94 | "source": [ 95 | "Não há regra que gida que um objeto só possa ter um nome. Uma associação pode fazer com que um segundo (ou terceiro, ...) nome se refira ao mesmo objeto." 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 3, 101 | "metadata": { 102 | "collapsed": true 103 | }, 104 | "outputs": [], 105 | "source": [ 106 | "x = 23\n", 107 | "y = x" 108 | ] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "metadata": {}, 113 | "source": [ 114 | "" 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "metadata": {}, 120 | "source": [ 121 | "Nem x nem y são o nome real do objeto. Ambos têm o mesmo status: cada um se refere ao objeto da mesma forma." 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": {}, 127 | "source": [ 128 | "### Fato: nomes são reassociados independentemente de outros nomes." 129 | ] 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "metadata": {}, 134 | "source": [ 135 | "Se dois nomes se referem ao mesmo objeto, isto não vincula magicamente os dois nomes. Reassociar um desses nomes não significa reassociar o outro:" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": 4, 141 | "metadata": { 142 | "collapsed": true 143 | }, 144 | "outputs": [], 145 | "source": [ 146 | "x = 23\n", 147 | "y = x\n", 148 | "x = 12" 149 | ] 150 | }, 151 | { 152 | "cell_type": "markdown", 153 | "metadata": {}, 154 | "source": [ 155 | "" 156 | ] 157 | }, 158 | { 159 | "cell_type": "markdown", 160 | "metadata": {}, 161 | "source": [ 162 | "Quando dizemos ```y = x```, estamos dizendo que **y** deve ser associado ao objeto associado a **x**. Isto não significa que **x** e **y** estarão associados ao mesmo objeto para sempre. Reassociar **x** com um novo objeto não altera a associação de **y**. Imagine o caos se não fosse assim!" 163 | ] 164 | }, 165 | { 166 | "cell_type": "markdown", 167 | "metadata": {}, 168 | "source": [ 169 | "### Fato: um objeto vive até que não haja mais nenhuma referência a ele." 170 | ] 171 | }, 172 | { 173 | "cell_type": "markdown", 174 | "metadata": {}, 175 | "source": [ 176 | "O interpretador Python mantém o registro de quantas referências um objeto têm, e automaticamente destrói objetos que não são mais referenciados. Isto se chama \"coleta de lixo\", e significa que você não precisa destruir objetos -- eles são destruídos quando não são mais necessários." 177 | ] 178 | }, 179 | { 180 | "cell_type": "markdown", 181 | "metadata": {}, 182 | "source": [ 183 | "## Associações" 184 | ] 185 | }, 186 | { 187 | "cell_type": "markdown", 188 | "metadata": {}, 189 | "source": [ 190 | "### Fato: uma associação nunca copia dados." 191 | ] 192 | }, 193 | { 194 | "cell_type": "markdown", 195 | "metadata": {}, 196 | "source": [ 197 | "Quando objetos têm mais de um nome, é fácil se confundir e pensar que são dois nomes e dois objetos:" 198 | ] 199 | }, 200 | { 201 | "cell_type": "code", 202 | "execution_count": 5, 203 | "metadata": { 204 | "collapsed": true 205 | }, 206 | "outputs": [], 207 | "source": [ 208 | "x = 23\n", 209 | "y = x\n", 210 | "# \"Agora eu tenho dois objetos: x e y!\"\n", 211 | "# NÃO: você tem dois nomes, mas apenas um objeto." 212 | ] 213 | }, 214 | { 215 | "cell_type": "markdown", 216 | "metadata": {}, 217 | "source": [ 218 | "Associar um objeto a um nome nunca copia dados, nem jamais cria um novo objeto. Associar apenas faz com o que o nome na esquerda se refira ao objeto na direita. Neste caso, temos apenas o objeto **23** e dois nomes **x** e **y**. Ambos se referem a **23**, como vimos no diagrama anterior.\n", 219 | "\n", 220 | "As coisas se tornam mais interessantes quando temos objetos mais complexos, como uma lista:" 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": 6, 226 | "metadata": { 227 | "collapsed": true 228 | }, 229 | "outputs": [], 230 | "source": [ 231 | "nums = [1, 2, 3]" 232 | ] 233 | }, 234 | { 235 | "cell_type": "markdown", 236 | "metadata": {}, 237 | "source": [ 238 | "" 239 | ] 240 | }, 241 | { 242 | "cell_type": "markdown", 243 | "metadata": {}, 244 | "source": [ 245 | "Agora, se associarmos esta lista com outro nome, teremos dois nomes se referindo à mesma lista:" 246 | ] 247 | }, 248 | { 249 | "cell_type": "code", 250 | "execution_count": 7, 251 | "metadata": { 252 | "collapsed": true 253 | }, 254 | "outputs": [], 255 | "source": [ 256 | "nums = [1, 2, 3]\n", 257 | "tri = nums" 258 | ] 259 | }, 260 | { 261 | "cell_type": "markdown", 262 | "metadata": {}, 263 | "source": [ 264 | "" 265 | ] 266 | }, 267 | { 268 | "cell_type": "markdown", 269 | "metadata": {}, 270 | "source": [ 271 | "Lembre-se: uma associação nunca cria novos objetos e nunca copia dados. Esta associação não transforma magicamente minha lista em duas listas.\n", 272 | "\n", 273 | "Neste ponto, temos uma lista, com dois nomes se referindo a ela, que pode levar a uma grande surpresa que é tão comum que deveria ganhar um apelido." 274 | ] 275 | }, 276 | { 277 | "cell_type": "markdown", 278 | "metadata": {}, 279 | "source": [ 280 | "### Fato: mudanças em um objeto são visíveis através de todos os seus nomes." 281 | ] 282 | }, 283 | { 284 | "cell_type": "markdown", 285 | "metadata": {}, 286 | "source": [ 287 | "Objetos podem pertencer a uma de duas categorias, em função do seu tipo: mutáveis ou imutáveis. \n", 288 | "\n", 289 | "Objetos imutáveis incluem números, strings e tuplas. Quase todo o resto é mutável, incluindo listas, dicionários e objetos definidos por usuários.\n", 290 | "\n", 291 | "**Mutável** significa que um objeto tem métodos que podem alterar seu estado *in-place* (sem precisar criar um novo objeto). \n", 292 | "\n", 293 | "**Imutável** significa que o objeto nunca poderá mudar. Na verdade, quando você pensa que está alterando um objeto imutável, você está criando novos objetos a partir do objeto existente.\n", 294 | "\n", 295 | "Já que números são imutáveis, você não pode alterá-los *in-place*. Você pode apenas criar um novo objeto e associá-lo ao mesmo nome:" 296 | ] 297 | }, 298 | { 299 | "cell_type": "code", 300 | "execution_count": 8, 301 | "metadata": { 302 | "collapsed": true 303 | }, 304 | "outputs": [], 305 | "source": [ 306 | "x = 1\n", 307 | "x = x + 1" 308 | ] 309 | }, 310 | { 311 | "cell_type": "markdown", 312 | "metadata": {}, 313 | "source": [ 314 | "Acima, ```x+1``` cria um novo objeto, que é então associado ao nome **x**.\n", 315 | "\n", 316 | "Mais precisamente, o nome **x** do lado direito da associação permite acessar o objeto **1**. O operador infixo de adição **+** recebe o objeto **1** duas vezes, e cria um objeto **2**.\n", 317 | "\n", 318 | "Assim, não é a associação que cria o novo objeto, mas a expressão do lado direito da associação.\n", 319 | "\n", 320 | "Com um objeto mutável, você pode mudar seu estado diretamente, geralmente através de um método do objeto:" 321 | ] 322 | }, 323 | { 324 | "cell_type": "code", 325 | "execution_count": 9, 326 | "metadata": { 327 | "collapsed": true 328 | }, 329 | "outputs": [], 330 | "source": [ 331 | "nums = [1, 2, 3]\n", 332 | "nums.append(4)" 333 | ] 334 | }, 335 | { 336 | "cell_type": "markdown", 337 | "metadata": {}, 338 | "source": [ 339 | "\n", 340 | "" 341 | ] 342 | }, 343 | { 344 | "cell_type": "markdown", 345 | "metadata": {}, 346 | "source": [ 347 | "Não mudamos a qual objeto **nums** se refere. \n", 348 | "\n", 349 | "No começo, o nome **nums** se refere a uma lista com três objetos.\n", 350 | "\n", 351 | "Em seguida, usamos o nome **numes** para acessar a lista, mas não associamos nada a **nums** -- o nome continua se referindo à mesma lista.\n", 352 | "\n", 353 | "O método ```append``` modifica a lista adicionando o objeto **4**, mas isso não cria uma nova lista -- a alteração é feita *in-place* e **nums** continua se referindo a esta lista.\n", 354 | "\n", 355 | "Esta distinção entre associar um nome e alterar um objeto às vezes é descrita como \"*reassociar o nome versus alterar o objeto*\".\n", 356 | "\n", 357 | "É neste ponto que muitas pessoas se sentem surpresas: **se dois nomes se referem ao mesmo objeto e objedo é alterado, os dois nomes perceberão a mudança**:" 358 | ] 359 | }, 360 | { 361 | "cell_type": "code", 362 | "execution_count": 10, 363 | "metadata": { 364 | "collapsed": false 365 | }, 366 | "outputs": [ 367 | { 368 | "name": "stdout", 369 | "output_type": "stream", 370 | "text": [ 371 | "[1, 2, 3, 4]\n" 372 | ] 373 | } 374 | ], 375 | "source": [ 376 | "nums = [1, 2, 3]\n", 377 | "tri = nums\n", 378 | "nums.append(4)\n", 379 | "\n", 380 | "print(tri)" 381 | ] 382 | }, 383 | { 384 | "cell_type": "markdown", 385 | "metadata": {}, 386 | "source": [ 387 | "Porque **tri** mudou?! A resposta segue o que aprendemos até aqui.\n", 388 | "\n", 389 | "Associações nunca copias valores, então os dois nomes se referem à mesma lista:" 390 | ] 391 | }, 392 | { 393 | "cell_type": "markdown", 394 | "metadata": {}, 395 | "source": [ 396 | "" 397 | ] 398 | }, 399 | { 400 | "cell_type": "markdown", 401 | "metadata": {}, 402 | "source": [ 403 | "Em seguida, alteramos a lista chamando o método ```append```, que modifica a lista *in-place*.\n", 404 | "\n", 405 | "Já que **tri** se refere à mesma lista, quando examinamos **tri** estamos examinamos a mesma lista referida por **nums**, que foi alterada.\n", 406 | "\n", 407 | "Assim, **tri** agora também inclui o objeto **4**:" 408 | ] 409 | }, 410 | { 411 | "cell_type": "markdown", 412 | "metadata": {}, 413 | "source": [ 414 | "" 415 | ] 416 | }, 417 | { 418 | "cell_type": "markdown", 419 | "metadata": {}, 420 | "source": [ 421 | "Este é o principal problema que as pessoas enfrentam com nomes e objetos em Python. \n", 422 | "\n", 423 | "Um objeto é referenciado por mais de um nome. Quando o objeto é alterado, todos os nomes visualizam a mudança!\n", 424 | "\n", 425 | "Pra que isto aconteça, você precisa de:\n", 426 | "\n", 427 | "* Um objeto mutável, neste caso a lista.\n", 428 | "* Mais de um nome se referindo a este objeto.\n", 429 | "* Algum trecho de código que altere o objeto através de um de seus nomes.\n", 430 | "\n", 431 | "Lembre-se que este não é um bug do Python. Muitos objetos têm mais de um nome ao longo de um código e é perfeitamente normal alterar objetos e essas alterações serem visíveis através dos seus outros nomes.\n", 432 | "\n", 433 | "A alternativa seria copiar os valores, mas isso tornaria os programas excessivamente lentos." 434 | ] 435 | }, 436 | { 437 | "cell_type": "markdown", 438 | "metadata": {}, 439 | "source": [ 440 | "### Mito: Python associa objetos mutáveis e imutáveis de forma diferente.\n", 441 | "\n", 442 | "Já que o caso acima só acontece com objetos mutáveis, algumas pessoas acreditam que a associação funciona de forma diferente para objetos mutáveis e imutáveis. Não é isso.\n", 443 | "\n", 444 | "Todas as associações funcionam da mesma forma: um nome passa a se referir a um objeto. A diferença é que um objeto imutável não pode ser alterado, então múltiplos nomes associados a ele sempre apresentarão o mesmo estado do objeto. " 445 | ] 446 | }, 447 | { 448 | "cell_type": "markdown", 449 | "metadata": {}, 450 | "source": [ 451 | "## Associações compostas" 452 | ] 453 | }, 454 | { 455 | "cell_type": "markdown", 456 | "metadata": {}, 457 | "source": [ 458 | "Um tipo de operador mal compreendido em Python são os operadores de associação composta. O operador ```+=```, por exemplo, é apresentado abaixo." 459 | ] 460 | }, 461 | { 462 | "cell_type": "code", 463 | "execution_count": 11, 464 | "metadata": { 465 | "collapsed": false 466 | }, 467 | "outputs": [], 468 | "source": [ 469 | "nums = [1, 2, 3]\n", 470 | "tri = nums\n", 471 | "nums += [4]" 472 | ] 473 | }, 474 | { 475 | "cell_type": "markdown", 476 | "metadata": {}, 477 | "source": [ 478 | "Antes da associação composta: \n", 479 | "Após a associação composta: " 480 | ] 481 | }, 482 | { 483 | "cell_type": "markdown", 484 | "metadata": {}, 485 | "source": [ 486 | "Como pode ser visto, o operador ```+=``` também funciona como um método de alteração in-place, no caso de objetos mutáveis. \n", 487 | "\n", 488 | "Em contrapartida, operadores infixos como o ```+``` devem sempre produzir novos objetos, independentemente de seus operandos serem mutáveis ou não:" 489 | ] 490 | }, 491 | { 492 | "cell_type": "code", 493 | "execution_count": 12, 494 | "metadata": { 495 | "collapsed": false 496 | }, 497 | "outputs": [], 498 | "source": [ 499 | "nums = [1, 2, 3]\n", 500 | "tri = nums\n", 501 | "nums = nums + [4]" 502 | ] 503 | }, 504 | { 505 | "cell_type": "markdown", 506 | "metadata": {}, 507 | "source": [ 508 | "Antes da associação: \n", 509 | "Após a associação: " 510 | ] 511 | }, 512 | { 513 | "cell_type": "markdown", 514 | "metadata": {}, 515 | "source": [ 516 | "Assim, é importante entender que, diferentemente de outras linguagens, **utilizar um operador de associação composta em Python não necessariamente leva ao mesmo resultado que fazer uma operação com um operador infixo e em seguida uma associação!**\n", 517 | "\n", 518 | "Note que esta diferença só se torna visível para objetos mutáveis, uma vez que objetos imutáveis não permitem alteração in-place:" 519 | ] 520 | }, 521 | { 522 | "cell_type": "code", 523 | "execution_count": 13, 524 | "metadata": { 525 | "collapsed": true 526 | }, 527 | "outputs": [], 528 | "source": [ 529 | "x = 23\n", 530 | "x = y\n", 531 | "x += 1" 532 | ] 533 | }, 534 | { 535 | "cell_type": "markdown", 536 | "metadata": {}, 537 | "source": [ 538 | "Antes da associação composta: \n", 539 | "Após a associação composta: " 540 | ] 541 | } 542 | ], 543 | "metadata": { 544 | "kernelspec": { 545 | "display_name": "Python 3", 546 | "language": "python", 547 | "name": "python3" 548 | }, 549 | "language_info": { 550 | "codemirror_mode": { 551 | "name": "ipython", 552 | "version": 3 553 | }, 554 | "file_extension": ".py", 555 | "mimetype": "text/x-python", 556 | "name": "python", 557 | "nbconvert_exporter": "python", 558 | "pygments_lexer": "ipython3", 559 | "version": "3.5.2" 560 | } 561 | }, 562 | "nbformat": 4, 563 | "nbformat_minor": 1 564 | } 565 | -------------------------------------------------------------------------------- /oop/examples/bank-account.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "class Account:\n", 10 | " modes = {\"checking\": \"Conta corrente\", \"savings\": \"Poupança\"}\n", 11 | " def __init__(self, number, owner, mode, balance):\n", 12 | " self.number = number\n", 13 | " self.owner = owner\n", 14 | " self.mode = mode\n", 15 | " self.balance = balance\n", 16 | " self.log = []\n", 17 | " \n", 18 | " def __str__(self):\n", 19 | " return f\"{self.number}\\t{self.owner}\\t{type(self).modes[self.mode]}\\t{self.balance:.2f}\"\n", 20 | "\n", 21 | " @property\n", 22 | " def number(self):\n", 23 | " return self.__number\n", 24 | " \n", 25 | " @number.setter\n", 26 | " def number(self, number):\n", 27 | " try:\n", 28 | " number = int(number)\n", 29 | " if number < 0:\n", 30 | " raise ValueError(\"account numbers should be non-negative\")\n", 31 | " except ValueError as error:\n", 32 | " print(f\"Invalid account number: {error}\")\n", 33 | " self.__number = number\n", 34 | " \n", 35 | " @property\n", 36 | " def owner(self):\n", 37 | " return self.__owner\n", 38 | " \n", 39 | " @owner.setter\n", 40 | " def owner(self, owner):\n", 41 | " from re import search\n", 42 | " if not owner or search(r\"\\d\", owner):\n", 43 | " print(\"Invalid account owner: owner is either empty or contains digits\")\n", 44 | " else:\n", 45 | " self.__owner = owner \n", 46 | " \n", 47 | " @property\n", 48 | " def mode(self):\n", 49 | " return self.__mode\n", 50 | " \n", 51 | " @mode.setter\n", 52 | " def mode(self, mode):\n", 53 | " if mode not in type(self).modes:\n", 54 | " print (\"Invalid account type: valid options are: {}\".format(\", \".join(type(self).modes.keys()))) \n", 55 | " self.__mode = mode\n", 56 | " \n", 57 | " @property\n", 58 | " def balance(self):\n", 59 | " return self.__balance\n", 60 | " \n", 61 | " @balance.setter\n", 62 | " def balance(self, balance):\n", 63 | " try:\n", 64 | " self.__balance = float(balance)\n", 65 | " except ValueError as error:\n", 66 | " print(f\"Invalid account balance: {error}\")\n", 67 | " \n", 68 | " def deposit(self, amount):\n", 69 | " if amount <= 0:\n", 70 | " print(f\"Invalid deposit amount: {amount}\")\n", 71 | " else:\n", 72 | " self.balance += amount\n", 73 | " self.log.append(amount)\n", 74 | "\n", 75 | " def withdraw(self, amount):\n", 76 | " if amount <= 0:\n", 77 | " print(f\"Invalid withdraw amount: {amount}\")\n", 78 | " else:\n", 79 | " self.balance -= amount\n", 80 | " self.log.append(-amount)\n", 81 | " \n", 82 | " def statement(self, records=30):\n", 83 | " print(*self.log[-records:], sep=\"\\n\")\n", 84 | "\n", 85 | " @classmethod\n", 86 | " def __build(cls, number, mode=\"savings\"):\n", 87 | " owner = input(\"Titular: \")\n", 88 | " balance = float(input(\"Saldo inicial: \"))\n", 89 | " return cls(number, owner, mode, balance)\n", 90 | "\n", 91 | " @classmethod\n", 92 | " def build_savings(cls, number):\n", 93 | " return cls.__build(number)\n", 94 | "\n", 95 | " @classmethod\n", 96 | " def build_checking(cls, number):\n", 97 | " return cls.__build(number, \"checking\")" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 2, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "name": "stdout", 107 | "output_type": "stream", 108 | "text": [ 109 | "Invalid account number: invalid literal for int() with base 10: 'a'\n" 110 | ] 111 | } 112 | ], 113 | "source": [ 114 | "cc1 = Account(\"a\", \"Leonardo Bezerra\", \"savings\", 0.01)" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": 3, 120 | "metadata": {}, 121 | "outputs": [ 122 | { 123 | "name": "stdout", 124 | "output_type": "stream", 125 | "text": [ 126 | "Invalid account number: account numbers should be non-negative\n" 127 | ] 128 | } 129 | ], 130 | "source": [ 131 | "cc1 = Account(-1, \"Leonardo Bezerra\", \"savings\", 0.01)" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 4, 137 | "metadata": {}, 138 | "outputs": [ 139 | { 140 | "name": "stdout", 141 | "output_type": "stream", 142 | "text": [ 143 | "Invalid account type: valid options are: checking, savings\n" 144 | ] 145 | } 146 | ], 147 | "source": [ 148 | "cc1 = Account(1, \"Leonardo Bezerra\", \"saving\", 0.01)" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": 5, 154 | "metadata": {}, 155 | "outputs": [ 156 | { 157 | "name": "stdout", 158 | "output_type": "stream", 159 | "text": [ 160 | "Invalid account balance: could not convert string to float: 'a'\n" 161 | ] 162 | } 163 | ], 164 | "source": [ 165 | "cc1 = Account(1, \"Leonardo Bezerra\", \"savings\", \"a\")" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": 6, 171 | "metadata": {}, 172 | "outputs": [], 173 | "source": [ 174 | "poupança1 = Account(1, \"Leonardo Bezerra\", \"savings\", 0.01)" 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": 7, 180 | "metadata": {}, 181 | "outputs": [ 182 | { 183 | "name": "stdout", 184 | "output_type": "stream", 185 | "text": [ 186 | "1\tLeonardo Bezerra\tPoupança\t0.01\n" 187 | ] 188 | } 189 | ], 190 | "source": [ 191 | "print(poupança1)" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": 8, 197 | "metadata": {}, 198 | "outputs": [ 199 | { 200 | "name": "stdout", 201 | "output_type": "stream", 202 | "text": [ 203 | "Titular: Leonardo Bezerra\n", 204 | "Saldo inicial: 0.02\n" 205 | ] 206 | } 207 | ], 208 | "source": [ 209 | "cc1 = Account.build_checking(1)" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": 9, 215 | "metadata": {}, 216 | "outputs": [ 217 | { 218 | "name": "stdout", 219 | "output_type": "stream", 220 | "text": [ 221 | "1\tLeonardo Bezerra\tConta corrente\t0.02\n" 222 | ] 223 | } 224 | ], 225 | "source": [ 226 | "print(cc1)" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": 10, 232 | "metadata": {}, 233 | "outputs": [ 234 | { 235 | "name": "stdout", 236 | "output_type": "stream", 237 | "text": [ 238 | "Titular: Júlia Bezerra\n", 239 | "Saldo inicial: 0.03\n" 240 | ] 241 | } 242 | ], 243 | "source": [ 244 | "poupança2 = Account.build_savings(2)" 245 | ] 246 | }, 247 | { 248 | "cell_type": "code", 249 | "execution_count": 11, 250 | "metadata": {}, 251 | "outputs": [ 252 | { 253 | "name": "stdout", 254 | "output_type": "stream", 255 | "text": [ 256 | "2\tJúlia Bezerra\tPoupança\t0.03\n" 257 | ] 258 | } 259 | ], 260 | "source": [ 261 | "print(poupança2)" 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": 11, 267 | "metadata": {}, 268 | "outputs": [ 269 | { 270 | "ename": "AttributeError", 271 | "evalue": "type object 'Account' has no attribute 'build'", 272 | "output_type": "error", 273 | "traceback": [ 274 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 275 | "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", 276 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mpoupança2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mAccount\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuild\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 277 | "\u001b[0;31mAttributeError\u001b[0m: type object 'Account' has no attribute 'build'" 278 | ] 279 | } 280 | ], 281 | "source": [ 282 | "poupança2 = Account.build(3)" 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": 12, 288 | "metadata": {}, 289 | "outputs": [ 290 | { 291 | "name": "stdout", 292 | "output_type": "stream", 293 | "text": [ 294 | "Titular: Laís Bezerra\n", 295 | "Saldo inicial: 0.04\n" 296 | ] 297 | } 298 | ], 299 | "source": [ 300 | "poupança3 = Account._Account__build(3)" 301 | ] 302 | }, 303 | { 304 | "cell_type": "code", 305 | "execution_count": 13, 306 | "metadata": { 307 | "scrolled": true 308 | }, 309 | "outputs": [ 310 | { 311 | "name": "stdout", 312 | "output_type": "stream", 313 | "text": [ 314 | "3\tLaís Bezerra\tPoupança\t0.04\n" 315 | ] 316 | } 317 | ], 318 | "source": [ 319 | "print(poupança3)" 320 | ] 321 | }, 322 | { 323 | "cell_type": "code", 324 | "execution_count": 14, 325 | "metadata": {}, 326 | "outputs": [ 327 | { 328 | "name": "stdout", 329 | "output_type": "stream", 330 | "text": [ 331 | "Invalid withdraw amount: -200\n" 332 | ] 333 | } 334 | ], 335 | "source": [ 336 | "cc1.withdraw(-200)" 337 | ] 338 | }, 339 | { 340 | "cell_type": "code", 341 | "execution_count": 15, 342 | "metadata": {}, 343 | "outputs": [], 344 | "source": [ 345 | "cc1.withdraw(200)" 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "execution_count": 17, 351 | "metadata": {}, 352 | "outputs": [ 353 | { 354 | "name": "stdout", 355 | "output_type": "stream", 356 | "text": [ 357 | "1\tLeonardo Bezerra\tConta corrente\t-199.98\n" 358 | ] 359 | } 360 | ], 361 | "source": [ 362 | "print(cc1)" 363 | ] 364 | }, 365 | { 366 | "cell_type": "code", 367 | "execution_count": 16, 368 | "metadata": {}, 369 | "outputs": [ 370 | { 371 | "name": "stdout", 372 | "output_type": "stream", 373 | "text": [ 374 | "Invalid deposit amount: -100\n" 375 | ] 376 | } 377 | ], 378 | "source": [ 379 | "cc1.deposit(-100)" 380 | ] 381 | }, 382 | { 383 | "cell_type": "code", 384 | "execution_count": 17, 385 | "metadata": {}, 386 | "outputs": [], 387 | "source": [ 388 | "cc1.deposit(300)" 389 | ] 390 | }, 391 | { 392 | "cell_type": "code", 393 | "execution_count": 18, 394 | "metadata": { 395 | "scrolled": false 396 | }, 397 | "outputs": [ 398 | { 399 | "name": "stdout", 400 | "output_type": "stream", 401 | "text": [ 402 | "1\tLeonardo Bezerra\tConta corrente\t100.02\n" 403 | ] 404 | } 405 | ], 406 | "source": [ 407 | "print(cc1)" 408 | ] 409 | }, 410 | { 411 | "cell_type": "code", 412 | "execution_count": 19, 413 | "metadata": {}, 414 | "outputs": [ 415 | { 416 | "name": "stdout", 417 | "output_type": "stream", 418 | "text": [ 419 | "-200\n", 420 | "300\n" 421 | ] 422 | } 423 | ], 424 | "source": [ 425 | "cc1.statement()" 426 | ] 427 | }, 428 | { 429 | "cell_type": "code", 430 | "execution_count": 20, 431 | "metadata": {}, 432 | "outputs": [], 433 | "source": [ 434 | "class Bank:\n", 435 | " def __init__(self):\n", 436 | " self.accounts = {}\n", 437 | " self.__next_account = 0\n", 438 | "\n", 439 | " @property\n", 440 | " def next_account(self):\n", 441 | " self.__next_account += 1\n", 442 | " return self.__next_account\n", 443 | "\n", 444 | " def create_account(self):\n", 445 | " try:\n", 446 | " mode = int(input(\"Tipo da conta (1 - Poupança, 2 - Conta corrente): \"))\n", 447 | " if mode not in (1,2):\n", 448 | " raise ValueError(\"available options: 1 - Poupança, 2 - Conta corrente\")\n", 449 | " except ValueError as error:\n", 450 | " print(f\"Invalid account type: {error}\")\n", 451 | " else:\n", 452 | " account = Account.build_savings(self.next_account) if mode == 1 else Account.build_checking(self.next_account)\n", 453 | " self.accounts[account.number] = account\n", 454 | " return account.number\n", 455 | " \n", 456 | " def port_account(self, account):\n", 457 | " if account.number in self.accounts:\n", 458 | " print(\"Account number already in use. Creating a new account number.\")\n", 459 | " account.number = self.next_account\n", 460 | " self.accounts[account.number] = account\n", 461 | " return account.number" 462 | ] 463 | }, 464 | { 465 | "cell_type": "code", 466 | "execution_count": 23, 467 | "metadata": {}, 468 | "outputs": [], 469 | "source": [ 470 | "bb = Bank()" 471 | ] 472 | }, 473 | { 474 | "cell_type": "code", 475 | "execution_count": 24, 476 | "metadata": {}, 477 | "outputs": [ 478 | { 479 | "name": "stdout", 480 | "output_type": "stream", 481 | "text": [ 482 | "Tipo da conta (1 - Poupança, 2 - Conta corrente): a\n", 483 | "Invalid account type: invalid literal for int() with base 10: 'a'\n" 484 | ] 485 | } 486 | ], 487 | "source": [ 488 | "bb.create_account()" 489 | ] 490 | }, 491 | { 492 | "cell_type": "code", 493 | "execution_count": 25, 494 | "metadata": {}, 495 | "outputs": [ 496 | { 497 | "name": "stdout", 498 | "output_type": "stream", 499 | "text": [ 500 | "Tipo da conta (1 - Poupança, 2 - Conta corrente): 3\n", 501 | "Invalid account type: available options: 1 - Poupança, 2 - Conta corrente\n" 502 | ] 503 | } 504 | ], 505 | "source": [ 506 | "bb.create_account()" 507 | ] 508 | }, 509 | { 510 | "cell_type": "code", 511 | "execution_count": 26, 512 | "metadata": { 513 | "scrolled": true 514 | }, 515 | "outputs": [ 516 | { 517 | "name": "stdout", 518 | "output_type": "stream", 519 | "text": [ 520 | "Tipo da conta (1 - Poupança, 2 - Conta corrente): 1\n", 521 | "Titular: Leonardo Bezerra\n", 522 | "Saldo inicial: 0.01\n" 523 | ] 524 | } 525 | ], 526 | "source": [ 527 | "number = bb.create_account()" 528 | ] 529 | }, 530 | { 531 | "cell_type": "code", 532 | "execution_count": 27, 533 | "metadata": { 534 | "scrolled": true 535 | }, 536 | "outputs": [ 537 | { 538 | "name": "stdout", 539 | "output_type": "stream", 540 | "text": [ 541 | "1\n" 542 | ] 543 | } 544 | ], 545 | "source": [ 546 | "print(number)" 547 | ] 548 | }, 549 | { 550 | "cell_type": "code", 551 | "execution_count": 28, 552 | "metadata": {}, 553 | "outputs": [ 554 | { 555 | "data": { 556 | "text/plain": [ 557 | "2" 558 | ] 559 | }, 560 | "execution_count": 28, 561 | "metadata": {}, 562 | "output_type": "execute_result" 563 | } 564 | ], 565 | "source": [ 566 | "poupança2.number" 567 | ] 568 | }, 569 | { 570 | "cell_type": "code", 571 | "execution_count": 29, 572 | "metadata": {}, 573 | "outputs": [ 574 | { 575 | "name": "stdout", 576 | "output_type": "stream", 577 | "text": [ 578 | "2\tJúlia Bezerra\tPoupança\t0.03\n" 579 | ] 580 | } 581 | ], 582 | "source": [ 583 | "print(poupança2)" 584 | ] 585 | }, 586 | { 587 | "cell_type": "code", 588 | "execution_count": 30, 589 | "metadata": {}, 590 | "outputs": [], 591 | "source": [ 592 | "number = bb.port_account(poupança2)" 593 | ] 594 | }, 595 | { 596 | "cell_type": "code", 597 | "execution_count": 31, 598 | "metadata": {}, 599 | "outputs": [ 600 | { 601 | "name": "stdout", 602 | "output_type": "stream", 603 | "text": [ 604 | "2\n" 605 | ] 606 | } 607 | ], 608 | "source": [ 609 | "print(number)" 610 | ] 611 | }, 612 | { 613 | "cell_type": "code", 614 | "execution_count": 32, 615 | "metadata": {}, 616 | "outputs": [ 617 | { 618 | "name": "stdout", 619 | "output_type": "stream", 620 | "text": [ 621 | "1\tLeonardo Bezerra\tConta corrente\t100.02\n" 622 | ] 623 | } 624 | ], 625 | "source": [ 626 | "print(cc1)" 627 | ] 628 | }, 629 | { 630 | "cell_type": "code", 631 | "execution_count": 33, 632 | "metadata": {}, 633 | "outputs": [ 634 | { 635 | "name": "stdout", 636 | "output_type": "stream", 637 | "text": [ 638 | "Account number already in use. Creating a new account number.\n" 639 | ] 640 | } 641 | ], 642 | "source": [ 643 | "number = bb.port_account(cc1)" 644 | ] 645 | }, 646 | { 647 | "cell_type": "code", 648 | "execution_count": 34, 649 | "metadata": {}, 650 | "outputs": [ 651 | { 652 | "name": "stdout", 653 | "output_type": "stream", 654 | "text": [ 655 | "2\n" 656 | ] 657 | } 658 | ], 659 | "source": [ 660 | "print(number)" 661 | ] 662 | }, 663 | { 664 | "cell_type": "code", 665 | "execution_count": null, 666 | "metadata": {}, 667 | "outputs": [], 668 | "source": [] 669 | } 670 | ], 671 | "metadata": { 672 | "kernelspec": { 673 | "display_name": "Python 3", 674 | "language": "python", 675 | "name": "python3" 676 | }, 677 | "language_info": { 678 | "codemirror_mode": { 679 | "name": "ipython", 680 | "version": 3 681 | }, 682 | "file_extension": ".py", 683 | "mimetype": "text/x-python", 684 | "name": "python", 685 | "nbconvert_exporter": "python", 686 | "pygments_lexer": "ipython3", 687 | "version": "3.7.0" 688 | } 689 | }, 690 | "nbformat": 4, 691 | "nbformat_minor": 2 692 | } 693 | -------------------------------------------------------------------------------- /alunos/functors01.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "Functors.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [], 9 | "collapsed_sections": [] 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "metadata": { 19 | "id": "We8BP5og4khG", 20 | "colab_type": "text" 21 | }, 22 | "cell_type": "markdown", 23 | "source": [ 24 | "# Functors" 25 | ] 26 | }, 27 | { 28 | "metadata": { 29 | "id": "MptbZjq94sPD", 30 | "colab_type": "text" 31 | }, 32 | "cell_type": "markdown", 33 | "source": [ 34 | "Este notebook é uma adaptação do post [Functors and their use in Python](https://www.geeksforgeeks.org/functors-use-python/), do portal Geek for Geeks: a computer science portal for geeks." 35 | ] 36 | }, 37 | { 38 | "metadata": { 39 | "id": "IaxjG8b6DxxS", 40 | "colab_type": "text" 41 | }, 42 | "cell_type": "markdown", 43 | "source": [ 44 | "## Definição" 45 | ] 46 | }, 47 | { 48 | "metadata": { 49 | "id": "bQGsecWqD1BW", 50 | "colab_type": "text" 51 | }, 52 | "cell_type": "markdown", 53 | "source": [ 54 | "Functors são objetos que podem ser tratados como se fossem uma função." 55 | ] 56 | }, 57 | { 58 | "metadata": { 59 | "id": "sLC9Huzc7faD", 60 | "colab_type": "text" 61 | }, 62 | "cell_type": "markdown", 63 | "source": [ 64 | "## Usabilidade" 65 | ] 66 | }, 67 | { 68 | "metadata": { 69 | "id": "gSj614By9iWB", 70 | "colab_type": "text" 71 | }, 72 | "cell_type": "markdown", 73 | "source": [ 74 | "* Functors são utilizados quando se deseja ocultar ou abstrair a implementação real. Por exemplo, quando você quer chamar diferentes funções dependendo da entrada do usuário, mas você não quer que ele faça chamadas explícitas para essas funções. Essa é uma situação ideal onde functors podem ajudar.\n", 75 | "\n", 76 | "* Nessa situação, podemos usar um functor que internamente chama a função mais adequada, dependendo do tipo de entrada.\n", 77 | "\n", 78 | "* E, caso houver algum problema de implementação das funções, então basta alterar o código principal, sem precisar que o código feito para o usuário sofra alterações. Assim, functors ajuda na manuntenção, desacoplamento e extensibilidade do código.\n", 79 | "\n" 80 | ] 81 | }, 82 | { 83 | "metadata": { 84 | "id": "7FEyrQmY7_0b", 85 | "colab_type": "text" 86 | }, 87 | "cell_type": "markdown", 88 | "source": [ 89 | "## Código sem functors" 90 | ] 91 | }, 92 | { 93 | "metadata": { 94 | "id": "sFmKzNiWD6Uj", 95 | "colab_type": "text" 96 | }, 97 | "cell_type": "markdown", 98 | "source": [ 99 | "Para entender como utilizar functors, vamos apresentar primeiramente um código que não usa functors e mostrar os problemas que acontessem nessa implementação. \n", 100 | "\n", 101 | "Para isso, vamos trabalhar no seguinte problema: queremos chamar diferentes métodos de ordenação de acordo com o tipo de entrada. Se a entrada for do tipo int então chame a função Mergesort, se a entrada for do tipo float então ordene com a função Heapsort, caso contrário chame a função Quicksort." 102 | ] 103 | }, 104 | { 105 | "metadata": { 106 | "id": "L0a4Ejcu8IMH", 107 | "colab_type": "code", 108 | "colab": {} 109 | }, 110 | "cell_type": "code", 111 | "source": [ 112 | "class UmaClasse: \n", 113 | " def FacaAlgumaCoisa(self, x): \n", 114 | " primeiro = x[0] \n", 115 | " if type(primeiro) is int : \n", 116 | " return self.__MergeSort(x) \n", 117 | " if type(primeiro) is float : \n", 118 | " return self.__HeapSort(x) \n", 119 | " else : \n", 120 | " return self.__QuickSort(x)\n", 121 | " \n", 122 | " def __MergeSort(self, a): \n", 123 | " print(\"Os dados foram ordenados pelo Mergesort\")\n", 124 | " return a \n", 125 | " def __HeapSort(self, b): \n", 126 | " print(\"Os dados foram ordenados pelo Heapsort\")\n", 127 | " return b \n", 128 | " def __QuickSort(self, c): \n", 129 | " print(\"Os dados foram ordenados pelo Quicksort\")\n", 130 | " return c " 131 | ], 132 | "execution_count": 0, 133 | "outputs": [] 134 | }, 135 | { 136 | "metadata": { 137 | "id": "cOUS1WglQu5l", 138 | "colab_type": "code", 139 | "colab": { 140 | "base_uri": "https://localhost:8080/", 141 | "height": 52 142 | }, 143 | "outputId": "c94b1ba6-4138-46a9-c33e-a71ebd8e3852" 144 | }, 145 | "cell_type": "code", 146 | "source": [ 147 | "umObjeto = UmaClasse() \n", 148 | "print(umObjeto.FacaAlgumaCoisa([1,2,3]))" 149 | ], 150 | "execution_count": 14, 151 | "outputs": [ 152 | { 153 | "output_type": "stream", 154 | "text": [ 155 | "Os dados foram ordenados pelo Mergesort\n", 156 | "[1, 2, 3]\n" 157 | ], 158 | "name": "stdout" 159 | } 160 | ] 161 | }, 162 | { 163 | "metadata": { 164 | "id": "IwubTkSNSt-3", 165 | "colab_type": "text" 166 | }, 167 | "cell_type": "markdown", 168 | "source": [ 169 | "* **Obs:** Note que o usuário precisa saber as condições para chamar uma estratégia de ordenação diferente. Dessa forma, o código se torna fortemente acoplado." 170 | ] 171 | }, 172 | { 173 | "metadata": { 174 | "id": "EURCi0zo8T1G", 175 | "colab_type": "text" 176 | }, 177 | "cell_type": "markdown", 178 | "source": [ 179 | "## Problemas dessa abordagem" 180 | ] 181 | }, 182 | { 183 | "metadata": { 184 | "id": "xW5MksrX8jGL", 185 | "colab_type": "text" 186 | }, 187 | "cell_type": "markdown", 188 | "source": [ 189 | "1. A implementação interna precisa ser escondida do código utilizado pelo usuário, i.e, a abstração deve ser mantida.\n", 190 | "\n", 191 | "2. Cada classe deve ser responsável por uma única funcionalidade.\n", 192 | "\n", 193 | "3. O código está muito acoplado." 194 | ] 195 | }, 196 | { 197 | "metadata": { 198 | "id": "ku6pWQbu8uvT", 199 | "colab_type": "text" 200 | }, 201 | "cell_type": "markdown", 202 | "source": [ 203 | "## Solução com functors" 204 | ] 205 | }, 206 | { 207 | "metadata": { 208 | "id": "mrRNuuEXVezp", 209 | "colab_type": "text" 210 | }, 211 | "cell_type": "markdown", 212 | "source": [ 213 | "Vamos resolver o mesmo problema utilizando functors." 214 | ] 215 | }, 216 | { 217 | "metadata": { 218 | "id": "mbTfMZEt8t8X", 219 | "colab_type": "code", 220 | "colab": {} 221 | }, 222 | "cell_type": "code", 223 | "source": [ 224 | "class Functor: \n", 225 | " def __init__(self, n=10): \n", 226 | " self.n = n \n", 227 | " \n", 228 | " def __call__(self, x) : \n", 229 | " primeiro = x[0] \n", 230 | " if type(primeiro) is int: \n", 231 | " return self. __MergeSort(x) \n", 232 | " if type(primeiro) is float: \n", 233 | " return self. __HeapSort(x) \n", 234 | " else : \n", 235 | " return self.__QuickSort(x) \n", 236 | " \n", 237 | " def __MergeSort(self,a): \n", 238 | " print(\"Os dados foram ordenados pelo Mergesort\")\n", 239 | " return a \n", 240 | " def __HeapSort(self,b): \n", 241 | " print(\"Os dados foram ordenados pelo Heapsort\")\n", 242 | " return b \n", 243 | " def __QuickSort(self,c): \n", 244 | " print(\"Os dados foram ordenados pelo Quicksort\")\n", 245 | " return c " 246 | ], 247 | "execution_count": 0, 248 | "outputs": [] 249 | }, 250 | { 251 | "metadata": { 252 | "id": "SGpzQ7AaXzvw", 253 | "colab_type": "text" 254 | }, 255 | "cell_type": "markdown", 256 | "source": [ 257 | "Agora, vamos criar a classe que vai chamar as funções acima. Sem o functor, a classe precisaria saber, com base no tipo de entrada, qual função específica deve ser chamada. " 258 | ] 259 | }, 260 | { 261 | "metadata": { 262 | "id": "C3uaQY9hVt9M", 263 | "colab_type": "code", 264 | "colab": {} 265 | }, 266 | "cell_type": "code", 267 | "source": [ 268 | "class UmaClasse: \n", 269 | " def __init__(self): \n", 270 | " self.ordena = Functor() \n", 271 | " \n", 272 | " def FacaAlgumaCoisa(self,x): \n", 273 | " return self.ordena(x) " 274 | ], 275 | "execution_count": 0, 276 | "outputs": [] 277 | }, 278 | { 279 | "metadata": { 280 | "id": "OBozQbUpZyK9", 281 | "colab_type": "text" 282 | }, 283 | "cell_type": "markdown", 284 | "source": [ 285 | "Note que a classe acima simplesmente chama a função e não precisa se preocupar qual ordenação é usada. Ele só sabe que a saída ordenada será o resultado dessa chamada." 286 | ] 287 | }, 288 | { 289 | "metadata": { 290 | "id": "sjetRdoNVwoG", 291 | "colab_type": "code", 292 | "colab": { 293 | "base_uri": "https://localhost:8080/", 294 | "height": 52 295 | }, 296 | "outputId": "574a891b-9ffb-41d3-fafd-d7f654117ae5" 297 | }, 298 | "cell_type": "code", 299 | "source": [ 300 | "umObjeto = UmaClasse() \n", 301 | "print(umObjeto.FacaAlgumaCoisa([5,4,6])) # Mergesort" 302 | ], 303 | "execution_count": 17, 304 | "outputs": [ 305 | { 306 | "output_type": "stream", 307 | "text": [ 308 | "Os dados foram ordenados pelo Mergesort\n", 309 | "[5, 4, 6]\n" 310 | ], 311 | "name": "stdout" 312 | } 313 | ] 314 | }, 315 | { 316 | "metadata": { 317 | "id": "9Fr5ENLablEA", 318 | "colab_type": "code", 319 | "colab": { 320 | "base_uri": "https://localhost:8080/", 321 | "height": 52 322 | }, 323 | "outputId": "28e7a58c-9112-4a48-8fd4-db5d4a1e733e" 324 | }, 325 | "cell_type": "code", 326 | "source": [ 327 | "print(umObjeto.FacaAlgumaCoisa([2.23,3.45,5.65])) # Heapsort" 328 | ], 329 | "execution_count": 18, 330 | "outputs": [ 331 | { 332 | "output_type": "stream", 333 | "text": [ 334 | "Os dados foram ordenados pelo Heapsort\n", 335 | "[2.23, 3.45, 5.65]\n" 336 | ], 337 | "name": "stdout" 338 | } 339 | ] 340 | }, 341 | { 342 | "metadata": { 343 | "id": "JaazJR5mbnpA", 344 | "colab_type": "code", 345 | "colab": { 346 | "base_uri": "https://localhost:8080/", 347 | "height": 52 348 | }, 349 | "outputId": "1010893f-2693-412e-e2ad-b5a7e9554a59" 350 | }, 351 | "cell_type": "code", 352 | "source": [ 353 | "print(umObjeto.FacaAlgumaCoisa(['a','s','b','q'])) # Quicksort " 354 | ], 355 | "execution_count": 19, 356 | "outputs": [ 357 | { 358 | "output_type": "stream", 359 | "text": [ 360 | "Os dados foram ordenados pelo Quicksort\n", 361 | "['a', 's', 'b', 'q']\n" 362 | ], 363 | "name": "stdout" 364 | } 365 | ] 366 | }, 367 | { 368 | "metadata": { 369 | "id": "33H4OzBV88ov", 370 | "colab_type": "text" 371 | }, 372 | "cell_type": "markdown", 373 | "source": [ 374 | "A abordagem acima, utilizando functors, facilita a alteração da implementação do código principal sem modificar o código usado pelo usuário. Dessa forma, o usuário pode usar com segurança o functor acima sem se preocupar com o que está por baixo. Assim, o código se torna desacoplado e de fácil extensibilidade e manutenção. " 375 | ] 376 | }, 377 | { 378 | "metadata": { 379 | "id": "zFuqxdl72tzJ", 380 | "colab_type": "text" 381 | }, 382 | "cell_type": "markdown", 383 | "source": [ 384 | "## Outros exemplos" 385 | ] 386 | }, 387 | { 388 | "metadata": { 389 | "id": "kkBbquwHgL5E", 390 | "colab_type": "text" 391 | }, 392 | "cell_type": "markdown", 393 | "source": [ 394 | "### Exemplo 1\n", 395 | "\n", 396 | "**Fonte:** https://www.daniweb.com/programming/software-development/threads/485098/functors-in-python" 397 | ] 398 | }, 399 | { 400 | "metadata": { 401 | "id": "1anv5lMN2wQV", 402 | "colab_type": "code", 403 | "colab": {} 404 | }, 405 | "cell_type": "code", 406 | "source": [ 407 | "class Acumulador:\n", 408 | " def __init__(self, n=0):\n", 409 | " self.n = n\n", 410 | " \n", 411 | " def __call__(self, x):\n", 412 | " self.n += x\n", 413 | " return self.n" 414 | ], 415 | "execution_count": 0, 416 | "outputs": [] 417 | }, 418 | { 419 | "metadata": { 420 | "id": "5l_P0ROa3O8i", 421 | "colab_type": "text" 422 | }, 423 | "cell_type": "markdown", 424 | "source": [ 425 | "* **Obs:** Note que _call_() permite que a classe instaciada seja chamada como uma função" 426 | ] 427 | }, 428 | { 429 | "metadata": { 430 | "id": "p8_zm0bQ3rtL", 431 | "colab_type": "code", 432 | "colab": { 433 | "base_uri": "https://localhost:8080/", 434 | "height": 85 435 | }, 436 | "outputId": "4d345186-2132-4fac-d1d1-13b846415f31" 437 | }, 438 | "cell_type": "code", 439 | "source": [ 440 | "# Criar uma instância e inicializar dado = 4\n", 441 | "ac = Acumulador(4)\n", 442 | "# Lembra 4 e adiciona 5\n", 443 | "print(ac(5)) # 9\n", 444 | "# Lembra 9 e adiciona 2\n", 445 | "print(ac(2)) # 11\n", 446 | "# Lembra 11 e adiciona 9\n", 447 | "print(ac(9)) # 20\n", 448 | "# Lembra 20 e adiciona 10, lembra 30 e adiciona 30\n", 449 | "print(ac(ac(10))) # 60" 450 | ], 451 | "execution_count": 7, 452 | "outputs": [ 453 | { 454 | "output_type": "stream", 455 | "text": [ 456 | "9\n", 457 | "11\n", 458 | "20\n", 459 | "60\n" 460 | ], 461 | "name": "stdout" 462 | } 463 | ] 464 | }, 465 | { 466 | "metadata": { 467 | "id": "ZuJ0SkQVgA1o", 468 | "colab_type": "text" 469 | }, 470 | "cell_type": "markdown", 471 | "source": [ 472 | "### Exemplo 2\n", 473 | "\n", 474 | "**Fonte:** Python Fluente: programação clara, consisa e eficaz, de Luciano Ramalho." 475 | ] 476 | }, 477 | { 478 | "metadata": { 479 | "id": "E_84l-9TWMsB", 480 | "colab_type": "code", 481 | "colab": {} 482 | }, 483 | "cell_type": "code", 484 | "source": [ 485 | "import random\n", 486 | "\n", 487 | "class BingoCage:\n", 488 | " def __init__(self, items):\n", 489 | " self._items = list(items)\n", 490 | " random.shuffle(self._items)\n", 491 | " \n", 492 | " def pick(self):\n", 493 | " try:\n", 494 | " return self._items.pop()\n", 495 | " except:\n", 496 | " raise LookupError('pick from empty BingoCage')\n", 497 | " \n", 498 | " def __call__(self):\n", 499 | " return self.pick()" 500 | ], 501 | "execution_count": 0, 502 | "outputs": [] 503 | }, 504 | { 505 | "metadata": { 506 | "id": "sIYtJzLsXMKt", 507 | "colab_type": "code", 508 | "colab": { 509 | "base_uri": "https://localhost:8080/", 510 | "height": 34 511 | }, 512 | "outputId": "f834e0fd-42d1-4c5b-e947-794b99124012" 513 | }, 514 | "cell_type": "code", 515 | "source": [ 516 | "bingo = BingoCage(range(3))\n", 517 | "bingo.pick()" 518 | ], 519 | "execution_count": 14, 520 | "outputs": [ 521 | { 522 | "output_type": "execute_result", 523 | "data": { 524 | "text/plain": [ 525 | "2" 526 | ] 527 | }, 528 | "metadata": { 529 | "tags": [] 530 | }, 531 | "execution_count": 14 532 | } 533 | ] 534 | }, 535 | { 536 | "metadata": { 537 | "id": "VvcqJaIwXpoh", 538 | "colab_type": "code", 539 | "colab": { 540 | "base_uri": "https://localhost:8080/", 541 | "height": 34 542 | }, 543 | "outputId": "7e9366a0-4cbb-4d2e-b6b3-588a5792079e" 544 | }, 545 | "cell_type": "code", 546 | "source": [ 547 | "bingo()" 548 | ], 549 | "execution_count": 15, 550 | "outputs": [ 551 | { 552 | "output_type": "execute_result", 553 | "data": { 554 | "text/plain": [ 555 | "1" 556 | ] 557 | }, 558 | "metadata": { 559 | "tags": [] 560 | }, 561 | "execution_count": 15 562 | } 563 | ] 564 | }, 565 | { 566 | "metadata": { 567 | "id": "8qdMA94-Xq4p", 568 | "colab_type": "code", 569 | "colab": { 570 | "base_uri": "https://localhost:8080/", 571 | "height": 34 572 | }, 573 | "outputId": "37e2afe0-4c8a-439a-c645-e124be2c4ad1" 574 | }, 575 | "cell_type": "code", 576 | "source": [ 577 | "callable(bingo)" 578 | ], 579 | "execution_count": 16, 580 | "outputs": [ 581 | { 582 | "output_type": "execute_result", 583 | "data": { 584 | "text/plain": [ 585 | "True" 586 | ] 587 | }, 588 | "metadata": { 589 | "tags": [] 590 | }, 591 | "execution_count": 16 592 | } 593 | ] 594 | } 595 | ] 596 | } -------------------------------------------------------------------------------- /oop/examples/address-book.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "class Person:\n", 10 | " def __init__(self, name, email, birthdate):\n", 11 | " self.name = name\n", 12 | " self.email = email\n", 13 | " self.birthdate = birthdate\n", 14 | " \n", 15 | " def __str__(self):\n", 16 | " return \"Nome: {}, Email: {}, Nascimento: {}, Idade: {}\".format(self.name, self.email, self.birthdate, self.age)\n", 17 | " \n", 18 | " @property\n", 19 | " def name(self):\n", 20 | " return self.__name\n", 21 | " \n", 22 | " @name.setter\n", 23 | " def name(self, name):\n", 24 | " from re import search\n", 25 | " if not name or search(r\"\\d\", name):\n", 26 | " print(\"Invalid name: name is either empty or contains digits\")\n", 27 | " else:\n", 28 | " self.__name = name\n", 29 | " \n", 30 | " @property\n", 31 | " def email(self):\n", 32 | " return self.__email\n", 33 | " \n", 34 | " @email.setter\n", 35 | " def email(self, email):\n", 36 | " from re import match\n", 37 | " if not email or not match(r\"[^@]+@[^@]+\\.[^@]+\", email):\n", 38 | " print(\"Invalid email address\")\n", 39 | " else:\n", 40 | " self.__email = email\n", 41 | "\n", 42 | " @property\n", 43 | " def birthdate(self):\n", 44 | " return self.__birthdate\n", 45 | " \n", 46 | " @birthdate.setter\n", 47 | " def birthdate(self, birthdate):\n", 48 | " from datetime import datetime\n", 49 | " from re import match\n", 50 | " pattern = r\"^((?:\\d)|(?:[0-2]\\d)|(?:3[01]))/((?:[0]?\\d)|(?:1[0-2]))/(\\d{4})$\"\n", 51 | " if not birthdate or not match(pattern, birthdate):\n", 52 | " print(\"Invalid birthdate\")\n", 53 | " else:\n", 54 | " self.__birthdate = datetime.strptime(birthdate, '%d/%m/%Y').date()\n", 55 | "\n", 56 | " @property\n", 57 | " def age(self):\n", 58 | " from datetime import date, timedelta\n", 59 | " today = date.today()\n", 60 | " return (date.today() - self.birthdate) // timedelta(days=365.2425)\n", 61 | " \n", 62 | " @classmethod\n", 63 | " def build(cls):\n", 64 | " name = input(\"Nome: \")\n", 65 | " email = input(\"Email: \")\n", 66 | " birthdate = input(\"Data de nascimento: \")\n", 67 | " return cls(name, email, birthdate)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 3, 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "maria = Person(\"Maria José\", \"maria@jo.se\", \"29/05/1967\")" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 4, 82 | "metadata": {}, 83 | "outputs": [ 84 | { 85 | "name": "stdout", 86 | "output_type": "stream", 87 | "text": [ 88 | "Nome: Maria José, Email: maria@jo.se, Nascimento: 1967-05-29, Idade: 51\n" 89 | ] 90 | } 91 | ], 92 | "source": [ 93 | "print(maria)" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 5, 99 | "metadata": { 100 | "scrolled": true 101 | }, 102 | "outputs": [ 103 | { 104 | "name": "stdout", 105 | "output_type": "stream", 106 | "text": [ 107 | "Invalid name: name is either empty or contains digits\n", 108 | "Invalid email address\n" 109 | ] 110 | } 111 | ], 112 | "source": [ 113 | "maricota = Person(\"Fim do Mundo 2018\", \"222.333.4445\", \"12/05/1975\")" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": 6, 119 | "metadata": {}, 120 | "outputs": [ 121 | { 122 | "name": "stdout", 123 | "output_type": "stream", 124 | "text": [ 125 | "Invalid email address\n" 126 | ] 127 | } 128 | ], 129 | "source": [ 130 | "caio = Person(\"Caio Caiu\", \"caio@caiu\", \"12/05/1975\")" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 9, 136 | "metadata": { 137 | "scrolled": true 138 | }, 139 | "outputs": [ 140 | { 141 | "ename": "KeyboardInterrupt", 142 | "evalue": "", 143 | "output_type": "error", 144 | "traceback": [ 145 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 146 | "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", 147 | "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/ipykernel/kernelbase.py\u001b[0m in \u001b[0;36m_input_request\u001b[0;34m(self, prompt, ident, parent, password)\u001b[0m\n\u001b[1;32m 877\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 878\u001b[0;31m \u001b[0mident\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mreply\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msession\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrecv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstdin_socket\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 879\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 148 | "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/jupyter_client/session.py\u001b[0m in \u001b[0;36mrecv\u001b[0;34m(self, socket, mode, content, copy)\u001b[0m\n\u001b[1;32m 802\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 803\u001b[0;31m \u001b[0mmsg_list\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msocket\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrecv_multipart\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 804\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mzmq\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mZMQError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 149 | "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/zmq/sugar/socket.py\u001b[0m in \u001b[0;36mrecv_multipart\u001b[0;34m(self, flags, copy, track)\u001b[0m\n\u001b[1;32m 466\u001b[0m \"\"\"\n\u001b[0;32m--> 467\u001b[0;31m \u001b[0mparts\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrecv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mflags\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtrack\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mtrack\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 468\u001b[0m \u001b[0;31m# have first part already, only loop while more to receive\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 150 | "\u001b[0;32mzmq/backend/cython/socket.pyx\u001b[0m in \u001b[0;36mzmq.backend.cython.socket.Socket.recv\u001b[0;34m()\u001b[0m\n", 151 | "\u001b[0;32mzmq/backend/cython/socket.pyx\u001b[0m in \u001b[0;36mzmq.backend.cython.socket.Socket.recv\u001b[0;34m()\u001b[0m\n", 152 | "\u001b[0;32mzmq/backend/cython/socket.pyx\u001b[0m in \u001b[0;36mzmq.backend.cython.socket._recv_copy\u001b[0;34m()\u001b[0m\n", 153 | "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/zmq/backend/cython/checkrc.pxd\u001b[0m in \u001b[0;36mzmq.backend.cython.checkrc._check_rc\u001b[0;34m()\u001b[0m\n", 154 | "\u001b[0;31mKeyboardInterrupt\u001b[0m: ", 155 | "\nDuring handling of the above exception, another exception occurred:\n", 156 | "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", 157 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mjoao\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mPerson\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuild\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 158 | "\u001b[0;32m\u001b[0m in \u001b[0;36mbuild\u001b[0;34m(cls)\u001b[0m\n\u001b[1;32m 54\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mclassmethod\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 55\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mbuild\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcls\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 56\u001b[0;31m \u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Nome: \"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 57\u001b[0m \u001b[0memail\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Email: \"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 58\u001b[0m \u001b[0mbirthdate\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Data de nascimento: \"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 159 | "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/ipykernel/kernelbase.py\u001b[0m in \u001b[0;36mraw_input\u001b[0;34m(self, prompt)\u001b[0m\n\u001b[1;32m 851\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_parent_ident\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 852\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_parent_header\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 853\u001b[0;31m \u001b[0mpassword\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 854\u001b[0m )\n\u001b[1;32m 855\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", 160 | "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/ipykernel/kernelbase.py\u001b[0m in \u001b[0;36m_input_request\u001b[0;34m(self, prompt, ident, parent, password)\u001b[0m\n\u001b[1;32m 881\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 882\u001b[0m \u001b[0;31m# re-raise KeyboardInterrupt, to truncate traceback\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 883\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mKeyboardInterrupt\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 884\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 885\u001b[0m \u001b[0;32mbreak\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 161 | "\u001b[0;31mKeyboardInterrupt\u001b[0m: " 162 | ] 163 | } 164 | ], 165 | "source": [ 166 | "joao = Person.build()" 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": 8, 172 | "metadata": {}, 173 | "outputs": [ 174 | { 175 | "name": "stdout", 176 | "output_type": "stream", 177 | "text": [ 178 | "Nome: João Maria, Email: joao@mar.ia, Nascimento: 1976-09-25, Idade: 42\n" 179 | ] 180 | } 181 | ], 182 | "source": [ 183 | "print(joao)" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": 11, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [ 192 | "class AddressBook:\n", 193 | " def __init__(self, contacts=[]):\n", 194 | " from copy import deepcopy\n", 195 | " self.contacts = {contact.name: deepcopy(contact) \n", 196 | " for contact in contacts}\n", 197 | " \n", 198 | " def __str__(self):\n", 199 | " return \"\\n\".join(map(str,self.contacts.values()))\n", 200 | " \n", 201 | " def add(self, contact):\n", 202 | " from copy import deepcopy\n", 203 | " if contact.name in self.contacts:\n", 204 | " print(\"Contact already in address book\")\n", 205 | " else:\n", 206 | " self.contacts[contact.name] = deepcopy(contact)\n", 207 | " \n", 208 | " def find(self, contact):\n", 209 | " try:\n", 210 | " return self.contacts[contact.name]\n", 211 | " except KeyError as error:\n", 212 | " print(f\"Contact not in address book: {contact.name}\")\n", 213 | " \n", 214 | " def update(self, key, contact):\n", 215 | " if key not in self.contacts:\n", 216 | " print(f\"Contact not in address book: {contact.name}\")\n", 217 | " else:\n", 218 | " if key != contact.name:\n", 219 | " del self.contacts[key]\n", 220 | " self.contacts[contact.name] = contact\n", 221 | " \n", 222 | " def remove(self, contact):\n", 223 | " try:\n", 224 | " del self.contacts[contact.name]\n", 225 | " except KeyError as error:\n", 226 | " print(f\"Contact not in address book: {contact.name}\")" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": 12, 232 | "metadata": {}, 233 | "outputs": [ 234 | { 235 | "name": "stdout", 236 | "output_type": "stream", 237 | "text": [ 238 | "Nome: João Maria, Email: joao@mar.ia, Nascimento: 1976-09-25, Idade: 42\n" 239 | ] 240 | } 241 | ], 242 | "source": [ 243 | "agenda = AddressBook([joao])\n", 244 | "print(agenda)" 245 | ] 246 | }, 247 | { 248 | "cell_type": "code", 249 | "execution_count": 13, 250 | "metadata": {}, 251 | "outputs": [], 252 | "source": [ 253 | "agenda.add(maria)" 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": 14, 259 | "metadata": { 260 | "scrolled": true 261 | }, 262 | "outputs": [ 263 | { 264 | "name": "stdout", 265 | "output_type": "stream", 266 | "text": [ 267 | "Nome: João Maria, Email: joao@mar.ia, Nascimento: 1976-09-25, Idade: 42\n", 268 | "Nome: Maria José, Email: maria@jo.se, Nascimento: 1967-05-29, Idade: 51\n" 269 | ] 270 | } 271 | ], 272 | "source": [ 273 | "print(agenda)" 274 | ] 275 | }, 276 | { 277 | "cell_type": "code", 278 | "execution_count": 15, 279 | "metadata": {}, 280 | "outputs": [], 281 | "source": [ 282 | "maria.name = \"Maria Jose\"" 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": 13, 288 | "metadata": {}, 289 | "outputs": [ 290 | { 291 | "ename": "TypeError", 292 | "evalue": "update() missing 1 required positional argument: 'contact'", 293 | "output_type": "error", 294 | "traceback": [ 295 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 296 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 297 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0magenda\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmaria\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 298 | "\u001b[0;31mTypeError\u001b[0m: update() missing 1 required positional argument: 'contact'" 299 | ] 300 | } 301 | ], 302 | "source": [ 303 | "agenda.update(maria)" 304 | ] 305 | }, 306 | { 307 | "cell_type": "code", 308 | "execution_count": 16, 309 | "metadata": {}, 310 | "outputs": [ 311 | { 312 | "name": "stdout", 313 | "output_type": "stream", 314 | "text": [ 315 | "Contact not in address book: Maria Jose\n" 316 | ] 317 | } 318 | ], 319 | "source": [ 320 | "agenda.update(maria.name, maria)" 321 | ] 322 | }, 323 | { 324 | "cell_type": "code", 325 | "execution_count": 17, 326 | "metadata": {}, 327 | "outputs": [], 328 | "source": [ 329 | "agenda.update(\"Maria José\", maria)" 330 | ] 331 | }, 332 | { 333 | "cell_type": "code", 334 | "execution_count": 18, 335 | "metadata": { 336 | "scrolled": false 337 | }, 338 | "outputs": [ 339 | { 340 | "name": "stdout", 341 | "output_type": "stream", 342 | "text": [ 343 | "Nome: João Maria, Email: joao@mar.ia, Nascimento: 1976-09-25, Idade: 42\n", 344 | "Nome: Maria Jose, Email: maria@jo.se, Nascimento: 1967-05-29, Idade: 51\n" 345 | ] 346 | } 347 | ], 348 | "source": [ 349 | "print(agenda)" 350 | ] 351 | }, 352 | { 353 | "cell_type": "code", 354 | "execution_count": 19, 355 | "metadata": {}, 356 | "outputs": [], 357 | "source": [ 358 | "joao.name = \"Joao Maria\"" 359 | ] 360 | }, 361 | { 362 | "cell_type": "code", 363 | "execution_count": 20, 364 | "metadata": {}, 365 | "outputs": [ 366 | { 367 | "name": "stdout", 368 | "output_type": "stream", 369 | "text": [ 370 | "Nome: João Maria, Email: joao@mar.ia, Nascimento: 1976-09-25, Idade: 42\n", 371 | "Nome: Maria Jose, Email: maria@jo.se, Nascimento: 1967-05-29, Idade: 51\n" 372 | ] 373 | } 374 | ], 375 | "source": [ 376 | "print(agenda)" 377 | ] 378 | }, 379 | { 380 | "cell_type": "code", 381 | "execution_count": 21, 382 | "metadata": {}, 383 | "outputs": [], 384 | "source": [ 385 | "agenda2 = AddressBook()" 386 | ] 387 | }, 388 | { 389 | "cell_type": "code", 390 | "execution_count": 22, 391 | "metadata": {}, 392 | "outputs": [], 393 | "source": [ 394 | "agenda2.add(joao)" 395 | ] 396 | }, 397 | { 398 | "cell_type": "code", 399 | "execution_count": 23, 400 | "metadata": {}, 401 | "outputs": [], 402 | "source": [ 403 | "agenda2.add(maria)" 404 | ] 405 | }, 406 | { 407 | "cell_type": "code", 408 | "execution_count": 24, 409 | "metadata": {}, 410 | "outputs": [ 411 | { 412 | "name": "stdout", 413 | "output_type": "stream", 414 | "text": [ 415 | "Nome: Joao Maria, Email: joao@mar.ia, Nascimento: 1976-09-25, Idade: 42\n", 416 | "Nome: Maria Jose, Email: maria@jo.se, Nascimento: 1967-05-29, Idade: 51\n" 417 | ] 418 | } 419 | ], 420 | "source": [ 421 | "print(agenda2)" 422 | ] 423 | }, 424 | { 425 | "cell_type": "code", 426 | "execution_count": 25, 427 | "metadata": {}, 428 | "outputs": [], 429 | "source": [ 430 | "agenda2.remove(maria)" 431 | ] 432 | }, 433 | { 434 | "cell_type": "code", 435 | "execution_count": 26, 436 | "metadata": {}, 437 | "outputs": [ 438 | { 439 | "name": "stdout", 440 | "output_type": "stream", 441 | "text": [ 442 | "Nome: Joao Maria, Email: joao@mar.ia, Nascimento: 1976-09-25, Idade: 42\n" 443 | ] 444 | } 445 | ], 446 | "source": [ 447 | "print(agenda2)" 448 | ] 449 | } 450 | ], 451 | "metadata": { 452 | "kernelspec": { 453 | "display_name": "Python 3", 454 | "language": "python", 455 | "name": "python3" 456 | }, 457 | "language_info": { 458 | "codemirror_mode": { 459 | "name": "ipython", 460 | "version": 3 461 | }, 462 | "file_extension": ".py", 463 | "mimetype": "text/x-python", 464 | "name": "python", 465 | "nbconvert_exporter": "python", 466 | "pygments_lexer": "ipython3", 467 | "version": "3.7.0" 468 | } 469 | }, 470 | "nbformat": 4, 471 | "nbformat_minor": 2 472 | } 473 | -------------------------------------------------------------------------------- /alunos/closures02.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "Closures & Variáveis livres.ipynb", 7 | "version": "0.3.2", 8 | "provenance": [], 9 | "collapsed_sections": [], 10 | "toc_visible": true 11 | }, 12 | "kernelspec": { 13 | "name": "python3", 14 | "display_name": "Python 3" 15 | } 16 | }, 17 | "cells": [ 18 | { 19 | "metadata": { 20 | "id": "BDwgn31wTcJB", 21 | "colab_type": "text" 22 | }, 23 | "cell_type": "markdown", 24 | "source": [ 25 | "# Closures\n", 26 | "## Definição\n", 27 | "Antes de definir Closure, é necessário revisar o conceito de `nested function` \n", 28 | "### `nested function`\n", 29 | "Uma `nested function` ou uma função aninhada ocorre quando definimos uma função dentro de outra. Ex: \n", 30 | "```python\n", 31 | "def funcao_externa(var):\n", 32 | " # Corpo da funcao externa\n", 33 | " def funcao_interna():\n", 34 | " # Corpo da funcao interna\n", 35 | " print(var)\n", 36 | " \n", 37 | " funcao_interna()\n", 38 | "```\n", 39 | "Nesse exemplo, definimos uma função interna dentro de uma externa. A função externa possui um parâmetro e em seu final, chama a função interna que foi declarada em seu escopo (função aninhada). \n", 40 | "Como o exemplo está agora, não conseguimos modificar dentro da função interna os valores da função externa. Para fazer isso, devemos declarar a variável que queremos modificar como `nonlocal` e então seguir com a modificação. Quando fazemos isso, o valor da variável no escopo externo também é modificado. Ex: \n", 41 | "```python\n", 42 | "def funcao_externa(var):\n", 43 | " # Corpo da funcao externa\n", 44 | " def funcao_interna():\n", 45 | " # Corpo da funcao interna\n", 46 | " nonlocal var\n", 47 | " var += \" modificada na funcao interna\"\n", 48 | " print(var + \" : sendo impresso na funcao interna\")\n", 49 | " \n", 50 | " print(var + \" : sendo impresso na funcao externa antes da chamada da interna\")\n", 51 | " funcao_interna()\n", 52 | " print(var + \" : sendo impresso na funcao externa apos a chamada da interna\")\n", 53 | " \n", 54 | "funcao_externa(\"msg\")\n", 55 | "```\n", 56 | "### Closure\n", 57 | "Uma Closure é uma função objeto (uma função interna) que \"lembra\" valores de um escopo exterior (da função externa) mesmo se eles não estiverem presentes na memória. É como se os valores fossem anexados ao código e pudessem ser acessados mesmo após o final da função externa. Ex:\n", 58 | "```python\n", 59 | "def funcao_externa(var):\n", 60 | " # Corpo da funcao externa\n", 61 | " def funcao_interna():\n", 62 | " # Corpo da funcao interna\n", 63 | " print(var)\n", 64 | " \n", 65 | " return funcao_interna\n", 66 | "\n", 67 | "func = funcao_externa(\"oi\")\n", 68 | "func()\n", 69 | "```\n", 70 | "\n", 71 | "## Por que usar?\n", 72 | "Closures podem evitar o uso de valores globais e fornecem uma forma de ocultação de valores que pode ser interessante dado o contexto. Ex: \n", 73 | "```python\n", 74 | "def somar_com(x):\n", 75 | " def soma(y):\n", 76 | " return x+y\n", 77 | " return soma\n", 78 | "\n", 79 | "soma_3 = somar_com(3)\n", 80 | "soma_5 = somar_com(5)\n", 81 | "soma_3(soma_5(1))\n", 82 | "```" 83 | ] 84 | }, 85 | { 86 | "metadata": { 87 | "id": "NyNGXyDVU5bD", 88 | "colab_type": "code", 89 | "outputId": "94d3ab14-da3a-4ecf-b90c-8af676a91669", 90 | "colab": { 91 | "base_uri": "https://localhost:8080/", 92 | "height": 34 93 | } 94 | }, 95 | "cell_type": "code", 96 | "source": [ 97 | "# Primeiro código\n", 98 | "def funcao_externa(var):\n", 99 | " # Corpo da funcao externa\n", 100 | " def funcao_interna():\n", 101 | " # Corpo da funcao interna\n", 102 | " print(var)\n", 103 | "\n", 104 | " funcao_interna()\n", 105 | " \n", 106 | "funcao_externa(\"oi\")" 107 | ], 108 | "execution_count": 0, 109 | "outputs": [ 110 | { 111 | "output_type": "stream", 112 | "text": [ 113 | "oi\n" 114 | ], 115 | "name": "stdout" 116 | } 117 | ] 118 | }, 119 | { 120 | "metadata": { 121 | "id": "-QYRofD-bp1j", 122 | "colab_type": "code", 123 | "outputId": "79489c34-37ca-4378-f013-a0110efce541", 124 | "colab": { 125 | "base_uri": "https://localhost:8080/", 126 | "height": 88 127 | } 128 | }, 129 | "cell_type": "code", 130 | "source": [ 131 | "# Segundo código\n", 132 | "def funcao_externa(var):\n", 133 | " # Corpo da funcao externa\n", 134 | " def funcao_interna():\n", 135 | " # Corpo da funcao interna\n", 136 | " nonlocal var\n", 137 | " var += \" modificada na funcao interna\"\n", 138 | " print(var + \" : sendo impresso na funcao interna\")\n", 139 | "\n", 140 | " print(var + \" : sendo impresso na funcao externa antes da chamada da interna\")\n", 141 | " funcao_interna()\n", 142 | " print(var + \" : sendo impresso na funcao externa apos a chamada da interna\")\n", 143 | "\n", 144 | "funcao_externa(\"msg\")" 145 | ], 146 | "execution_count": 0, 147 | "outputs": [ 148 | { 149 | "output_type": "stream", 150 | "text": [ 151 | "msg : sendo impresso na funcao externa antes da chamada da interna\n", 152 | "msg modificada na funcao interna : sendo impresso na funcao interna\n", 153 | "msg modificada na funcao interna : sendo impresso na funcao externa apos a chamada da interna\n" 154 | ], 155 | "name": "stdout" 156 | } 157 | ] 158 | }, 159 | { 160 | "metadata": { 161 | "id": "x2riGyENbt3l", 162 | "colab_type": "code", 163 | "outputId": "29088247-55bf-44ee-de2e-6b4bfc17594b", 164 | "colab": { 165 | "base_uri": "https://localhost:8080/", 166 | "height": 35 167 | } 168 | }, 169 | "cell_type": "code", 170 | "source": [ 171 | "# Terceiro código\n", 172 | "def funcao_externa(var):\n", 173 | " # Corpo da funcao externa\n", 174 | " def funcao_interna():\n", 175 | " # Corpo da funcao interna\n", 176 | " print(var)\n", 177 | "\n", 178 | " return funcao_interna\n", 179 | "\n", 180 | "func = funcao_externa(\"oi\")\n", 181 | "func()" 182 | ], 183 | "execution_count": 0, 184 | "outputs": [ 185 | { 186 | "output_type": "stream", 187 | "text": [ 188 | "oi\n" 189 | ], 190 | "name": "stdout" 191 | } 192 | ] 193 | }, 194 | { 195 | "metadata": { 196 | "id": "nUWy-aUHdb4X", 197 | "colab_type": "code", 198 | "outputId": "00781ead-0cf8-40d4-d183-68219d6ccd63", 199 | "colab": { 200 | "base_uri": "https://localhost:8080/", 201 | "height": 67 202 | } 203 | }, 204 | "cell_type": "code", 205 | "source": [ 206 | "from random import randint\n", 207 | "\n", 208 | "# Quarto código\n", 209 | "def somar_com(x):\n", 210 | " def soma(y):\n", 211 | " return x+y\n", 212 | " return soma\n", 213 | "\n", 214 | "soma_3 = somar_com(3)\n", 215 | "soma_5 = somar_com(5)\n", 216 | "print(soma_3(soma_5(1)))\n", 217 | "\n", 218 | "somar_com_rand = somar_com(randint(0,10))\n", 219 | "print(somar_com_rand(0))" 220 | ], 221 | "execution_count": 0, 222 | "outputs": [ 223 | { 224 | "output_type": "stream", 225 | "text": [ 226 | "9\n", 227 | "9\n", 228 | "9\n" 229 | ], 230 | "name": "stdout" 231 | } 232 | ] 233 | }, 234 | { 235 | "metadata": { 236 | "id": "GZVUOSPqk6sq", 237 | "colab_type": "code", 238 | "colab": {} 239 | }, 240 | "cell_type": "code", 241 | "source": [ 242 | "" 243 | ], 244 | "execution_count": 0, 245 | "outputs": [] 246 | }, 247 | { 248 | "metadata": { 249 | "id": "tTESc-W9fccD", 250 | "colab_type": "code", 251 | "outputId": "e0c04560-84f2-4afe-e3f2-be439c59153e", 252 | "colab": { 253 | "base_uri": "https://localhost:8080/", 254 | "height": 34 255 | } 256 | }, 257 | "cell_type": "code", 258 | "source": [ 259 | "def somar_com_mais4(x):\n", 260 | " y = 4\n", 261 | " def soma(z):\n", 262 | " return x+y+z\n", 263 | " return soma\n", 264 | "\n", 265 | "soma_3 = somar_com_mais4(3)\n", 266 | "soma_3(1)" 267 | ], 268 | "execution_count": 0, 269 | "outputs": [ 270 | { 271 | "output_type": "execute_result", 272 | "data": { 273 | "text/plain": [ 274 | "8" 275 | ] 276 | }, 277 | "metadata": { 278 | "tags": [] 279 | }, 280 | "execution_count": 24 281 | } 282 | ] 283 | }, 284 | { 285 | "metadata": { 286 | "id": "s3wP8exsfRZ7", 287 | "colab_type": "code", 288 | "outputId": "6c39225c-b096-4e11-a02a-5d78f84ca424", 289 | "colab": { 290 | "base_uri": "https://localhost:8080/", 291 | "height": 35 292 | } 293 | }, 294 | "cell_type": "code", 295 | "source": [ 296 | "def esconder_numero(x):\n", 297 | " def numero_escondido():\n", 298 | " return x\n", 299 | " return numero_escondido\n", 300 | "\n", 301 | "foo = esconder_numero(10)\n", 302 | "\n", 303 | "foo()" 304 | ], 305 | "execution_count": 0, 306 | "outputs": [ 307 | { 308 | "output_type": "execute_result", 309 | "data": { 310 | "text/plain": [ 311 | "10" 312 | ] 313 | }, 314 | "metadata": { 315 | "tags": [] 316 | }, 317 | "execution_count": 8 318 | } 319 | ] 320 | }, 321 | { 322 | "metadata": { 323 | "id": "qWiIzQTlgiZD", 324 | "colab_type": "code", 325 | "outputId": "d44b9ce7-1655-49c4-bd21-9403ef66fd87", 326 | "colab": { 327 | "base_uri": "https://localhost:8080/", 328 | "height": 105 329 | } 330 | }, 331 | "cell_type": "code", 332 | "source": [ 333 | "def foo1(x):\n", 334 | " def foo2(y):\n", 335 | " nonlocal x\n", 336 | " x += [y]\n", 337 | " return x\n", 338 | " return foo2\n", 339 | "\n", 340 | "foo = foo1([])\n", 341 | "del foo1\n", 342 | "\n", 343 | "for _ in range(5):\n", 344 | " print(foo(3))" 345 | ], 346 | "execution_count": 0, 347 | "outputs": [ 348 | { 349 | "output_type": "stream", 350 | "text": [ 351 | "[3]\n", 352 | "[3, 3]\n", 353 | "[3, 3, 3]\n", 354 | "[3, 3, 3, 3]\n", 355 | "[3, 3, 3, 3, 3]\n" 356 | ], 357 | "name": "stdout" 358 | } 359 | ] 360 | }, 361 | { 362 | "metadata": { 363 | "id": "0q93vbyUd0b8", 364 | "colab_type": "text" 365 | }, 366 | "cell_type": "markdown", 367 | "source": [ 368 | "#

Definição de Variável Livre (Docs Python)

\n", 369 | "\n", 370 | "
Se um nome estiver vinculado em um bloco, ele será uma variável local desse bloco, a menos que seja declarado como não local ou global. Se um nome é limitado no nível do módulo, é uma variável global. (As variáveis do bloco de código são locais e globais.) Se uma variável é usada em um código de bloco, mas não é definida lá, é uma variável livre.
\n", 371 | "\n", 372 | "
A resolução de nomes de variáveis livres ocorre em tempo de execução, não em tempo de compilação.
\n", 373 | "\n", 374 | "https://stackoverflow.com/questions/12919278/how-to-define-free-variable-in-python [Dúvida sobre como definir]\n", 375 | "\n", 376 | "http://mathamy.com/python-closures-and-free-variables.html [Closures e Variáveis Livres]\n", 377 | "\n", 378 | "https://docs.python.org/3/reference/executionmodel.html [Modelo de Execução]" 379 | ] 380 | }, 381 | { 382 | "metadata": { 383 | "id": "CLwcp-Z_d-Q8", 384 | "colab_type": "text" 385 | }, 386 | "cell_type": "markdown", 387 | "source": [ 388 | "

Definição Wikipédia

\n", 389 | "\n", 390 | "
Uma variável livre é uma variável referenciada em uma função, que não é nem uma variável local nem um argumento daquela função
" 391 | ] 392 | }, 393 | { 394 | "metadata": { 395 | "id": "jyfGTTvQeBRV", 396 | "colab_type": "text" 397 | }, 398 | "cell_type": "markdown", 399 | "source": [ 400 | "
**locals():** Atualiza e retorna um dicionário que representa a tabela de símbolos local atual. Variáveis livres são retornadas por locals () quando são chamadas em blocos de funções, mas não em blocos de classes.
" 401 | ] 402 | }, 403 | { 404 | "metadata": { 405 | "id": "fAv5laOLeEl1", 406 | "colab_type": "code", 407 | "outputId": "c75a0435-318d-40be-e6c2-1f68a14cb305", 408 | "colab": { 409 | "base_uri": "https://localhost:8080/", 410 | "height": 51 411 | } 412 | }, 413 | "cell_type": "code", 414 | "source": [ 415 | "#Retorno da função com variável global definida!\n", 416 | "x = 0 #x é global\n", 417 | "\n", 418 | "def somefunction(param1):\n", 419 | " x = param1 #x é local\n", 420 | " print(locals())\n", 421 | " return x\n", 422 | "\n", 423 | "somefunction(1)" 424 | ], 425 | "execution_count": 0, 426 | "outputs": [ 427 | { 428 | "output_type": "stream", 429 | "text": [ 430 | "{'x': 1, 'param1': 1}\n" 431 | ], 432 | "name": "stdout" 433 | }, 434 | { 435 | "output_type": "execute_result", 436 | "data": { 437 | "text/plain": [ 438 | "1" 439 | ] 440 | }, 441 | "metadata": { 442 | "tags": [] 443 | }, 444 | "execution_count": 3 445 | } 446 | ] 447 | }, 448 | { 449 | "metadata": { 450 | "id": "FN6gm4RBeHIt", 451 | "colab_type": "code", 452 | "colab": {} 453 | }, 454 | "cell_type": "code", 455 | "source": [ 456 | "#Print em escopo global com variável global definida depois da execução da função!\n", 457 | "x = 0 #x é global\n", 458 | "\n", 459 | "def somefunction(param1):\n", 460 | " x = param1 #x é local\n", 461 | " print(locals())\n", 462 | " return x\n", 463 | "\n", 464 | "somefunction(1)\n", 465 | "\n", 466 | "print(x)" 467 | ], 468 | "execution_count": 0, 469 | "outputs": [] 470 | }, 471 | { 472 | "metadata": { 473 | "id": "doeQAUo1eJBV", 474 | "colab_type": "code", 475 | "colab": {} 476 | }, 477 | "cell_type": "code", 478 | "source": [ 479 | "#Print do escopo global após execução da função usando variável global!\n", 480 | "x = 0 #x é global\n", 481 | "\n", 482 | "def somefunction(param1):\n", 483 | " global x \n", 484 | " x = param1 #x é global\n", 485 | " print(locals())\n", 486 | "\n", 487 | "somefunction(1)\n", 488 | "\n", 489 | "print(x)" 490 | ], 491 | "execution_count": 0, 492 | "outputs": [] 493 | }, 494 | { 495 | "metadata": { 496 | "id": "JggDLEfNeL6t", 497 | "colab_type": "code", 498 | "outputId": "fd2aa1c8-859b-4413-d2fa-5650998a3fce", 499 | "colab": { 500 | "base_uri": "https://localhost:8080/", 501 | "height": 34 502 | } 503 | }, 504 | "cell_type": "code", 505 | "source": [ 506 | "#X é local, global ou livre?...\n", 507 | "def make_contains_function(x):\n", 508 | " \n", 509 | " def contains(s):\n", 510 | " return x in s\n", 511 | " \n", 512 | " return contains\n", 513 | "\n", 514 | "contains_L = make_contains_function(\"L\")\n", 515 | "\n", 516 | "contains_L(\"Leonardo\")" 517 | ], 518 | "execution_count": 0, 519 | "outputs": [ 520 | { 521 | "output_type": "execute_result", 522 | "data": { 523 | "text/plain": [ 524 | "True" 525 | ] 526 | }, 527 | "metadata": { 528 | "tags": [] 529 | }, 530 | "execution_count": 29 531 | } 532 | ] 533 | }, 534 | { 535 | "metadata": { 536 | "id": "Q4I3cWBZeNfE", 537 | "colab_type": "code", 538 | "outputId": "9e65f766-5c50-46f5-ee81-e72072f94a9e", 539 | "colab": { 540 | "base_uri": "https://localhost:8080/", 541 | "height": 34 542 | } 543 | }, 544 | "cell_type": "code", 545 | "source": [ 546 | "contains_L(\"Jefferson\")" 547 | ], 548 | "execution_count": 0, 549 | "outputs": [ 550 | { 551 | "output_type": "execute_result", 552 | "data": { 553 | "text/plain": [ 554 | "False" 555 | ] 556 | }, 557 | "metadata": { 558 | "tags": [] 559 | }, 560 | "execution_count": 30 561 | } 562 | ] 563 | }, 564 | { 565 | "metadata": { 566 | "id": "Nty3EmZTeOD0", 567 | "colab_type": "code", 568 | "outputId": "f0bce3a7-88d8-44c3-c55d-b40d41a2d63c", 569 | "colab": { 570 | "base_uri": "https://localhost:8080/", 571 | "height": 34 572 | } 573 | }, 574 | "cell_type": "code", 575 | "source": [ 576 | "#Qual o tipo?\n", 577 | "contains_L" 578 | ], 579 | "execution_count": 0, 580 | "outputs": [ 581 | { 582 | "output_type": "execute_result", 583 | "data": { 584 | "text/plain": [ 585 | ".contains>" 586 | ] 587 | }, 588 | "metadata": { 589 | "tags": [] 590 | }, 591 | "execution_count": 31 592 | } 593 | ] 594 | }, 595 | { 596 | "metadata": { 597 | "id": "EssiLcIxeQpk", 598 | "colab_type": "code", 599 | "outputId": "24c7887c-81cc-4c4b-83d2-d8b2234f54b3", 600 | "colab": { 601 | "base_uri": "https://localhost:8080/", 602 | "height": 50 603 | } 604 | }, 605 | "cell_type": "code", 606 | "source": [ 607 | "#Print da locals... Estamos roubando?\n", 608 | "def make_contains_function(x):\n", 609 | " def contains(s):\n", 610 | " print(locals())\n", 611 | " return x in s\n", 612 | " return contains\n", 613 | "\n", 614 | "contains_s = make_contains_function('s')\n", 615 | "\n", 616 | "contains_s(\"Big Smoke\")\n", 617 | "print(contains_s.__code__.co_freevars)" 618 | ], 619 | "execution_count": 0, 620 | "outputs": [ 621 | { 622 | "output_type": "stream", 623 | "text": [ 624 | "{'s': 'Big Smoke', 'x': 's'}\n", 625 | "('x',)\n" 626 | ], 627 | "name": "stdout" 628 | } 629 | ] 630 | }, 631 | { 632 | "metadata": { 633 | "id": "s1tTGzoAeSwV", 634 | "colab_type": "text" 635 | }, 636 | "cell_type": "markdown", 637 | "source": [ 638 | "
**locals():** Atualiza e retorna um dicionário que representa a tabela de símbolos local atual. Variáveis livres são retornadas por locals () quando são chamadas em blocos de funções, mas não em blocos de classes.
" 639 | ] 640 | }, 641 | { 642 | "metadata": { 643 | "id": "xM2HOLx8eV0N", 644 | "colab_type": "text" 645 | }, 646 | "cell_type": "markdown", 647 | "source": [ 648 | "# Conclusão" 649 | ] 650 | }, 651 | { 652 | "metadata": { 653 | "id": "vXbx8a2JeZQP", 654 | "colab_type": "text" 655 | }, 656 | "cell_type": "markdown", 657 | "source": [ 658 | "
É por possuir noções como de Enclosure que pode-se haver a existência de variáveis livres em python.
\n", 659 | "
Uma vez que o aninhamento de funções permite o uso de variáveis das funções mais eternas sem serem consideradas locais, determinadas pelo escopo, e nem passadas por parâmetro.
" 660 | ] 661 | } 662 | ] 663 | } -------------------------------------------------------------------------------- /ned/names-and-values-02.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Fatos e mitos sobre referências e objetos em Python" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Este notebook é a segunda parte de uma adaptação do post [\"Facts and myths about Python names and values\"](https://nedbatchelder.com/text/names.html), de Ned Batchelder." 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## A diversidade do Python" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "### Fato: referências podem ser mais que apenas nomes." 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "Todos os exemplos usados até aqui usaram nomes como referências a objetos, mas outras coisas também podem ser referências.\n", 36 | "\n", 37 | "Python tem um leque de estruturas de dados compostas, cada uma armazenando referências a objetos: elementos de uma lista, chaves e valores de um dicionário, atributos de objetos, e por aí vai.\n", 38 | "\n", 39 | "Cada exemplo acima pode ser usado do lado esquerdo de uma operação de associação e todos os detalhes discutos para associação também se aplicam aqui.\n", 40 | "\n", 41 | "Em resumo: **qualquer coisa que possa aparecer do lado esquerdo de uma associação é uma referência** e você pode substituir o **nome** pelo termo **referência** em todos os lugares onde ele aparecia.\n", 42 | "\n", 43 | "No nosso diagrama de listas, eu mostrei números como elementos, mas na verdade cada elemento é uma referência a número. \n", 44 | "\n", 45 | "A ilustração mais apropriada é esta:" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": {}, 58 | "source": [ 59 | "Por simplicidade, vamos continuar usando o estilo de ilustração anterior.\n", 60 | "\n", 61 | "Se você tiver elementos de uma lista se referindo a outros objetos mutáveis, como sub-listas, é importante se lembrar que os elementos da lista são apenas referências a objetos.\n", 62 | "\n", 63 | "Veja mais alguns exemplos de associações. Cada um desses elementos que aparecem do lado esquerdo das operações de associação é uma referência:" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": 1, 69 | "metadata": { 70 | "collapsed": false 71 | }, 72 | "outputs": [ 73 | { 74 | "name": "stdout", 75 | "output_type": "stream", 76 | "text": [ 77 | "{'a': 24}\n" 78 | ] 79 | } 80 | ], 81 | "source": [ 82 | "my_dict = {}\n", 83 | "my_dict[\"a\"] = 24\n", 84 | "print(my_dict)" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": 2, 90 | "metadata": { 91 | "collapsed": false 92 | }, 93 | "outputs": [ 94 | { 95 | "name": "stdout", 96 | "output_type": "stream", 97 | "text": [ 98 | "[25, 2, 3]\n" 99 | ] 100 | } 101 | ], 102 | "source": [ 103 | "my_list = [1, 2, 3]\n", 104 | "my_list[0] = 25\n", 105 | "print(my_list)" 106 | ] 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "metadata": {}, 111 | "source": [ 112 | "Muitas estruturas de Python armazenam objetos, cada um deles através de uma referência.\n", 113 | "\n", 114 | "Todas as regras explicadas aqui sobre nomes se aplicam exatamente da mesma forma a qualquer uma dessas referências.\n", 115 | "\n", 116 | "O coletor de lixo, por exemplo, não conta apenas nomes -- conta qualquer tipo de referência para decidir quando um objeto pode ser liberado.\n", 117 | "\n", 118 | "Note que ```i = x``` faz uma associação do nome **i** com o objeto referenciado por **x**. Já ```i[0] = x``` faz uma associação da referência presente na primeira posição da lista referenciada por **i** com o objeto referenciado por **x**.\n", 119 | "\n", 120 | "É importante entender corretamente o que está sendo associado com o quê. Só porque um nome aparece em alguma parte do lado esquerdo de uma associação, isso não significa que o nome esteja sendo reassociado." 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "metadata": {}, 126 | "source": [ 127 | "### Fato: muitas coisas são associações" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "Assim como muitas coisas podem servir como referências, muitas operações em Python são associações. \n", 135 | "\n", 136 | "Cada uma das linhas a seguir é uma associação com o nome **X**:" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": 3, 142 | "metadata": { 143 | "collapsed": false 144 | }, 145 | "outputs": [ 146 | { 147 | "name": "stdout", 148 | "output_type": "stream", 149 | "text": [ 150 | "4384446088\n", 151 | "4384801544\n", 152 | "4384150672\n", 153 | "4384446088\n", 154 | "4385238184\n" 155 | ] 156 | } 157 | ], 158 | "source": [ 159 | "for X in \"texto\":\n", 160 | " print(id(X))" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 4, 166 | "metadata": { 167 | "collapsed": false 168 | }, 169 | "outputs": [ 170 | { 171 | "data": { 172 | "text/plain": [ 173 | "[4384446088, 4384801544, 4384150672, 4384446088, 4385238184]" 174 | ] 175 | }, 176 | "execution_count": 4, 177 | "metadata": {}, 178 | "output_type": "execute_result" 179 | } 180 | ], 181 | "source": [ 182 | "[id(X) for X in \"texto\"]" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": 5, 188 | "metadata": { 189 | "collapsed": false 190 | }, 191 | "outputs": [ 192 | { 193 | "data": { 194 | "text/plain": [ 195 | "{4384150672, 4384446088, 4384801544, 4385238184}" 196 | ] 197 | }, 198 | "execution_count": 5, 199 | "metadata": {}, 200 | "output_type": "execute_result" 201 | } 202 | ], 203 | "source": [ 204 | "{id(X) for X in \"texto\"}" 205 | ] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": 6, 210 | "metadata": { 211 | "collapsed": false 212 | }, 213 | "outputs": [ 214 | { 215 | "name": "stdout", 216 | "output_type": "stream", 217 | "text": [ 218 | "140214689169640\n" 219 | ] 220 | } 221 | ], 222 | "source": [ 223 | "class X():\n", 224 | " pass\n", 225 | "print(id(X))" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": 7, 231 | "metadata": { 232 | "collapsed": false 233 | }, 234 | "outputs": [ 235 | { 236 | "name": "stdout", 237 | "output_type": "stream", 238 | "text": [ 239 | "4411468656\n" 240 | ] 241 | } 242 | ], 243 | "source": [ 244 | "def X():\n", 245 | " pass\n", 246 | "print(id(X))" 247 | ] 248 | }, 249 | { 250 | "cell_type": "code", 251 | "execution_count": 8, 252 | "metadata": { 253 | "collapsed": false 254 | }, 255 | "outputs": [ 256 | { 257 | "name": "stdout", 258 | "output_type": "stream", 259 | "text": [ 260 | "4383079328\n" 261 | ] 262 | } 263 | ], 264 | "source": [ 265 | "def fn(X): \n", 266 | " print(id(X))\n", 267 | "fn(12)" 268 | ] 269 | }, 270 | { 271 | "cell_type": "code", 272 | "execution_count": 9, 273 | "metadata": { 274 | "collapsed": false 275 | }, 276 | "outputs": [ 277 | { 278 | "name": "stdout", 279 | "output_type": "stream", 280 | "text": [ 281 | "4410248432\n" 282 | ] 283 | } 284 | ], 285 | "source": [ 286 | "with open(\"imgs/ned1.png\") as X:\n", 287 | " print(id(X))" 288 | ] 289 | }, 290 | { 291 | "cell_type": "code", 292 | "execution_count": 10, 293 | "metadata": { 294 | "collapsed": false 295 | }, 296 | "outputs": [ 297 | { 298 | "name": "stdout", 299 | "output_type": "stream", 300 | "text": [ 301 | "4389861240\n" 302 | ] 303 | } 304 | ], 305 | "source": [ 306 | "import random\n", 307 | "print(id(random))" 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": 11, 313 | "metadata": { 314 | "collapsed": false 315 | }, 316 | "outputs": [ 317 | { 318 | "name": "stdout", 319 | "output_type": "stream", 320 | "text": [ 321 | "4389861240\n" 322 | ] 323 | } 324 | ], 325 | "source": [ 326 | "import random as X\n", 327 | "print(id(X))" 328 | ] 329 | }, 330 | { 331 | "cell_type": "code", 332 | "execution_count": 12, 333 | "metadata": { 334 | "collapsed": false 335 | }, 336 | "outputs": [ 337 | { 338 | "name": "stdout", 339 | "output_type": "stream", 340 | "text": [ 341 | "4389391944\n" 342 | ] 343 | } 344 | ], 345 | "source": [ 346 | "from random import randint\n", 347 | "print(id(randint))" 348 | ] 349 | }, 350 | { 351 | "cell_type": "code", 352 | "execution_count": 13, 353 | "metadata": { 354 | "collapsed": false 355 | }, 356 | "outputs": [ 357 | { 358 | "name": "stdout", 359 | "output_type": "stream", 360 | "text": [ 361 | "4389391944\n" 362 | ] 363 | } 364 | ], 365 | "source": [ 366 | "from random import randint as X\n", 367 | "print(id(X))" 368 | ] 369 | }, 370 | { 371 | "cell_type": "code", 372 | "execution_count": 14, 373 | "metadata": { 374 | "collapsed": false 375 | }, 376 | "outputs": [ 377 | { 378 | "name": "stdout", 379 | "output_type": "stream", 380 | "text": [ 381 | "4411991496\n" 382 | ] 383 | } 384 | ], 385 | "source": [ 386 | "try:\n", 387 | " some_dict[\"a\"] = 1\n", 388 | "except NameError as X:\n", 389 | " print(id(X))" 390 | ] 391 | }, 392 | { 393 | "cell_type": "markdown", 394 | "metadata": {}, 395 | "source": [ 396 | "Eu não quero dizer que essas instruções atuam como associações -- eu quero dizer que elas são associações.\n", 397 | "\n", 398 | "Todas elas fazem com o que o nome **X** (ou ```random``` e ```randint```, nos exemplos 23 e 25) se refira a um objeto e tudo o que eu tenho dito sobre associações se aplicam a elas igualmente." 399 | ] 400 | }, 401 | { 402 | "cell_type": "markdown", 403 | "metadata": {}, 404 | "source": [ 405 | "### Fato: Python passa argumentos de função através de associações." 406 | ] 407 | }, 408 | { 409 | "cell_type": "markdown", 410 | "metadata": {}, 411 | "source": [ 412 | "Vamos analisar o caso mais interessante dentre essas associações: chamar um procedimento.\n", 413 | "\n", 414 | "Quando eu defino um procedimento, eu nomeio seus parâmetros:" 415 | ] 416 | }, 417 | { 418 | "cell_type": "code", 419 | "execution_count": 15, 420 | "metadata": { 421 | "collapsed": true 422 | }, 423 | "outputs": [], 424 | "source": [ 425 | "def my_proc(x, y):\n", 426 | " return x+y" 427 | ] 428 | }, 429 | { 430 | "cell_type": "markdown", 431 | "metadata": {}, 432 | "source": [ 433 | "Aqui, **x** e **y** são parâmetros da função referenciada pelo nome ```my_proc``` -- lembre-se que em Python tudo é objeto ou referência, logo um procedimento é um objeto cujo nome é uma referência.\n", 434 | "\n", 435 | "Ao invocar ```my_proc```, eu forneço objetos existentes para serem usados como parâmetros do procedimento. Estes objetos são associados aos nomes definidos para os parâmetros da mesma forma que uma instrução de associação simples faria:" 436 | ] 437 | }, 438 | { 439 | "cell_type": "code", 440 | "execution_count": 16, 441 | "metadata": { 442 | "collapsed": false 443 | }, 444 | "outputs": [ 445 | { 446 | "name": "stdout", 447 | "output_type": "stream", 448 | "text": [ 449 | "17\n" 450 | ] 451 | } 452 | ], 453 | "source": [ 454 | "def my_proc(x, y):\n", 455 | " return x+y\n", 456 | "\n", 457 | "print(my_proc(8, 9))" 458 | ] 459 | }, 460 | { 461 | "cell_type": "markdown", 462 | "metadata": {}, 463 | "source": [ 464 | "Quando ```my_proc``` é invocada, o nome **x** é associado ao objeto **8**, e o nome **y** é associado ao objeto **9**. Esta associação funciona exatamente como as instruções de associação que discutimos. Os nome **x** e **y** são locais ao procedimento, então quando o procedimento retorna, estes nomes desaparecem. No entanto, se os objetos aos quais eles estavam associados estiverem sendo referidos por outros nomes, estes objetos não desaparecerão.\n", 465 | "\n", 466 | "Assim como em qualquer outra associação, objetos mutáveis podem ser passados como parâmetros de procedimentos, e mudanças feitas nesses objetos serão visíveis para todos os seus nomes:" 467 | ] 468 | }, 469 | { 470 | "cell_type": "code", 471 | "execution_count": 1, 472 | "metadata": { 473 | "collapsed": false 474 | }, 475 | "outputs": [ 476 | { 477 | "name": "stdout", 478 | "output_type": "stream", 479 | "text": [ 480 | "[1, 2, 3, 4, 4]\n" 481 | ] 482 | } 483 | ], 484 | "source": [ 485 | "def augment_twice(a_list, val):\n", 486 | " \"\"\"Acrescenta duas referências a `val` no final da lista `a_list`.\"\"\"\n", 487 | " a_list.append(val)\n", 488 | " a_list.append(val)\n", 489 | "\n", 490 | "nums = [1, 2, 3]\n", 491 | "augment_twice(nums, 4)\n", 492 | "print(nums)" 493 | ] 494 | }, 495 | { 496 | "cell_type": "markdown", 497 | "metadata": {}, 498 | "source": [ 499 | "Talvez o resultado da execução do código acima seja surpreendente para você, então vamos analisá-lo passo a passo. Quando invocamos o procedimento ```augment_twice```, os nomes e objetos estão assim:" 500 | ] 501 | }, 502 | { 503 | "cell_type": "markdown", 504 | "metadata": {}, 505 | "source": [ 506 | "" 507 | ] 508 | }, 509 | { 510 | "cell_type": "markdown", 511 | "metadata": {}, 512 | "source": [ 513 | "As referências locais em um procedimento são desenhados em uma moldura. Invocar o procedimento associou os objetos aos nomes dos parâmetros, assim como qualquer instrução de associação faria.\n", 514 | "\n", 515 | "Lembre-se que associações nunca cria novos objetos nem copia dado algum, então aqui a referência local ```a_list``` está associada ao mesmo objeto passado na invocação -- isto é, o objeto ao qual ```nums``` também está associado.\n", 516 | "\n", 517 | "Neste ponto, chamamos a_list.append duas vezes, que altera a lista:" 518 | ] 519 | }, 520 | { 521 | "cell_type": "markdown", 522 | "metadata": {}, 523 | "source": [ 524 | "" 525 | ] 526 | }, 527 | { 528 | "cell_type": "markdown", 529 | "metadata": {}, 530 | "source": [ 531 | "Quando o procedimento se encerra, as referências locais são destruídas. Objetos que não sejam mais referenciados são coletados, mas os outros permanecem:" 532 | ] 533 | }, 534 | { 535 | "cell_type": "markdown", 536 | "metadata": {}, 537 | "source": [ 538 | "" 539 | ] 540 | }, 541 | { 542 | "cell_type": "markdown", 543 | "metadata": {}, 544 | "source": [ 545 | "Nós passamos a lista para o procedimento, que a modificou. Nenhum objeto foi copiado. \n", 546 | "\n", 547 | "Ainda que este comportamento possa ser surpreendente, ela é essencial Sem ela, não seria possível criar métodos que alterassem objetos.\n", 548 | "\n", 549 | "Aqui vai uma outra forma de criar um procedimento, mas que não funciona. Vamos ver porquê:" 550 | ] 551 | }, 552 | { 553 | "cell_type": "code", 554 | "execution_count": 2, 555 | "metadata": { 556 | "collapsed": false 557 | }, 558 | "outputs": [ 559 | { 560 | "name": "stdout", 561 | "output_type": "stream", 562 | "text": [ 563 | "[1, 2, 3]\n" 564 | ] 565 | } 566 | ], 567 | "source": [ 568 | "def augment_twice_bad(a_list, val):\n", 569 | " \"\"\"Acrescenta duas referências a `val` no final da lista `a_list`.\"\"\"\n", 570 | " a_list = a_list + [val, val]\n", 571 | "\n", 572 | "nums = [1, 2, 3]\n", 573 | "augment_twice_bad(nums, 4)\n", 574 | "print(nums)" 575 | ] 576 | }, 577 | { 578 | "cell_type": "markdown", 579 | "metadata": {}, 580 | "source": [ 581 | "No momento em que invocamos ```augment_twice_bad```, tudo parece igual ao exemplo anterior:" 582 | ] 583 | }, 584 | { 585 | "cell_type": "markdown", 586 | "metadata": {}, 587 | "source": [ 588 | "" 589 | ] 590 | }, 591 | { 592 | "cell_type": "markdown", 593 | "metadata": {}, 594 | "source": [ 595 | "A próxima instrução é uma associação.\n", 596 | "\n", 597 | "A expressão no lado direito cria uma nova lista, que então é associada à referência ```a_list```.\n", 598 | "\n", 599 | "**Lembre-se que os operadores infixos não tentam fazer alterações in-place! Este papel é dos operadores de associação composta!**" 600 | ] 601 | }, 602 | { 603 | "cell_type": "markdown", 604 | "metadata": {}, 605 | "source": [ 606 | "" 607 | ] 608 | }, 609 | { 610 | "cell_type": "markdown", 611 | "metadata": {}, 612 | "source": [ 613 | "Quando o procedimento acaba, suas referências locais são destruídas e quaisquer objetos que não sejam mais referenciados são coletados, nos levando de volta ao estado anterior à execução do procedimento:" 614 | ] 615 | }, 616 | { 617 | "cell_type": "markdown", 618 | "metadata": {}, 619 | "source": [ 620 | "" 621 | ] 622 | }, 623 | { 624 | "cell_type": "markdown", 625 | "metadata": {}, 626 | "source": [ 627 | "É realmente importante ter em mente a diferença entre alterar um objeto in-place e reassociar uma referência.\n", 628 | "\n", 629 | "O procedimento ```augment_twice``` funcionou porque alterou o objeto passado, então a alteração estava disponível após o procedimento retornar.\n", 630 | "\n", 631 | "Já o procedimento ```augment_twice_bad``` usou uma associação para reassociar uma referência local, então estas mudanças não são visíveis fora do procedimento.\n", 632 | "\n", 633 | "Outra opção para o nosso procedimento é criar um novo objeto e retorná-lo:" 634 | ] 635 | }, 636 | { 637 | "cell_type": "code", 638 | "execution_count": 4, 639 | "metadata": { 640 | "collapsed": false 641 | }, 642 | "outputs": [ 643 | { 644 | "name": "stdout", 645 | "output_type": "stream", 646 | "text": [ 647 | "[1, 2, 3, 4, 4]\n" 648 | ] 649 | } 650 | ], 651 | "source": [ 652 | "def augment_twice_good(a_list, val):\n", 653 | " a_list = a_list + [val, val]\n", 654 | " return a_list\n", 655 | "\n", 656 | "nums = [1, 2, 3]\n", 657 | "nums = augment_twice_good(nums, 4)\n", 658 | "print(nums)" 659 | ] 660 | }, 661 | { 662 | "cell_type": "markdown", 663 | "metadata": {}, 664 | "source": [ 665 | "Aqui nós criamos um objeto inteiramente novo dentro de ```augment_twice_good``` e o retornamos de dentro do procedimento. Quem chamou o procedimento usa uma associação para se referir a esse objeto, então conseguimos o efeito que queremos.\n", 666 | "\n", 667 | "Este último procedimento é talvez o melhor, já que cria a menor quantidade de surpresas, uma vez que não tenta fazer alterações in-place, criando diretamente novos objetos.\n", 668 | "\n", 669 | "Não há resposta certa entre escolher alterar ou reassociar: o que você deve usar depende do efeito que você precisa.\n", 670 | "\n", 671 | "O mais importante é entender como cada situação acontece, saber as ferramentas à sua disposição e então escolher a que funcione melhor para o seu problema específico." 672 | ] 673 | }, 674 | { 675 | "cell_type": "markdown", 676 | "metadata": {}, 677 | "source": [ 678 | "## Tipagem dinâmica" 679 | ] 680 | }, 681 | { 682 | "cell_type": "markdown", 683 | "metadata": {}, 684 | "source": [ 685 | "Alguns detalhes sobre os objetos e referências Python:" 686 | ] 687 | }, 688 | { 689 | "cell_type": "markdown", 690 | "metadata": {}, 691 | "source": [ 692 | "### Fato: Qualquer nome pode se referir a qualquer objeto em qualquer momento." 693 | ] 694 | }, 695 | { 696 | "cell_type": "markdown", 697 | "metadata": {}, 698 | "source": [ 699 | "Python tem tipagem dinâmica, o que significa que referências em si não tem tipos. \n", 700 | "\n", 701 | "Qualquer nome pode se referir a qualquer objeto em qualquer momento. \n", 702 | "\n", 703 | "Um nome pode se referir a um inteiro, depois a uma string, em seguida a um procedimento e, por fim, a um módulo.\n", 704 | "\n", 705 | "Obviamente, este seria um código bastante confuso, então **não faça isso**, mas o interpretador Python não se confundirá!" 706 | ] 707 | }, 708 | { 709 | "cell_type": "markdown", 710 | "metadata": {}, 711 | "source": [ 712 | "### Fato: Referências não têm tipo, objetos não tem escopo." 713 | ] 714 | }, 715 | { 716 | "cell_type": "markdown", 717 | "metadata": {}, 718 | "source": [ 719 | "Assim como referências não têm tipo, objetos não têm escopo.\n", 720 | "\n", 721 | "Quando dizemos que um procedimento tem uma variável local, queremos dizer que aquela referência tem seu escopo restrito ao procedimento: você não consegue usá-la fora do procedimento e, quando o procedimento retornar, aquela referência será destruída.\n", 722 | "\n", 723 | "Mas como já vimos, se o objeto referido internamente no procedimento tiver referências externas ao procedimento, ele continuará existindo mesmo quando o procedimento retornar. \n", 724 | "\n", 725 | "**É uma referência local, não um objeto local.**" 726 | ] 727 | }, 728 | { 729 | "cell_type": "code", 730 | "execution_count": 3, 731 | "metadata": { 732 | "collapsed": false 733 | }, 734 | "outputs": [ 735 | { 736 | "name": "stdout", 737 | "output_type": "stream", 738 | "text": [ 739 | "4448867976\n", 740 | "4448867976\n", 741 | "[1, 3, 2]\n" 742 | ] 743 | } 744 | ], 745 | "source": [ 746 | "def proc(a):\n", 747 | " a.append(2)\n", 748 | " print(id(a))\n", 749 | " \n", 750 | "b = [1,3]\n", 751 | "proc(b)\n", 752 | "print(id(b))\n", 753 | "print(b)" 754 | ] 755 | }, 756 | { 757 | "cell_type": "markdown", 758 | "metadata": {}, 759 | "source": [ 760 | "### Fato: Objetos não podem ser destruídos, apenas referências." 761 | ] 762 | }, 763 | { 764 | "cell_type": "markdown", 765 | "metadata": {}, 766 | "source": [ 767 | "A gerência de memória do Python é central para o comportamento do interpretador -- **não só você não têm que destruir objetos, você não tem como destruir objetos**.\n", 768 | "\n", 769 | "Talvez você tenha lido sobre a instrução ```del```:" 770 | ] 771 | }, 772 | { 773 | "cell_type": "code", 774 | "execution_count": 6, 775 | "metadata": { 776 | "collapsed": true 777 | }, 778 | "outputs": [], 779 | "source": [ 780 | "nums = [1, 2, 3]\n", 781 | "del nums" 782 | ] 783 | }, 784 | { 785 | "cell_type": "markdown", 786 | "metadata": {}, 787 | "source": [ 788 | "Isto não destrói o objeto referido por **nums** -- isto destrói a referência **nums**.\n", 789 | "\n", 790 | "Esta referência é removida do escopo atual e então o coletor de lixo do Python entra em ação: se o objeto referido por **nums** só estivesse sendo referido por **nums**, este objeto será coletado. Caso contrário, o objeto continua existindo." 791 | ] 792 | }, 793 | { 794 | "cell_type": "markdown", 795 | "metadata": {}, 796 | "source": [ 797 | "### Mito: Python não têm variáveis." 798 | ] 799 | }, 800 | { 801 | "cell_type": "markdown", 802 | "metadata": {}, 803 | "source": [ 804 | "Algumas pessoas gostam de dizer que \"*Python não tem variáveis -- apenas nomes*\". \n", 805 | "\n", 806 | "people like to say, “Python has no variables, it has names.” This slogan is misleading. The truth is that Python has variables, they just work differently than variables in C.\n", 807 | "\n", 808 | "Names are Python’s variables: they refer to values, and those values can change (vary) over the course of your program. Just because another language (albeit an important one) behaves differently is no reason to describe Python as not having variables.\n", 809 | "\n", 810 | "\n" 811 | ] 812 | }, 813 | { 814 | "cell_type": "code", 815 | "execution_count": null, 816 | "metadata": { 817 | "collapsed": true 818 | }, 819 | "outputs": [], 820 | "source": [] 821 | } 822 | ], 823 | "metadata": { 824 | "kernelspec": { 825 | "display_name": "Python 3", 826 | "language": "python", 827 | "name": "python3" 828 | }, 829 | "language_info": { 830 | "codemirror_mode": { 831 | "name": "ipython", 832 | "version": 3 833 | }, 834 | "file_extension": ".py", 835 | "mimetype": "text/x-python", 836 | "name": "python", 837 | "nbconvert_exporter": "python", 838 | "pygments_lexer": "ipython3", 839 | "version": "3.5.2" 840 | } 841 | }, 842 | "nbformat": 4, 843 | "nbformat_minor": 1 844 | } 845 | --------------------------------------------------------------------------------