├── .gitignore ├── CONTRIBUIR.md ├── ERRATA.md ├── LICENSE.md ├── README.md ├── docs ├── 00-prefacio.md ├── 01-jornada.md ├── 02-vars-expr-instr.md ├── 03-funcoes.md ├── 04-caso-interface.md ├── 05-cond-recur.md ├── 06-funcoes-result.md ├── 07-iteracao.md ├── 08-strings.md ├── 09-caso-palavras.md ├── 10-listas.md ├── 11-dicionarios.md ├── 12-tuplas.md ├── 13-caso-estruturas.md ├── 14-arquivos.md ├── 15-classes-objetos.md ├── 16-classes-funcoes.md ├── 17-classes-metodos.md ├── 18-heranca.md ├── 19-extra.md ├── A-depuracao.md ├── B-analise-algorit.md ├── C-colofao-autor.md ├── _config.yml └── index.md ├── ebooks ├── PenseEmPython2e.epub └── metadata.xml ├── fig ├── p19f1.png ├── p242f1.png ├── p63f1.png ├── p72f1.png ├── p79f1.png ├── p79f2.png ├── p80f1.png ├── p83f1.png ├── tnkp_0201.png ├── tnkp_0301.png ├── tnkp_0401.png ├── tnkp_0402.png ├── tnkp_0501.png ├── tnkp_0502.png ├── tnkp_0601.png ├── tnkp_0701.png ├── tnkp_0801.png ├── tnkp_0802.png ├── tnkp_1001.png ├── tnkp_1002.png ├── tnkp_1003.png ├── tnkp_1004.png ├── tnkp_1005.png ├── tnkp_1101.png ├── tnkp_1102.png ├── tnkp_1201.png ├── tnkp_1202.png ├── tnkp_1501.png ├── tnkp_1502.png ├── tnkp_1503.png ├── tnkp_1601.png ├── tnkp_1801.png ├── tnkp_1802.png └── tnkp_2101.png ├── img ├── Capa_PenseEmPython167x232.png ├── Capa_PenseEmPython332x461-borda.png └── Capa_PenseEmPython667x927.png ├── recebido ├── PenseEmPython.md ├── PenseEmPython.xml ├── capitulos.ods ├── capitulos.txt ├── capitulos │ ├── 00-prefacio.md │ ├── 01-jornada.md │ ├── 02-vars-expr-instr.md │ ├── 03-funcoes.md │ ├── 04-caso-interface.md │ ├── 05-cond-recur.md │ ├── 06-funcoes-result.md │ ├── 07-iteracao.md │ ├── 08-strings.md │ ├── 09-caso-palavras.md │ ├── 10-listas.md │ ├── 11-dicionarios.md │ ├── 12-tuplas.md │ ├── 13-caso-estruturas.md │ ├── 14-arquivos.md │ ├── 15-classes-objetos.md │ ├── 16-classes-funcoes.md │ ├── 17-classes-metodos.md │ ├── 18-heranca.md │ ├── 19-extra.md │ ├── A-depuracao.md │ └── B-analise-algorit.md ├── figuras │ ├── p19f1.pdf │ ├── p242f1.pdf │ ├── p63f1.pdf │ ├── p72f1.pdf │ ├── p79f1.pdf │ ├── p79f2.pdf │ ├── p80f1.pdf │ ├── p83f1.pdf │ ├── tnkp_0201.ai │ ├── tnkp_0301.ai │ ├── tnkp_0401.ai │ ├── tnkp_0402.ai │ ├── tnkp_0501.ai │ ├── tnkp_0502.ai │ ├── tnkp_0601.ai │ ├── tnkp_0701.ai │ ├── tnkp_0801.ai │ ├── tnkp_0802.ai │ ├── tnkp_1001.ai │ ├── tnkp_1002.ai │ ├── tnkp_1003.ai │ ├── tnkp_1004.ai │ ├── tnkp_1005.ai │ ├── tnkp_1101.ai │ ├── tnkp_1102.ai │ ├── tnkp_1201.ai │ ├── tnkp_1202.ai │ ├── tnkp_1501.ai │ ├── tnkp_1502.ai │ ├── tnkp_1503.ai │ ├── tnkp_1601.ai │ ├── tnkp_1801.ai │ ├── tnkp_1802.ai │ └── tnkp_2101.ai ├── sumario.md └── thinkpython2.pdf └── util ├── epub.py ├── gloss_e_exerc.py ├── glossario_dl.py ├── marcar_listagens.py ├── marcar_secoes.py └── separar_capitulos.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | 91 | tmp/ 92 | -------------------------------------------------------------------------------- /CONTRIBUIR.md: -------------------------------------------------------------------------------- 1 | # Como contribuir 2 | 3 | ## Procedimento 4 | 5 | Para contribuir: 6 | 7 | 1. Use o GitHub para fazer um fork do [repositório principal](https://github.com/PenseAllen/PensePython2e.git). 8 | 9 | 2. Clone o seu fork em sua máquina local. 10 | 11 | 3. Faça `commit` explicando claramente o motivo de cada alteração. 12 | 13 | 4. Faça `push` de suas alterações para o seu fork. 14 | 15 | 5. Use o GitHub para submeter um _pull request_ do seu fork para o repositório principal, incluindo uma descrição clara das alterações propostas. 16 | 17 | 18 | ## Critérios editoriais 19 | 20 | ### Marcação de palavras no texto corrido 21 | 22 | Nomes de variáveis, funções e módulos que aparecem nos exemplos antes e depois de um parágrafo devem ser marcadas como código, usando crases, assim: `x`, `factorial`, `os.path`. 23 | 24 | Os nomes dos tipos mais comuns, como string, float e bytes, exigem uma decisão. Por exemplo, quando o assunto é cadeia de caracteres qualquer, use string sem adorno, mas quando se está falando especificamente do tipo `string`, em uma discussão sobre tipos, use marcação de código: `string`. O motivo desse critério é evitar poluir demais o texto com marcações de código quando se trata genericamente desses conceitos. 25 | -------------------------------------------------------------------------------- /ERRATA.md: -------------------------------------------------------------------------------- 1 | # Erros encontrados na tradução 2 | 3 | ## Prefácio 4 | 5 | Ante-penúltimo ponto: em vez de "Muito, muito obrigada" deveria ser "Muito, muito obrigado" 6 | 7 | ### Exemplos de uso de código (de acordo com a política da O'Reilly) 8 | 9 | O título desta sessão em inglês é "Using Code Examples". Em português, "Uso do código dos exemplos" seria uma tradução mais fiel. O texto entre parênteses não aparece no PDF da O'Reilly (p. xiii do PDF original). 10 | 11 | ## Capítulo 3 12 | 13 | ### 3.9 - Diagrama da pilha 14 | 15 | Parágrafo 3, "`__main__`, que é um nome especial para o frame na posição mais proeminente"; no original, trata-se do "topmost frame". Seria melhor traduzir como "o frame no topo da pilha" (veja figura 3.1) 16 | 17 | 18 | ## Capítulo 5 19 | 20 | ### Exercício 5.2 21 | 22 | "há nenhum número inteiro positivo a, b e c tal que" deveria ser "não existem números inteiros a, b e c tais que" 23 | 24 | ## Capítulo 6 25 | 26 | ### 6.5 - Mais recursividade 27 | 28 | Parágrafo 2: "é conhecido como o Teste de Turing. Para uma exposição mais completa (e exata) do Teste de Turing": o autor está explicando a Tese de Turing, portanto o correto é: "é conhecida como a Tese de Turing. Para uma exposição mais completa (e exata) da Tese de Turing" 29 | 30 | ## Capítulo 7 31 | 32 | ### 7.5 - Raízes quadradas 33 | 34 | Antepenúltimo parágrafo: "números mais racionais, como 1/3" está errado, o correto é "a maioria dos números racionais, como 1/3" 35 | 36 | ## Capítulo 12 37 | 38 | ### 12.5 - Listas e tuplas 39 | 40 | Parágrafo 5: "Se quiser usar operadores de lista e métodos", deveria ser "Se quiser usar operadores e métodos de lista" 41 | 42 | 43 | ## Capítulo 14 44 | 45 | 46 | ## 14.5 - Captura de exceções 47 | 48 | Parágrafo 3: "E se tentar abrir um diretório de leitura", deveria ser "E se tentar abrir um diretório para leitura" 49 | 50 | 51 | ## 14.7 - Usando o Pickle 52 | 53 | Parágrafos 3 e 4: as seguintes explicações entre parêntesis estão equivocadas e devem ser removidas: 54 | 55 | (dumps é a abreviação de “string de depósito” em inglês) 56 | (“string de carregamento” em inglês) 57 | 58 | ## 14.9 - Módulos de escrita 59 | 60 | O título desta seção no original é "Writing modules"; no contexto, a tradução correta é "Escrevendo módulos". 61 | 62 | 63 | ## Capítulo 15 64 | 65 | ### 15.1 - Tipos definidos pelos programadores 66 | 67 | Parágrafo 2, "(x, y) representa o ponto que está x unidades à direita e y unidades a partir da origem." deveria ser "(x, y) representa o ponto que está x unidades à direita e y unidades acima da origem." 68 | 69 | ## Capítulo 18 70 | 71 | ### 18.11 - Glossário 72 | 73 | A definição do termo __multiplicidade__ está confusa. Em vez de "quantas referências dela são instâncias de outra classe." é melhor "quantas referências a instâncias da outra classe podem existir." 74 | 75 | ## Capítulo 19 76 | 77 | ### 19.3 - Expressões geradoras 78 | 79 | Parágrafo 4, a exceção mencionada está como "StopException", mas o correto é "StopIteration". 80 | 81 | Nota: este erro existe também no original e eu (@ramalho) já o reportei no site da O'Reilly. 82 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Licença 2 | 3 | Copyright © 2015 Allen Downey. 4 | 5 | ## CC BY-NC 3.0 6 | 7 | Este trabalho é oferecido sob a licença __Creative Commons Atribuição-NãoComercial 3.0 Não Adaptada__. 8 | 9 | O texto a seguir é um resumo e não substitui a licença completa em [legalês inglês](https://creativecommons.org/licenses/by-nc/3.0/legalcode). 10 | 11 | 12 | ## Você tem o direito de: 13 | 14 | __Compartilhar__ — copiar e redistribuir o material em qualquer suporte ou formato 15 | 16 | __Adaptar__ — remixar, transformar, e criar a partir do material 17 | 18 | O licenciante não pode revogar estes direitos desde que você respeite os termos da licença. 19 | 20 | 21 | ## De acordo com os termos seguintes: 22 | 23 | __Atribuição__ — Você deve dar o __crédito apropriado__, prover um link para a licença e __indicar se mudanças foram feitas__. Você deve fazê-lo em qualquer circunstância razoável, mas de maneira alguma que sugira ao licenciante a apoiar você ou o seu uso. 24 | 25 | __NãoComercial__ — Você não pode usar o material para __fins comerciais__. 26 | 27 | __Sem restrições adicionais__ — Você não pode aplicar termos jurídicos ou __medidas de caráter tecnológico__ que restrinjam legalmente outros de fazerem algo que a licença permita. 28 | 29 | ## Avisos: 30 | 31 | Você não tem de cumprir com os termos da licença relativamente a elementos do material que estejam no domínio público ou cuja utilização seja permitida por uma __exceção ou limitação__ que seja aplicável. 32 | 33 | Não são dadas quaisquer garantias. A licença pode não lhe dar todas as autorizações necessárias para o uso pretendido. Por exemplo, outros direitos, tais como __direitos de imagem, de privacidade ou direitos morais__, podem limitar o uso do material. 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pense em Python 2 | 3 | 4 | 5 | Tradução do livro [Think Python](http://greenteapress.com/wp/think-python-2e/) (2ª edição), de Allen B. Downey, publicado sob licença [CC BY-NC 3.0](LICENSE.md). 6 | 7 | Este livro ensina programação para quem nunca programou, usando Python 3 nos exemplos. É aplicado no Olin College, IBMEC e outras faculdades de engenharia excelentes. 8 | 9 | > __DICA__: Você pode comprar um exemplar impresso de [__Pense em Python__](https://novatec.com.br/livros/pense-em-python/) no site da [Editora Novatec](https://novatec.com.br/livros/pense-em-python/) ou em livrarias. [ISBN: 978-85-7522-508-0](https://novatec.com.br/livros/pense-em-python/). 10 | 11 | [Versão navegável em HTML](https://PenseAllen.github.io/PensePython2e/) 12 | 13 | 14 | ## Créditos da edição brasileira 15 | 16 | Editor: Rubens Prates
17 | Tradução: Sheila Gomes
18 | Revisão Gramatical: Smirna Cavalheiro
19 | Editoração Eletrônica: Carolina Kuwabata
20 | Assistente Editorial: Priscila A. Yoshimatsu 21 | 22 | 23 | ## Proveniência 24 | 25 | Agradecemos a Rubens Prates da Editora Novatec por ter cedido gentilmente os arquivos com o texto integral e as figuras de [Pense em Python](https://novatec.com.br/livros/pense-em-python/), publicado sob licença da O'Reilly Media. 26 | 27 | O arquivo [`recebido/PenseEmPython.xml`](recebido/PenseEmPython.xml) em formato DocBook foi gerado a partir do arquivo InDesign criado pela Editora Novatec. Na conversão para DocBook foram usados os programas InDesign, Word e LibreOffice. 28 | 29 | O DocBook `PenseEmPython.xml` foi convertido para _markdown_ com a ferramenta Pandoc versão 1.19.2.1 usando a seguinte linha de comando: 30 | 31 | ```bash 32 | $ pandoc PenseEmPython.xml -f docbook -t markdown_github -o PenseEmPython.md 33 | ``` 34 | 35 | Os arquivos _markdown_ separados por capítulo em [`recebido/docs/`](recebido/docs/) foram gerados a partir de `PenseEmPython.md` pelo script [`util/separar_capitulos.py`](util/separar_capitulos.py). 36 | 37 | A partir desse ponto, os ajustes nos capítulos foram feitos manualmente, com ajuda ocasional de scripts encontrados no diretório [`util/`](util/). 38 | -------------------------------------------------------------------------------- /docs/02-vars-expr-instr.md: -------------------------------------------------------------------------------- 1 | # Capítulo 2: Variáveis, expressões e instruções 2 | 3 | Um dos recursos mais eficientes de uma linguagem de programação é a capacidade de manipular variáveis. Uma variável é um nome que se refere a um valor. 4 | 5 | ## 2.1 - Instruções de atribuição 6 | 7 | Uma instrução de atribuição cria uma nova variável e dá um valor a ela: 8 | 9 | ```python 10 | >>> message = 'And now for something completely different' 11 | >>> n = 17 12 | >>> pi = 3.141592653589793 13 | ``` 14 | 15 | Esse exemplo faz três atribuições. A primeira atribui uma string a uma nova variável chamada message; a segunda dá o número inteiro 17 a n; a terceira atribui o valor (aproximado) de π a pi. 16 | 17 | Uma forma comum de representar variáveis por escrito é colocar o nome com uma flecha apontando para o seu valor. Este tipo de número é chamado de diagrama de estado porque mostra o estado no qual cada uma das variáveis está (pense nele como o estado de espírito da variável). A Figura 2.1 mostra o resultado do exemplo anterior. 18 | 19 | ![Figura 2.1 – Diagrama de estado.](https://github.com/PenseAllen/PensePython2e/raw/master/fig/tnkp_0201.png) 20 |
_Figura 2.1 – Diagrama de estado._ 21 | 22 | 23 | ## 2.2 - Nomes de variáveis 24 | 25 | Os programadores geralmente escolhem nomes significativos para as suas variáveis – eles documentam o uso da variável. 26 | 27 | Nomes de variáveis podem ser tão longos quanto você queira. Podem conter tanto letras como números, mas não podem começar com um número. É legal usar letras maiúsculas, mas a convenção é usar apenas letras minúsculas para nomes de variáveis. 28 | 29 | O caractere de sublinhar (\_) pode aparecer em um nome. Muitas vezes é usado em nomes com várias palavras, como your\_name ou airspeed\_of\_unladen\_swallow. 30 | 31 | Se você der um nome ilegal a uma variável, recebe um erro de sintaxe: 32 | 33 | ```python 34 | >>> 76trombones = 'big parade' 35 | SyntaxError: invalid syntax 36 | >>> more@ = 1000000 37 | SyntaxError: invalid syntax 38 | >>> class = 'Advanced Theoretical Zymurgy' 39 | SyntaxError: invalid syntax 40 | ``` 41 | `76trombones` é ilegal porque começa com um número. `more@` é ilegal porque contém um caractere ilegal, o `@`. Mas o que há de errado com `class`? 42 | 43 | A questão é que class é uma das palavras-chave do Python. O interpretador usa palavras-chave para reconhecer a estrutura do programa e elas não podem ser usadas como nomes de variável. 44 | 45 | 46 | O Python 3 tem estas palavras-chave: 47 | 48 | ``` 49 | and del from None True 50 | as elif global nonlocal try 51 | assert else if not while 52 | break except import or with 53 | class False in pass yield 54 | continue finally is raise 55 | def for lambda return 56 | ``` 57 | 58 | Você não precisa memorizar essa lista. Na maior parte dos ambientes de desenvolvimento, as palavras-chave são exibidas em uma cor diferente; se você tentar usar uma como nome de variável, vai perceber. 59 | 60 | ## 2.3 - Expressões e instruções 61 | 62 | Uma expressão é uma combinação de valores, variáveis e operadores. Um valor por si mesmo é considerado uma expressão, assim como uma variável, portanto as expressões seguintes são todas legais: 63 | 64 | ```python 65 | >>> 42 66 | 42 67 | >>> n 68 | 17 69 | >>> n + 25 70 | 42 71 | ``` 72 | 73 | Quando você digita uma expressão no prompt, o interpretador a avalia, ou seja, ele encontra o valor da expressão. Neste exemplo, o n tem o valor 17 e n + 25 tem o valor 42. 74 | 75 | Uma instrução é uma unidade de código que tem um efeito, como criar uma variável ou exibir um valor. 76 | 77 | ```python 78 | >>> n = 17 79 | >>> print(n) 80 | ``` 81 | 82 | A primeira linha é uma instrução de atribuição que dá um valor a n. A segunda linha é uma instrução de exibição que exibe o valor de n. 83 | 84 | Quando você digita uma instrução, o interpretador a executa, o que significa que ele faz o que a instrução diz. Em geral, instruções não têm valores. 85 | 86 | ## 2.4 - Modo script 87 | 88 | Até agora executamos o Python no modo interativo, no qual você interage diretamente com o interpretador. O modo interativo é uma boa forma de começar, mas se estiver trabalhando com mais do que algumas linhas do código, o processo pode ficar desorganizado. 89 | 90 | A alternativa é salvar o código em um arquivo chamado script e então executar o interpretador no modo script para executá-lo. Por convenção, os scripts no Python têm nomes que terminam com .py. 91 | 92 | Se souber como criar e executar um script no seu computador, você está pronto. Senão, recomendo usar o PythonAnywhere novamente. Inseri instruções sobre como executar programas no modo script em http://tinyurl.com/thinkpython2e. 93 | 94 | Como o Python oferece os dois modos, você pode testar pedaços do código no modo interativo antes de colocá-los em um script. Mas há diferenças entre o modo interativo e o modo script que podem confundir as pessoas. 95 | 96 | Por exemplo, se estiver usando o Python como uma calculadora, você poderia digitar: 97 | 98 | ```python 99 | >>> miles = 26.2 100 | >>> miles * 1.61 101 | 42.182 102 | ``` 103 | 104 | A primeira linha atribui um valor a miles, mas não tem efeito visível. A segunda linha é uma expressão, então o interpretador a avalia e exibe o resultado. No fim, chega-se ao resultado de que uma maratona tem aproximadamente 42 quilômetros. 105 | 106 | Mas se você digitar o mesmo código em um script e executá-lo, não recebe nenhuma saída. Uma expressão, por conta própria, não tem efeito visível no modo script. O Python, na verdade, avalia a expressão, mas não exibe o valor a menos que você especifique: 107 | 108 | ```python 109 | miles = 26.2 110 | print(miles * 1.61) 111 | ``` 112 | 113 | Este comportamento pode confundir um pouco no início. 114 | 115 | Um script normalmente contém uma sequência de instruções. Se houver mais de uma instrução, os resultados aparecem um após o outro, conforme as instruções sejam executadas. 116 | 117 | Por exemplo, o script 118 | 119 | ```python 120 | print(1) 121 | x = 2 122 | print(x) 123 | ``` 124 | produz a saída 125 | 126 | ```python 127 | 1 128 | 2 129 | ``` 130 | 131 | A instrução de atribuição não produz nenhuma saída. 132 | 133 | Para verificar sua compreensão, digite as seguintes instruções no interpretador do Python e veja o que fazem: 134 | 135 | ```python 136 | 5 137 | x = 5 138 | x + 1 139 | ``` 140 | 141 | Agora ponha as mesmas instruções em um script e o execute. Qual é a saída? Altere o script transformando cada expressão em uma instrução de exibição e então o execute novamente. 142 | 143 | ## 2.5 - Ordem das operações 144 | 145 | Quando uma expressão contém mais de um operador, a ordem da avaliação depende da ordem das operações. Para operadores matemáticos, o Python segue a convenção matemática. O acrônimo PEMDAS pode ser útil para lembrar das regras: 146 | 147 | * Os Parênteses têm a precedência mais alta e podem ser usados para forçar a avaliação de uma expressão na ordem que você quiser. Como as expressões em parênteses são avaliadas primeiro, `2 * (3-1)` é 4, e `(1+1)**(5-2)` é 8. Também é possível usar parênteses para facilitar a leitura de uma expressão, como no caso de `(minute * 100) / 60`, mesmo se o resultado não for alterado. 148 | 149 | * A Exponenciação tem a próxima precedência mais alta, então `1 + 2**3` é 9, não 27, e `2 * 3**2` é 18, não 36. 150 | 151 | * A Multiplicação e a Divisão têm precedência mais alta que a Adição e a Subtração. Assim, `2 * 3 - 1` é 5, não 4, e `6 + 4 / 2` é 8, não 5. 152 | 153 | * Os operadores com a mesma precedência são avaliados da esquerda para a direita (exceto na exponenciação). Assim, na expressão `degrees / 2 * pi`, a divisão acontece primeiro e o resultado é multiplicado por `pi`. Para dividir por 2π, você pode usar parênteses ou escrever `degrees / 2 / pi`. 154 | 155 | Eu não fico sempre tentando lembrar da precedência de operadores. Se a expressão não estiver clara à primeira vista, uso parênteses para fazer isso. 156 | 157 | ## 2.6 - Operações com strings 158 | 159 | Em geral, não é possível executar operações matemáticas com strings, mesmo se elas parecerem números, então coisas assim são ilegais: 160 | 161 | ``` 162 | '2'-'1'    'eggs'/'easy'    'third'*'a charm' 163 | ``` 164 | 165 | Mas há duas exceções, `+` e `*`. 166 | 167 | O operador `+` executa uma concatenação de strings, ou seja, une as strings pelas extremidades. Por exemplo: 168 | 169 | ```python 170 | >>> first = 'throat' 171 | >>> second = 'warbler' 172 | >>> first + second 173 | throatwarbler 174 | ``` 175 | 176 | O operador `*` também funciona em strings; ele executa a repetição. Por exemplo, 'Spam'`*`3 é 'SpamSpamSpam'. Se um dos valores for uma string, o outro tem de ser um número inteiro. 177 | 178 | Este uso de + e `*` faz sentido por analogia com a adição e a multiplicação. Tal como `4 * 3` é equivalente a `4 + 4 + 4`, esperamos que `'Spam' * 3` seja o mesmo que 'Spam'+'Spam'+'Spam', e assim é. Por outro lado, há uma diferença significativa entre a concatenação de strings e a repetição em relação à adição e à multiplicação de números inteiros. Você consegue pensar em uma propriedade que a adição tem, mas a concatenação de strings não tem? 179 | 180 | ## 2.7 - Comentários 181 | 182 | Conforme os programas ficam maiores e mais complicados, eles são mais difíceis de ler. As linguagens formais são densas e muitas vezes é difícil ver um pedaço de código e compreender o que ele faz ou por que faz isso. 183 | 184 | Por essa razão, é uma boa ideia acrescentar notas aos seus programas para explicar em linguagem natural o que o programa está fazendo. Essas notas são chamadas de comentários, e começam com o símbolo `#`: 185 | 186 | 187 | ```python 188 | # computa a percentagem da hora que passou 189 | percentage = (minute * 100) / 60 190 | ``` 191 | Nesse caso, o comentário aparece sozinho em uma linha. Você também pode pôr comentários no fim das linhas: 192 | 193 | ```python 194 | percentage = (minute * 100) / 60    # percentagem de uma hora 195 | ``` 196 | 197 | Tudo do `#` ao fim da linha é ignorado – não tem efeito na execução do programa. 198 | 199 | Os comentários tornam-se mais úteis quando documentam algo no código que não está óbvio. Podemos supor que o leitor compreenda o que o código faz; assim, é mais útil explicar porque faz o que faz. 200 | 201 | Este comentário é redundante em relação ao código, além de inútil: 202 | 203 | ```python 204 | v = 5    # atribui 5 a v 205 | ``` 206 | 207 | Este comentário contém informações úteis que não estão no código: 208 | 209 | ```python 210 | v = 5    # velocidade em metros/segundo. 211 | ``` 212 | 213 | Bons nomes de variáveis podem reduzir a necessidade de comentários, mas nomes longos podem tornar expressões complexas difíceis de ler, então é preciso analisar o que vale mais a pena. 214 | 215 | ## 2.8 - Depuração 216 | 217 | Há três tipos de erros que podem ocorrer em um programa: erros de sintaxe, erros de tempo de execução e erros semânticos. É útil distinguir entre eles para rastreá-los mais rapidamente. 218 | 219 |
220 |
Erro de sintaxe
221 |
A “sintaxe” refere-se à estrutura de um programa e suas respectivas regras. Por exemplo, os parênteses devem vir em pares correspondentes, então (1 + 2) é legal, mas 8) é um erro de sintaxe.
222 |
Se houver um erro de sintaxe em algum lugar no seu programa, o Python exibe uma mensagem de erro e para, e não será possível executar o programa. Nas primeiras poucas semanas da sua carreira em programação, você pode passar muito tempo rastreando erros de sintaxe. Ao adquirir experiência, você fará menos erros e os encontrará mais rápido.
223 | 224 |
Erro de tempo de execução
225 |
O segundo tipo de erro é o erro de tempo de execução, assim chamado porque o erro não aparece até que o programa seja executado. Esses erros também se chamam de exceções porque normalmente indicam que algo excepcional (e ruim) aconteceu.
226 |
Os erros de tempo de execução são raros nos programas simples que veremos nos primeiros capítulos, então pode demorar um pouco até você encontrar algum.
227 | 228 |
Erro semântico
229 |
O terceiro tipo do erro é “semântico”, ou seja, relacionado ao significado. Se houver um erro semântico no seu programa, ele será executado sem gerar mensagens de erro, mas não vai fazer a coisa certa. Vai fazer algo diferente. Especificamente, vai fazer o que você disser para fazer.
230 |
Identificar erros semânticos pode ser complicado, porque é preciso trabalhar de trás para a frente, vendo a saída do programa e tentando compreender o que ele está fazendo.
231 |
232 | 233 | ## 2.9 - Glossário 234 | 235 |
236 |
variável
237 |
Um nome que se refere a um valor.
238 | 239 |
atribuição
240 |
Uma instrução que atribui um valor a uma variável.
241 | 242 |
diagrama de estado
243 |
Uma representação gráfica de um grupo de variáveis e os valores a que se referem.
244 | 245 |
palavra-chave
246 |
Uma palavra reservada, usada para analisar um programa; não é possível usar palavras-chave como if, def e while como nomes de variáveis.
247 | 248 |
operando
249 |
Um dos valores que um operador produz.
250 | 251 |
expressão
252 |
Uma combinação de variáveis, operadores e valores que representa um resultado único.
253 | 254 |
avaliar
255 |
Simplificar uma expressão executando as operações para produzir um valor único.
256 | 257 |
instrução
258 |
Uma seção do código que representa um comando ou ação. Por enquanto, as instruções que vimos são instruções de atribuições e de exibição.
259 | 260 |
executar
261 |
Executar uma instrução para fazer o que ela diz.
262 | 263 |
modo interativo
264 |
Um modo de usar o interpretador do Python, digitando o código no prompt.
265 | 266 |
modo script
267 |
Um modo de usar o interpretador do Python para ler código em um script e executá-lo.
268 | 269 |
script
270 |
Um programa armazenado em um arquivo.
271 | 272 |
ordem das operações
273 |
As regras que governam a ordem na qual as expressões que envolvem vários operadores e operandos são avaliadas.
274 | 275 |
concatenar
276 |
Juntar dois operandos pelas extremidades.
277 | 278 |
comentários
279 |
Informações em um programa destinadas a outros programadores (ou qualquer pessoa que leia o texto fonte) que não têm efeito sobre a execução do programa.
280 | 281 |
erro de sintaxe
282 |
Um erro em um programa que torna sua análise impossível (e por isso impossível de interpretar).
283 | 284 |
exceção
285 |
Um erro que se descobre quando o programa é executado.
286 | 287 |
semântica
288 |
O significado de um programa.
289 | 290 |
erro semântico
291 |
Um erro que faz com que um programa faça algo diferente do que o programador pretendia.
292 | 293 |
294 | 295 | ## 2.10 - Exercícios 296 | 297 | ### Exercício 2.1 298 | 299 | Repetindo o meu conselho do capítulo anterior, sempre que você aprender um recurso novo, você deve testá-lo no modo interativo e fazer erros de propósito para ver o que acontece. 300 | 301 | * Vimos que n = 42 é legal. E 42 = n? 302 | 303 | * Ou x = y = 1? 304 | 305 | * Em algumas linguagens, cada instrução termina em um ponto e vírgula ;. O que acontece se você puser um ponto e vírgula no fim de uma instrução no Python? 306 | 307 | * E se puser um ponto no fim de uma instrução? 308 | 309 | * Em notação matemática é possível multiplicar x e y desta forma: xy. O que acontece se você tentar fazer o mesmo no Python? 310 | 311 | ### Exercício 2.2 312 | 313 | Pratique o uso do interpretador do Python como uma calculadora: 314 | 315 | 1. O volume de uma esfera com raio r é ![Fórmula – Volume de uma esfera.](https://github.com/PenseAllen/PensePython2e/raw/master/fig/p19f1.png). Qual é o volume de uma esfera com raio 5? 316 | 317 | 2. Suponha que o preço de capa de um livro seja R$ 24,95, mas as livrarias recebem um desconto de 40%. O transporte custa R$ 3,00 para o primeiro exemplar e 75 centavos para cada exemplar adicional. Qual é o custo total de atacado para 60 cópias? 318 | 319 | 3. Se eu sair da minha casa às 6:52 e correr 1 quilômetro a um certo passo (8min15s por quilômetro), então 3 quilômetros a um passo mais rápido (7min12s por quilômetro) e 1 quilômetro no mesmo passo usado em primeiro lugar, que horas chego em casa para o café da manhã? 320 | -------------------------------------------------------------------------------- /docs/07-iteracao.md: -------------------------------------------------------------------------------- 1 | # Capítulo 7: Iteração 2 | 3 | Este capítulo é sobre a iteração, a capacidade de executar um bloco de instruções repetidamente. Vimos um tipo de iteração, usando a recursividade, em “Recursividade”, na página 81. Vimos outro tipo, usando um loop for, em “Repetição simples”, na página 65. Neste capítulo veremos ainda outro tipo, usando a instrução while. Porém, primeiro quero falar um pouco mais sobre a atribuição de variáveis. 4 | 5 | ## 7.1 - Reatribuição 6 | 7 | Pode ser que você já tenha descoberto que é permitido fazer mais de uma atribuição para a mesma variável. Uma nova atribuição faz uma variável existente referir-se a um novo valor (e deixar de referir-se ao valor anterior). 8 | 9 | ```python 10 | >>> x = 5 11 | >>> x 12 | 5 13 | >>> x = 7 14 | >>> x 15 | 7 16 | ``` 17 | 18 | A primeira vez que exibimos x, seu valor é 5; na segunda vez, seu valor é 7. 19 | 20 | A Figura 7.1 mostra que a reatribuição parece um diagrama de estado. 21 | 22 | Neste ponto quero tratar de uma fonte comum de confusão. Como o Python usa o sinal de igual (=) para atribuição, é tentador interpretar uma afirmação como a = b como uma proposição matemática de igualdade; isto é, a declaração de que a e b são iguais. Mas esta é uma interpretação equivocada. 23 | 24 | Em primeiro lugar, a igualdade é uma relação simétrica e a atribuição não é. Por exemplo, na matemática, se a=7 então 7=a. Mas no Python, a instrução a = 7 é legal e 7 = a não é. 25 | 26 | Além disso, na matemática, uma proposição de igualdade é verdadeira ou falsa para sempre. Se a=b agora, então a sempre será igual a b. No Python, uma instrução de atribuição pode tornar duas variáveis iguais, mas elas não precisam se manter assim: 27 | 28 | ```python 29 | >>> a = 5 30 | >>> b = a    # a e b agora são iguais 31 | >>> a = 3    # a e b não são mais iguais 32 | >>> b 33 | 5 34 | ``` 35 | 36 | A terceira linha modifica o valor de a, mas não muda o valor de b, então elas já não são iguais. 37 | 38 | A reatribuição de variáveis muitas vezes é útil, mas você deve usá-la com prudência. Se os valores das variáveis mudarem frequentemente, isso pode dificultar a leitura e depuração do código. 39 | 40 | ```python 41 | Figura 7.1 – Diagrama de estado. 42 | ``` 43 | 44 | ![Figura 7.1 – Diagrama de estado da variável x.](https://github.com/PenseAllen/PensePython2e/raw/master/fig/tnkp_0701.png) 45 |
_Figura 7.1 – Diagrama de estado da variável x._ 46 | 47 | ## 7.2 - Atualização de variáveis 48 | 49 | Um tipo comum de reatribuição é uma atualização, onde o novo valor da variável depende do velho. 50 | 51 | ```python 52 | >>> x = x + 1 53 | ``` 54 | 55 | Isso significa “pegue o valor atual de x, acrescente um, e então atualize x para o novo valor”. 56 | 57 | Se você tentar atualizar uma variável que não existe, recebe um erro porque o Python avalia o lado direito antes de atribuir um valor a x: 58 | 59 | ```python 60 | >>> x = x + 1 61 | NameError: name 'x' is not defined 62 | ``` 63 | 64 | Antes de poder atualizar uma variável é preciso inicializá-la, normalmente com uma atribuição simples: 65 | 66 | ```python 67 | >>> x = 0 68 | >>> x = x + 1 69 | ``` 70 | 71 | Atualizar uma variável acrescentando 1 chama-se incremento; subtrair 1 chama-se decremento. 72 | 73 | ## 7.3 - Instrução while 74 | 75 | Os computadores muitas vezes são usados para automatizar tarefas repetitivas. A repetição de tarefas idênticas ou semelhantes sem fazer erros é algo que os computadores fazem bem e as pessoas não. Em um programa de computador, a repetição também é chamada de iteração. 76 | 77 | Já vimos duas funções, `countdown` e `print_n`, que se repetem usando recursividade. Como a iteração é bem comum, o Python fornece recursos de linguagem para facilitá-la. Um deles é a instrução `for` que vimos em “Repetição simples”, na página 65. Voltaremos a isso mais adiante. 78 | 79 | Outra é a instrução `while`. Aqui está uma versão de countdown que usa a instrução `while`: 80 | 81 | ```python 82 | def countdown(n): 83 |     while n > 0: 84 |         print(n) 85 |         n = n - 1 86 |     print('Blastoff!') 87 | ``` 88 | 89 | Você até pode ler a instrução `while` como se fosse uma tradução do inglês. Significa “Enquanto `n` for maior que 0, mostre o valor de `n` e então decremente `n`. Quando chegar a 0, mostre a palavra Blastoff!” 90 | 91 | Mais formalmente, aqui está o fluxo de execução para uma instrução while: 92 | 93 | 1. Determine se a condição é verdadeira ou falsa. 94 | 95 | 2. Se for falsa, saia da instrução while e continue a execução da próxima instrução. 96 | 97 | 3. Se a condição for verdadeira, execute o corpo e então volte ao passo 1. 98 | 99 | Este tipo de fluxo chama-se loop (laço), porque o terceiro passo faz um loop de volta ao topo. 100 | 101 | O corpo do loop deve mudar o valor de uma ou mais variáveis para que, a certa altura, a condição fique falsa e o loop termine. Senão o loop vai se repetir para sempre, o que é chamado de loop infinito. Uma fonte infindável de divertimento para cientistas da computação é a observação das instruções no xampu, “Faça espuma, enxágue, repita”, que são parte de um loop infinito. 102 | 103 | No caso de countdown, podemos provar que o loop termina: se `n` for zero ou negativo, o loop nunca é executado. Senão, `n` fica cada vez menor ao passar pelo loop, até eventualmente chegar a 0. 104 | 105 | Para alguns outros loops, não é tão fácil perceber isso. Por exemplo: 106 | 107 | ```python 108 | def sequence(n): 109 |     while n != 1: 110 |         print(n) 111 |         if n % 2 == 0:        # n é par 112 |             n = n / 2 113 |         else:                 # n é ímpar 114 |             n = n * 3 + 1 115 | ``` 116 | 117 | A condição deste loop é `n != 1`, então o loop continuará até que `n` seja 1, o que torna a condição falsa. 118 | 119 | Cada vez que passa pelo loop, o programa produz o valor de `n` e então verifica se é par ou ímpar. Se for par, `n` é dividido por 2. Se for ímpar, o valor de `n` é substituído por `n * 3 + 1`. Por exemplo, se o argumento passado a sequence for 3, os valores resultantes de `n` são 3, 10, 5, 16, 8, 4, 2, 1. 120 | 121 | Como `n` às vezes aumenta e às vezes diminui, não há nenhuma prova óbvia de que `n` chegará eventualmente a 1, ou que o programa terminará. Para alguns valores de `n`, podemos provar o término. Por exemplo, se o valor inicial for uma potência de dois, `n` será par cada vez que passar pelo loop até que chegue a 1. O exemplo anterior termina com uma sequência assim, que inicia com 16. 122 | 123 | A questão difícil é se podemos provar que este programa termina para todos os valores positivos de `n`. Por enquanto, ninguém foi capaz de comprovar ou refutar isso! (Veja http://en.wikipedia.org/wiki/Collatz\_conjecture.) 124 | 125 | Como um exercício, reescreva a função print\_n de “Recursividade”, na página 81, usando a iteração em vez da recursividade. 126 | 127 | ## 7.4 - break 128 | 129 | Às vezes você não sabe que está na hora de terminar um loop até que já esteja na metade do corpo. Neste caso pode usar a instrução break para sair do loop. 130 | 131 | Por exemplo, suponha que você quer receber uma entrada do usuário até que este digite done. Você pode escrever: 132 | 133 | ```python 134 | while True: 135 |     line = input('> ') 136 |     if line == 'done': 137 |         break 138 |     print(line) 139 | print('Done!') 140 | ``` 141 | 142 | A condição do loop é True, que sempre é verdade, então o loop roda até que chegue à instrução de interrupção. 143 | 144 | Cada vez que passa pelo loop, o programa apresenta ao usuário um colchete angular. Se o usuário digitar done, a instrução break sai do loop. Senão, o programa ecoa o que quer que o usuário digite e volta ao topo do loop. Aqui está uma amostra de execução: 145 | 146 | ```python 147 | > not done 148 | not done 149 | > done 150 | Done! 151 | ``` 152 | 153 | Esta forma de escrever loops while é comum porque podemos verificar a condição em qualquer lugar do loop (não somente no topo) e podemos exprimir a condição de parada afirmativamente (“pare quando isto acontecer”) em vez de negativamente (“continue a seguir até que isto aconteça”). 154 | 155 | ## 7.5 - Raízes quadradas 156 | 157 | Loops muitas vezes são usados em programas que calculam resultados numéricos, começando com uma resposta aproximada e melhorando-a iterativamente. 158 | 159 | Por exemplo, uma forma de calcular raízes quadradas é o método de Newton. Suponha que você queira saber a raiz quadrada de a. Se começar com quase qualquer estimativa, x, é possível calcular uma estimativa melhor com a seguinte fórmula: 160 | 161 | ![Fórmula – Raiz quadrada pelo método de Newton.](https://github.com/PenseAllen/PensePython2e/raw/master/fig/p79f1.png) 162 | 163 | ```python 164 | Por exemplo, se a for 4 e x for 3: 165 | >>> a = 4 166 | >>> x = 3 167 | >>> y = (x + a/x) / 2 168 | >>> y 169 | 2.16666666667 170 | ``` 171 | O resultado é mais próximo à resposta correta (![Fórmula – Raiz quadrada de 4.](https://github.com/PenseAllen/PensePython2e/raw/master/fig/p79f2.png) = 2). Se repetirmos o processo com a nova estimativa, chegamos ainda mais perto: 172 | 173 | ```python 174 | >>> x = y 175 | >>> y = (x + a/x) / 2 176 | >>> y 177 | 2.00641025641 178 | ``` 179 | Depois de algumas atualizações, a estimativa é quase exata: 180 | 181 | ```python 182 | >>> x = y 183 | >>> y = (x + a/x) / 2 184 | >>> y 185 | 2.00001024003 186 | >>> x = y 187 | >>> y = (x + a/x) / 2 188 | >>> y 189 | 2.00000000003 190 | ``` 191 | 192 | Em geral, não sabemos com antecedência quantos passos são necessários para chegar à resposta correta, mas sabemos quando chegamos lá porque a estimativa para de mudar: 193 | 194 | ```python 195 | >>> x = y 196 | >>> y = (x + a/x) / 2 197 | >>> y 198 | 2.0 199 | >>> x = y 200 | >>> y = (x + a/x) / 2 201 | >>> y 202 | 2.0 203 | ``` 204 | Quando y == x, podemos parar. Aqui está um loop que começa com uma estimativa inicial, x, e a melhora até que deixe de mudar: 205 | 206 | ```python 207 | while True: 208 |     print(x) 209 |     y = (x + a/x) / 2 210 |     if y == x: 211 |         break 212 |     x = y 213 | ``` 214 | 215 | Para a maior parte de valores de `a` funciona bem, mas pode ser perigoso testar a igualdade de um float. Os valores de ponto flutuante são aproximadamente corretos: a maioria dos números racionais, como 1/3, e números irracionais, como ![Fórmula – Raiz quadrada de 2.](https://github.com/PenseAllen/PensePython2e/raw/master/fig/p80f1.png), não podem ser representados exatamente com um float. 216 | 217 | Em vez de verificar se `x` e `y` são exatamente iguais, é mais seguro usar a função integrada `abs` para calcular o valor absoluto ou magnitude da diferença entre eles: 218 | 219 | ```python 220 | if abs(y-x) < epsilon: 221 |     break 222 | ``` 223 | 224 | Onde `epsilon` tem um valor como 0.0000001, que determina a proximidade desejada entre `x` e `y`. 225 | 226 | ## 7.6 - Algoritmos 227 | 228 | O método de Newton é um exemplo de um algoritmo: um processo mecânico para resolver uma categoria de problemas (neste caso, calcular raízes quadradas). 229 | 230 | Para entender o que é um algoritmo, pode ser útil começar com algo que não é um algoritmo. Quando aprendeu a multiplicar números de um dígito, você provavelmente memorizou a tabuada. Ou seja, você memorizou 100 soluções específicas. Este tipo de conhecimento não é algorítmico. 231 | 232 | No entanto, se você foi “preguiçoso”, poderia ter aprendido alguns truques. Por exemplo, para encontrar o produto de `n` e 9, pode escrever `n-1` como o primeiro dígito e `10-n` como o segundo dígito. Este truque é uma solução geral para multiplicar qualquer número de dígito único por 9. Isto é um algoritmo! 233 | 234 | De forma semelhante, as técnicas que aprendeu, como o transporte na adição, o empréstimo na subtração e a divisão longa são todos algoritmos. Uma das características de algoritmos é que eles não exigem inteligência para serem executados. São processos mecânicos, nos quais cada passo segue a partir do último, de acordo com um conjunto de regras simples. 235 | 236 | A execução de algoritmos é maçante, mas projetá-los é interessante, intelectualmente desafiador e uma parte central da Ciência da Computação. 237 | 238 | Algumas coisas que as pessoas fazem naturalmente, sem dificuldade ou pensamento consciente, são as mais difíceis para exprimir algoritmicamente. A compreensão de linguagem natural é um bom exemplo. Todos nós o fazemos, mas por enquanto ninguém foi capaz de explicar como o fazemos, pelo menos não na forma de um algoritmo. 239 | 240 | ## 7.7 - Depuração 241 | 242 | Ao começar a escrever programas maiores, pode ser que você passe mais tempo depurando. Mais código significa mais possibilidades fazer erros e mais lugares para esconder defeitos. 243 | 244 | Uma forma de cortar o tempo de depuração é “depurar por bisseção”. Por exemplo, se há 100 linhas no seu programa e você as verifica uma a uma, seriam 100 passos a tomar. 245 | 246 | Em vez disso, tente quebrar o problema pela metade. Olhe para o meio do programa, ou perto disso, para um valor intermediário que possa verificar. Acrescente uma instrução print (ou outra coisa que tenha um efeito verificável) e execute o programa. 247 | 248 | Se a verificação do ponto central for incorreta, deve haver um problema na primeira metade do programa. Se for correta, o problema está na segunda metade. 249 | 250 | Cada vez que executar uma verificação assim, divida ao meio o número de linhas a serem verificadas. Depois de seis passos (que é menos de 100), você teria menos de uma ou duas linhas do código para verificar, pelo menos em teoria. 251 | 252 | Na prática, nem sempre é claro o que representa o “meio do programa” e nem sempre é possível verificá-lo. Não faz sentido contar linhas e encontrar o ponto central exato. Em vez disso, pense em lugares no programa onde poderia haver erros e lugares onde é fácil inserir um ponto de verificação. Então escolha um lugar onde as possibilidades são basicamente as mesmas de que o defeito esteja antes ou depois da verificação. 253 | 254 | ## 7.8 - Glossário 255 | 256 |
257 |
reatribuição
258 |
Atribuir um novo valor a uma variável que já existe.
259 | 260 |
atualização
261 |
Uma atribuição onde o novo valor da variável dependa do velho.
262 | 263 |
inicialização
264 |
Uma atribuição que dá um valor inicial a uma variável que será atualizada.
265 | 266 |
incremento
267 |
Uma atualização que aumenta o valor de uma variável (normalmente por uma unidade).
268 | 269 |
decremento
270 |
Uma atualização que reduz o valor de uma variável.
271 | 272 |
iteração
273 |
Execução repetida de um grupo de instruções, usando uma chamada da função recursiva ou um loop.
274 | 275 |
loop infinito
276 |
Um loop no qual a condição de término nunca é satisfeita.
277 | 278 |
algoritmo
279 |
Um processo geral para resolver uma categoria de problemas.
280 | 281 |
282 | 283 | ## 7.9 - Exercícios 284 | 285 | ### Exercício 7.1 286 | 287 | Copie o loop de “Raízes quadradas”, na página 111, e encapsule-o em uma função chamada `mysqrt` que receba a como parâmetro, escolha um valor razoável de x e devolva uma estimativa da raiz quadrada de a. 288 | 289 | Para testar, escreva uma função denominada `test_square_root`, que exibe uma tabela como esta: 290 | 291 | ```python 292 | a   mysqrt(a)     math.sqrt(a)  diff 293 | -   ---------     ------------  ---- 294 | 1.0 1.0           1.0           0.0 295 | 2.0 1.41421356237 1.41421356237 2.22044604925e-16 296 | 3.0 1.73205080757 1.73205080757 0.0 297 | 4.0 2.0           2.0           0.0 298 | 5.0 2.2360679775  2.2360679775  0.0 299 | 6.0 2.44948974278 2.44948974278 0.0 300 | 7.0 2.64575131106 2.64575131106 0.0 301 | 8.0 2.82842712475 2.82842712475 4.4408920985e-16 302 | 9.0 3.0           3.0           0.0 303 | ``` 304 | 305 | A primeira coluna é um número, `a`; a segunda coluna é a raiz quadrada de a calculada com `mysqrt`; a terceira coluna é a raiz quadrada calculada por `math.sqrt`; a quarta coluna é o valor absoluto da diferença entre as duas estimativas. 306 | 307 | ### Exercício 7.2 308 | 309 | A função integrada `eval` toma uma string e a avalia, usando o interpretador do Python. Por exemplo: 310 | 311 | ```python 312 | >>> eval('1 + 2 * 3') 313 | 7 314 | >>> import math 315 | >>> eval('math.sqrt(5)') 316 | 2.2360679774997898 317 | >>> eval('type(math.pi)') 318 | 319 | ``` 320 | 321 | Escreva uma função chamada `eval_loop` que iterativamente peça uma entrada ao usuário, a avalie usando `eval` e exiba o resultado. 322 | 323 | Ela deve continuar até que o usuário digite `done`; então deverá exibir o valor da última expressão avaliada. 324 | 325 | ### Exercício 7.3 326 | 327 | O matemático Srinivasa Ramanujan encontrou uma série infinita que pode ser usada para gerar uma aproximação numérica de 1/π: 328 | 329 | ![Fórmula – Aproximação de π pela série de Ramanujan.](https://github.com/PenseAllen/PensePython2e/raw/master/fig/p83f1.png) 330 | 331 | Escreva uma função chamada `estimate_pi` que use esta fórmula para computar e devolver uma estimativa de π. Você deve usar o loop `while` para calcular os termos da adição até que o último termo seja menor que 1e-15 (que é a notação do Python para `10 ** 15`). Você pode verificar o resultado comparando-o com `math.pi`. 332 | -------------------------------------------------------------------------------- /docs/09-caso-palavras.md: -------------------------------------------------------------------------------- 1 | # Capítulo 9: Estudo de caso: jogos de palavras 2 | 3 | Este capítulo apresenta o segundo estudo de caso que envolve solucionar quebra-cabeças usando palavras com certas propriedades. Por exemplo, encontraremos os palíndromos mais longos em inglês e procuraremos palavras cujas letras apareçam em ordem alfabética. E apresentarei outro plano de desenvolvimento de programa: a redução a um problema resolvido anteriormente. 4 | 5 | ## 9.1 - Leitura de listas de palavras 6 | 7 | Para os exercícios deste capítulo vamos usar uma lista de palavras em inglês. Há muitas listas de palavras disponíveis na internet, mas a mais conveniente ao nosso propósito é uma das listas de palavras disponibilizadas em domínio público por Grady Ward como parte do projeto lexical Moby (ver http://wikipedia.org/wiki/Moby\_Project). É uma lista de 113.809 palavras cruzadas oficiais; isto é, as palavras que se consideram válidas em quebra-cabeças de palavras cruzadas e outros jogos de palavras. Na coleção Moby, o nome do arquivo é 113809of.fic; você pode baixar uma cópia, com um nome mais simples como words.txt, de http://thinkpython2.com/code/words.txt. 8 | 9 | Este arquivo está em texto simples, então você pode abri-lo com um editor de texto, mas também pode lê-lo no Python. A função integrada open recebe o nome do arquivo como um parâmetro e retorna um objeto de arquivo que você pode usar para ler o arquivo. 10 | 11 | ```python 12 | >>> fin = open('words.txt') 13 | ``` 14 | 15 | `fin` é um nome comum de objeto de arquivo usado para entrada de dados. O objeto de arquivo oferece vários métodos de leitura, inclusive readline, que lê caracteres no arquivo até chegar a um comando de nova linha, devolvendo o resultado como uma string: 16 | 17 | ```python 18 | >>> fin.readline() 19 | 'aa\r\n' 20 | ``` 21 | 22 | A primeira palavra nesta lista específica é “aa”, uma espécie de lava. A sequência `'\r\n'` representa dois caracteres que representam espaços em branco (whitespace), um retorno de carro e uma nova linha, que separa esta palavra da seguinte. 23 | 24 | O objeto de arquivo grava a posição em que está no arquivo, então se você chamar readline mais uma vez, receberá a seguinte palavra: 25 | 26 | ```python 27 | >>> fin.readline() 28 | 'aah\r\n' 29 | ``` 30 | 31 | A palavra seguinte é “aah”, uma palavra perfeitamente legítima, então pare de olhar para mim desse jeito. Ou, se é o whitespace que está incomodando você, podemos nos livrar dele com o método de string `strip`: 32 | 33 | ```python 34 | >>> line = fin.readline() 35 | >>> word = line.strip() 36 | >>> word 37 | 'aahed' 38 | ``` 39 | 40 | Você também pode usar um objeto de arquivo como parte de um loop `for`. Este programa lê words.txt e imprime cada palavra, uma por linha: 41 | 42 | ```python 43 | fin = open('words.txt') 44 | for line in fin: 45 |     word = line.strip() 46 |     print(word) 47 | ``` 48 | 49 | ## 9.2 - Exercícios 50 | 51 | Há soluções para estes exercícios na próxima seção. Mas é bom você tentar fazer cada um antes de ver as soluções. 52 | 53 | ### Exercício 9.1 54 | 55 | Escreva um programa que leia words.txt e imprima apenas as palavras com mais de 20 caracteres (sem contar whitespace). 56 | 57 | ### Exercício 9.2 58 | 59 | Em 1939, Ernest Vincent Wright publicou uma novela de 50.000 palavras, chamada Gadsby, que não contém a letra “e”. Como o “e” é a letra mais comum em inglês, isso não é algo fácil de fazer. 60 | 61 | Na verdade, é difícil até construir um único pensamento sem usar o símbolo mais comum do idioma. No início é lento, mas com prudência e horas de treino, vai ficando cada vez mais fácil. 62 | 63 | ```python 64 | Muito bem, agora eu vou parar. 65 | ``` 66 | 67 | Escreva uma função chamada `has_no_e` que retorne `True` se a palavra dada não tiver a letra “e” nela. 68 | 69 | Altere seu programa na seção anterior para imprimir apenas as palavras que não têm “e” e calcule a porcentagem de palavras na lista que não têm “e”. 70 | 71 | ### Exercício 9.3 72 | 73 | Escreva uma função chamada avoids que receba uma palavra e uma série de letras proibidas, e retorne True se a palavra não usar nenhuma das letras proibidas. 74 | 75 | Altere o código para que o usuário digite uma série de letras proibidas e o programa imprima o número de palavras que não contêm nenhuma delas. Você pode encontrar uma combinação de cinco letras proibidas que exclua o menor número possível de palavras? 76 | 77 | ### Exercício 9.4 78 | 79 | Escreva uma função chamada `uses_only` que receba uma palavra e uma série de letras e retorne `True`, se a palavra só contiver letras da lista. Você pode fazer uma frase usando só as letras acefhlo? Que não seja “Hoe alfalfa?” 80 | 81 | ### Exercício 9.5 82 | 83 | Escreva uma função chamada `uses_all` que receba uma palavra e uma série de letras obrigatórias e retorne `True` se a palavra usar todas as letras obrigatórias pelo menos uma vez. Quantas palavras usam todas as vogais (aeiou)? E que tal aeiouy? 84 | 85 | ### Exercício 9.6 86 | 87 | Escreva uma função chamada `is_abecedarian` que retorne `True` se as letras numa palavra aparecerem em ordem alfabética (tudo bem se houver letras duplas). Quantas palavras em ordem alfabética existem? 88 | 89 | ## 9.3 - Busca 90 | 91 | Todos os exercícios na seção anterior têm algo em comum; eles podem ser resolvidos com o modelo de busca que vimos em [Buscando](./08-strings.md#86---buscando). O exemplo mais simples é: 92 | 93 | ```python 94 | def has_no_e(word): 95 |     for letter in word: 96 |         if letter == 'e': 97 |             return False 98 |     return True 99 | ``` 100 | 101 | O loop for atravessa os caracteres em word. Se encontrarmos a letra “e”, podemos retornar False imediatamente; se não for o caso, temos que ir à letra seguinte. Se sairmos do loop normalmente, isso quer dizer que não encontramos um “e”, então retornamos True. 102 | 103 | Você pode escrever esta função de forma mais concisa usando o operador in, mas comecei com esta versão porque ela demonstra a lógica do modelo de busca. 104 | 105 | `avoids` é uma versão mais geral de `has_no_e`, mas tem a mesma estrutura: 106 | 107 | 108 | ```python 109 | def avoids(word, forbidden): 110 |     for letter in word: 111 |         if letter in forbidden: 112 |             return False 113 |     return True 114 | ``` 115 | 116 | Podemos retornar `False` logo que encontrarmos uma letra proibida; se chegarmos ao fim do loop, retornamos `True`. 117 | 118 | `uses_only` é semelhante, exceto pelo sentido da condição, que se inverte: 119 | 120 | ```python 121 | def uses_only(word, available): 122 |     for letter in word: 123 |         if letter not in available: 124 |             return False 125 |     return True 126 | ``` 127 | 128 | Em vez de uma lista de letras proibidas, temos uma lista de letras disponíveis. Se encontrarmos uma letra em word que não está em `available`, podemos retornar `False`. 129 | 130 | `uses_all` é semelhante, mas invertemos a função da palavra e a string de letras: 131 | 132 | ```python 133 | def uses_all(word, required): 134 |     for letter in required: 135 |         if letter not in word: 136 |             return False 137 |     return True 138 | ``` 139 | 140 | Em vez de atravessar as letras em `word`, o loop atravessa as letras obrigatórias. Se alguma das letras obrigatórias não aparecer na palavra, podemos retornar `False`. 141 | 142 | Se você realmente estivesse pensando como um cientista da computação, teria reconhecido que `uses_all` foi um exemplo de um problema resolvido anteriormente e escreveria: 143 | 144 | ```python 145 | def uses_all(word, required): 146 |     return uses_only(required, word) 147 | ``` 148 | 149 | Esse é um exemplo de um plano de desenvolvimento de programa chamado __redução a um problema resolvido anteriormente__, ou seja, você reconhece o problema no qual está trabalhando como um exemplo de um problema já resolvido e aplica uma solução existente. 150 | 151 | ## 9.4 - Loop com índices 152 | 153 | Escrevi as funções na seção anterior com loops `for` porque eu só precisava dos caracteres nas strings; não precisava fazer nada com os índices. 154 | 155 | Para `is_abecedarian` temos que comparar letras adjacentes, o que é um pouco complicado para o loop for: 156 | 157 | ```python 158 | def is_abecedarian(word): 159 |     previous = word[0] 160 |     for c in word: 161 |         if c < previous: 162 |             return False 163 |         previous = c 164 |     return True 165 | ``` 166 | 167 | Uma alternativa é usar a recursividade: 168 | 169 | ```python 170 | def is_abecedarian(word): 171 |     if len(word) <= 1: 172 |         return True 173 |     if word[0] > word[1]: 174 |         return False 175 |     return is_abecedarian(word[1:]) 176 | ``` 177 | 178 | Outra opção é usar um loop `while`: 179 | 180 | ```python 181 | def is_abecedarian(word): 182 |     i = 0 183 |     while i < len(word)-1: 184 |         if word[i+1] < word[i]: 185 |             return False 186 |         i = i+1 187 |     return True 188 | ``` 189 | 190 | O loop começa com `i == 0` e termina quando `i == len(word)-1`. Cada vez que passa pelo loop, o programa compara o “i-ésimo” caractere (que você pode considerar o caractere atual) com o caractere de posição `i+1` (que pode ser considerado o caractere seguinte). 191 | 192 | Se o próximo caractere for de uma posição anterior (alfabeticamente anterior) à atual, então descobrimos uma quebra na tendência alfabética, e retornamos `False`. 193 | 194 | Se chegarmos ao fim do loop sem encontrar uma quebra, então a palavra passa no teste. Para convencer-se de que o loop termina corretamente, considere um exemplo como `'flossy'`. O comprimento da palavra é 6, então o loop é executado pela última vez quando i for igual a 4, que é o índice do segundo caractere de trás para frente. Na última iteração, o programa compara o penúltimo caractere com o último, que é o que queremos. 195 | 196 | Aqui está uma versão de `is_palindrome` (veja o Exercício 6.3) que usa dois índices: um começa no início e aumenta; o outro começa no final e diminui. 197 | 198 | ```python 199 | def is_palindrome(word): 200 |     i = 0 201 |     j = len(word)-1 202 |     while i 237 |
objeto de arquivo
238 |
Um valor que representa um arquivo aberto.
239 | 240 |
redução a um problema resolvido anteriormente
241 |
Um modo de resolver um problema expressando-o como uma instância de um problema resolvido anteriormente.
242 | 243 |
caso especial
244 |
Um caso de teste que é atípico ou não é óbvio (e com probabilidade menor de ser tratado corretamente).
245 | 246 | 247 | 248 | ## 9.7 - Exercícios 249 | 250 | ### Exercício 9.7 251 | 252 | Esta pergunta é baseada em um quebra-cabeça veiculado em um programa de rádio chamado Car Talk (http://www.cartalk.com/content/puzzlers): 253 | 254 | Dê uma palavra com três letras duplas consecutivas. Vou dar exemplos de palavras que quase cumprem a condição, mas não chegam lá. Por exemplo, a palavra committee, c-o-m-m-i-t-t-e-e. Seria perfeita se não fosse aquele ‘i’ que se meteu ali no meio. Ou Mississippi: M-i-s-s-i-s-s-i-p-p-i. Se pudesse tirar aqueles ‘is’, daria certo. Mas há uma palavra que tem três pares consecutivos de letras e, que eu saiba, pode ser a única palavra que existe. É claro que provavelmente haja mais umas 500, mas só consigo pensar nessa. Qual é a palavra? 255 | 256 | Escreva um programa que a encontre. 257 | 258 | Solução: http://thinkpython2.com/code/cartalk1.py. 259 | 260 | ### Exercício 9.8 261 | 262 | Aqui está outro quebra-cabeça do programa Car Talk (http://www.cartalk.com/content/puzzlers): 263 | 264 | “Estava dirigindo outro dia e percebi algo no hodômetro que chamou a minha atenção. Como a maior parte dos hodômetros, ele mostra seis dígitos, apenas em milhas inteiras. Por exemplo, se o meu carro tivesse 300.000 milhas, eu veria 3-0-0-0-0-0. 265 | 266 | “Agora, o que vi naquele dia foi muito interessante. Notei que os últimos 4 dígitos eram um palíndromo; isto é, podiam ser lidos da mesma forma no sentido correto e no sentido inverso. Por exemplo, 5-4-4-5 é um palíndromo, então no meu hodômetro poderia ser 3-1-5-4-4-5. 267 | 268 | “Uma milha depois, os últimos 5 números formaram um palíndromo. Por exemplo, poderia ser 3-6-5-4-5-6. Uma milha depois disso, os 4 números do meio, dentro dos 6, formavam um palíndromo. E adivinhe só? Um milha depois, todos os 6 formavam um palíndromo! 269 | 270 | “A pergunta é: o que estava no hodômetro quando olhei primeiro?” 271 | 272 | Escreva um programa Python que teste todos os números de seis dígitos e imprima qualquer número que satisfaça essas condições. 273 | 274 | Solução: http://thinkpython2.com/code/cartalk2.py. 275 | 276 | ### Exercício 9.9 277 | 278 | Aqui está outro problema do Car Talk que você pode resolver com uma busca (http://www.cartalk.com/content/puzzlers): 279 | 280 | “Há pouco tempo recebi uma visita da minha mãe e percebemos que os dois dígitos que compõem a minha idade, quando invertidos, representavam a idade dela. Por exemplo, se ela tem 73 anos, eu tenho 37 anos. Ficamos imaginando com que frequência isto aconteceu nos anos anteriores, mas acabamos mudando de assunto e não chegamos a uma resposta. 281 | 282 | “Quando cheguei em casa, cheguei à conclusão de que os dígitos das nossas idades tinham sido reversíveis seis vezes até então. Também percebi que, se tivéssemos sorte, isso aconteceria novamente dali a alguns anos, e se fôssemos muito sortudos, aconteceria mais uma vez depois disso. Em outras palavras, aconteceria 8 vezes no total. Então a pergunta é: quantos anos tenho agora?” 283 | 284 | Escreva um programa em Python que busque soluções para esse problema. Dica: pode ser uma boa ideia usar o método de string zfill. 285 | -------------------------------------------------------------------------------- /docs/15-classes-objetos.md: -------------------------------------------------------------------------------- 1 | # Capítulo 15: Classes e objetos 2 | 3 | A esta altura você já sabe como usar funções para organizar código e tipos integrados para organizar dados. O próximo passo é aprender “programação orientada a objeto”, que usa tipos definidos pelos programadores para organizar tanto o código quanto os dados. A programação orientada a objeto é um tópico abrangente; será preciso passar por alguns capítulos para abordar o tema. 4 | 5 | Os exemplos de código deste capítulo estão disponíveis em http://thinkpython2.com/code/Point1.py; as soluções para os exercícios estão disponíveis em http://thinkpython2.com/code/Point1_soln.py. 6 | 7 | ## 15.1 - Tipos definidos pelos programadores 8 | 9 | Já usamos muitos tipos integrados do Python; agora vamos definir um tipo próprio. Como exemplo, criaremos um tipo chamado `Point`, que representa um ponto no espaço bidimensional. 10 | 11 | Na notação matemática, os pontos muitas vezes são escritos entre parênteses, com uma vírgula separando as coordenadas. Por exemplo, (0,0) representa a origem e (x, y) representa o ponto que está x unidades à direita e y unidades acima da origem. 12 | 13 | Há várias formas para representar pontos no Python: 14 | 15 | * Podemos armazenar as coordenadas separadamente em duas variáveis, x e y. 16 | 17 | * Podemos armazenar as coordenadas como elementos em uma lista ou tupla. 18 | 19 | * Podemos criar um tipo para representar pontos como objetos. 20 | 21 | Criar um tipo é mais complicado que outras opções, mas tem vantagens que logo ficarão evidentes. 22 | 23 | Um tipo definido pelo programador também é chamado de classe. Uma definição de classe pode ser assim: 24 | 25 | ```python 26 | class Point: 27 |     """Represents a point in 2-D space.""" 28 | ``` 29 | 30 | O cabeçalho indica que a nova classe se chama `Point`. O corpo é uma docstring que explica para que a classe serve. Você pode definir variáveis e métodos dentro de uma definição de classe, mas voltaremos a isso depois. 31 | 32 | Definir uma classe denominada `Point` cria um objeto de classe: 33 | 34 | ```python 35 | >>> Point 36 | 37 | ``` 38 | 39 | Como `Point` é definido no nível superior, seu “nome completo” é `__main__.Point`. 40 | 41 | O objeto de classe é como uma fábrica para criar objetos. Para criar um `Point`, você chama `Point` como se fosse uma função: 42 | 43 | 44 | ```python 45 | >>> blank = Point() 46 | >>> blank 47 | <__main__.Point object at 0xb7e9d3ac> 48 | ``` 49 | 50 | O valor de retorno é uma referência a um objeto `Point`, ao qual atribuímos blank. 51 | 52 | Criar um objeto chama-se instanciação, e o objeto é uma instância da classe. 53 | 54 | Quando você exibe uma instância, o Python diz a que classe ela pertence e onde está armazenada na memória (o prefixo o 0x significa que o número seguinte está em formato hexadecimal). 55 | 56 | Cada objeto é uma instância de alguma classe, então “objeto” e “instância” são intercambiáveis. Porém, neste capítulo uso “instância” para indicar que estou falando sobre um tipo definido pelo programador. 57 | 58 | ## 15.2 - Atributos 59 | 60 | Você pode atribuir valores a uma instância usando a notação de ponto: 61 | 62 | ```python 63 | >>> blank.x = 3.0 64 | >>> blank.y = 4.0 65 | ``` 66 | 67 | Essa sintaxe é semelhante à usada para selecionar uma variável de um módulo, como math.pi ou string.whitespace. Nesse caso, entretanto, estamos atribuindo valores a elementos nomeados de um objeto. Esses elementos chamam-se atributos. 68 | 69 | Em inglês, quando é um substantivo, a palavra “AT-trib-ute” é pronunciada com ênfase na primeira sílaba, ao contrário de “a-TRIB-ute”, que é um verbo. 70 | 71 | O diagrama seguinte mostra o resultado dessas atribuições. Um diagrama de estado que mostra um objeto e seus atributos chama-se diagrama de objeto; veja a Figura 15.1. 72 | 73 | ![Figura 15.1 – Diagrama de um objeto Point.](https://github.com/PenseAllen/PensePython2e/raw/master/fig/tnkp_1501.png) 74 |
_Figura 15.1 – Diagrama de um objeto_ `Point`. 75 | 76 | A variável blank refere-se a um objeto `Point`, que contém dois atributos. Cada atributo refere-se a um número de ponto flutuante. 77 | 78 | Você pode ler o valor de um atributo usando a mesma sintaxe: 79 | 80 | ```python 81 | >>> blank.y 82 | 4.0 83 | >>> x = blank.x 84 | >>> x 85 | 3.0 86 | ``` 87 | 88 | A expressão `blank.x` significa “Vá ao objeto a que blank se refere e pegue o valor de x”. No exemplo, atribuímos este valor a uma variável `x`. Não há nenhum conflito entre a variável `x` e o atributo `x`. 89 | 90 | Você pode usar a notação de ponto como parte de qualquer expressão. Por exemplo: 91 | 92 | ```python 93 | >>> '(%g, %g)' % (blank.x, blank.y) 94 | '(3.0, 4.0)' 95 | >>> distance = math.sqrt(blank.x ** 2 + blank.y ** 2) 96 | >>> distance 97 | 5.0 98 | ``` 99 | 100 | Você pode passar uma instância como argumento da forma habitual. Por exemplo: 101 | 102 | ```python 103 | def print_point(p): 104 |     print('(%g, %g)' % (p.x, p.y)) 105 | ``` 106 | 107 | `print_point` toma um ponto como argumento e o exibe em notação matemática. Para invocá-lo, você pode passar `blank` como argumento: 108 | 109 | ```python 110 | >>> print_point(blank) 111 | (3.0, 4.0) 112 | ``` 113 | 114 | Dentro da função, `p` é um alias para `blank`, então, se a função altera `p`, `blank` também muda. 115 | 116 | Como exercício, escreva uma função chamada `distance_between_points`, que toma dois pontos como argumentos e retorna a distância entre eles. 117 | 118 | ## 15.3 - Retângulos 119 | 120 | Às vezes, é óbvio quais deveriam ser os atributos de um objeto, mas outras é preciso decidir entre as possibilidades. Por exemplo, vamos supor que você esteja criando uma classe para representar retângulos. Que atributos usaria para especificar a posição e o tamanho de um retângulo? Você pode ignorar ângulo; para manter as coisas simples, suponha que o retângulo seja vertical ou horizontal. 121 | 122 | Há duas possibilidades, no mínimo: 123 | 124 | * Você pode especificar um canto do retângulo (ou o centro), a largura e a altura. 125 | 126 | * Você pode especificar dois cantos opostos. 127 | 128 | Nesse ponto é difícil dizer qual opção é melhor, então implementaremos a primeira, como exemplo. 129 | 130 | Aqui está a definição de classe: 131 | 132 | ```python 133 | class Rectangle: 134 |     """Represents a rectangle. 135 |     attributes: width, height, corner. 136 |     """ 137 | ``` 138 | 139 | A docstring lista os atributos: width e height são números; corner é um objeto `Point` que especifica o canto inferior esquerdo. 140 | 141 | Para representar um retângulo, você tem que instanciar um objeto `Rectangle` e atribuir valores aos atributos: 142 | 143 | ```python 144 | box = Rectangle() 145 | box.width = 100.0 146 | box.height = 200.0 147 | box.corner = Point() 148 | box.corner.x = 0.0 149 | box.corner.y = 0.0 150 | ``` 151 | 152 | A expressão `box.corner.x` significa “Vá ao objeto ao qual `box` se refere e pegue o atributo denominado `corner`; então vá a este objeto e pegue o atributo denominado `x`”. 153 | 154 | A Figura 15.2 mostra o estado deste objeto. Um objeto que é um atributo de outro objeto é integrado. 155 | 156 | A Figura 10.1 mostra o diagrama de estado para cheeses, numbers e empty. 157 | 158 | ![Figura 15.2 – Diagrama de um objeto Rectangle.](https://github.com/PenseAllen/PensePython2e/raw/master/fig/tnkp_1502.png) 159 |
_Figura 15.2 – Diagrama de um objeto_ `Rectangle`. 160 | 161 | 162 | ## 15.4 - Instâncias como valores de retorno 163 | 164 | As funções podem retornar instâncias. Por exemplo, `find_center` recebe um `Rectangle` como argumento e devolve um `Point`, que contém as coordenadas do centro do retângulo: 165 | 166 | ```python 167 | def find_center(rect): 168 |     p = Point() 169 |     p.x = rect.corner.x + rect.width/2 170 |     p.y = rect.corner.y + rect.height/2 171 |     return p 172 | ``` 173 | 174 | Aqui está um exemplo que passa `box` como um argumento para `find_center` e atribui o `ponto` resultante à variável `center`: 175 | 176 | ```python 177 | >>> center = find_center(box) 178 | >>> print_point(center) 179 | (50, 100) 180 | ``` 181 | 182 | ## 15.5 - Objetos são mutáveis 183 | 184 | Você pode alterar o estado de um objeto fazendo uma atribuição a um dos seus atributos. Por exemplo, para mudar o tamanho de um retângulo sem mudar sua posição, você pode alterar os valores de width e height: 185 | 186 | ```python 187 | box.width = box.width + 50 188 | box.height = box.height + 100 189 | ``` 190 | 191 | Você também pode escrever funções que alteram objetos. Por exemplo, `grow_rectangle` recebe um objeto `Rectangle` e dois números, `dwidth` e `dheight`, e adiciona os números à largura e altura do retângulo: 192 | 193 | ```python 194 | def grow_rectangle(rect, dwidth, dheight): 195 |     rect.width += dwidth 196 |     rect.height += dheight 197 | ``` 198 | 199 | Eis um exemplo que demonstra o efeito: 200 | 201 | ```python 202 | >>> box.width, box.height 203 | (150.0, 300.0) 204 | >>> grow_rectangle(box, 50, 100) 205 | >>> box.width, box.height 206 | (200.0, 400.0) 207 | ``` 208 | 209 | Dentro da função, `rect` é um alias de `box`, então quando a função altera `rect`, `box` aponta para o objeto alterado. 210 | 211 | Como exercício, escreva uma função chamada `move_rectangle` que toma um Rectangle e dois números chamados dx e dy. Ela deve alterar a posição do retângulo, adicionando dx à coordenada x de corner e adicionando dy à coordenada y de corner. 212 | 213 | ## 15.6 - Cópia 214 | 215 | Alias podem tornar um programa difícil de ler porque as alterações em um lugar podem ter efeitos inesperados em outro lugar. É difícil monitorar todas as variáveis que podem referir-se a um dado objeto. 216 | 217 | Em vez de usar alias, copiar o objeto pode ser uma alternativa. O módulo `copy` contém uma função chamada `copy` que pode duplicar qualquer objeto: 218 | 219 | ```python 220 | >>> p1 = Point() 221 | >>> p1.x = 3.0 222 | >>> p1.y = 4.0 223 | >>> import copy 224 | >>> p2 = copy.copy(p1) 225 | ``` 226 | 227 | `p1` e `p2` contêm os mesmos dados, mas não são o mesmo `Point`: 228 | 229 | ```python 230 | >>> print_point(p1) 231 | (3, 4) 232 | >>> print_point(p2) 233 | (3, 4) 234 | >>> p1 is p2 235 | False 236 | >>> p1 == p2 237 | False 238 | ``` 239 | 240 | O operador `is` indica que `p1` e `p2` não são o mesmo objeto, que é o que esperamos. Porém, você poderia ter esperado que `==` fosse apresentado como `True`, porque esses pontos contêm os mesmos dados. Nesse caso, pode ficar desapontado ao saber que, para instâncias, o comportamento padrão do operador `==` é o mesmo que o do operador `is`; ele verifica a identidade dos objetos, não a sua equivalência. Isso acontece porque, para tipos definidos pelo programador, o Python não sabe o que deve ser considerado equivalente. Pelo menos, ainda não. 241 | 242 | Se você usar `copy.copy` para duplicar um retângulo, descobrirá que ele copia o objeto `Rectangle`, mas não o `Point` embutido nele: 243 | 244 | ```python 245 | >>> box2 = copy.copy(box) 246 | >>> box2 is box 247 | False 248 | >>> box2.corner is box.corner 249 | True 250 | ``` 251 | 252 | A Figura 15.3 mostra como fica o diagrama de objeto. Esta operação chama-se cópia superficial porque copia o objeto e qualquer referência que contenha, mas não os objetos integrados. 253 | 254 | ![Figura 15.3 – Diagrama: dois objetos Rectangle compartilhando o mesmo Point.](https://github.com/PenseAllen/PensePython2e/raw/master/fig/tnkp_1503.png) 255 |
_Figura 15.3 – Diagrama: dois objetos_ `Rectangle` _compartilhando o mesmo_ `Point`. 256 | 257 | Para a maior parte das aplicações, não é isso que você quer. Nesse exemplo, invocar `grow_rectangle` em um dos Rectangles não afetaria o outro, mas invocar `move_rectangle` em qualquer um deles afetaria a ambos! Esse comportamento é confuso e propenso a erros. 258 | 259 | Felizmente, o módulo `copy` oferece um método chamado `deepcopy` que copia não só o objeto, mas também os objetos aos quais ele se refere, e os objetos aos quais estes se referem, e assim por diante. Você não se surpreenderá ao descobrir que esta operação se chama cópia profunda. 260 | 261 | ```python 262 | >>> box3 = copy.deepcopy(box) 263 | >>> box3 is box 264 | False 265 | >>> box3.corner is box.corner 266 | False 267 | box3 e box são objetos completamente separados. 268 | ``` 269 | 270 | Como exercício, escreva uma versão de `move_rectangle` que cria e retorne um novo retângulo em vez de alterar o antigo. 271 | 272 | ## 15.7 - Depuração 273 | 274 | Ao começar a trabalhar com objetos, provavelmente você encontrará algumas novas exceções. Se tentar acessar um atributo que não existe, recebe um `AttributeError`: 275 | 276 | ```python 277 | >>> p = Point() 278 | >>> p.x = 3 279 | >>> p.y = 4 280 | >>> p.z 281 | AttributeError: Point instance has no attribute 'z' 282 | ``` 283 | 284 | Se não estiver certo sobre o tipo que um objeto é, pode perguntar: 285 | 286 | ```python 287 | >>> type(p) 288 | 289 | ``` 290 | 291 | Você também pode usar `isinstance` para verificar se um objeto é uma instância de uma classe: 292 | 293 | ```python 294 | >>> isinstance(p, Point) 295 | True 296 | ``` 297 | 298 | Caso não tenha certeza se um objeto tem determinado atributo, você pode usar a função integrada `hasattr`: 299 | 300 | ```python 301 | >>> hasattr(p, 'x') 302 | True 303 | >>> hasattr(p, 'z') 304 | False 305 | ``` 306 | 307 | O primeiro argumento pode ser qualquer objeto; o segundo argumento é uma `string` com o nome do atributo. 308 | 309 | Você também pode usar uma instrução `try` para ver se o objeto tem os atributos de que precisa: 310 | 311 | 312 | ```python 313 | try: 314 |     x = p.x 315 | except AttributeError: 316 |     x = 0 317 | ``` 318 | 319 | Essa abordagem pode facilitar a escrita de funções que atuam com tipos diferentes; você verá mais informações sobre isso em “Polimorfismo”, na página 248. 320 | 321 | ## 15.8 - Glossário 322 | 323 |
324 |
classe
325 |
Tipo definido pelo programador. Uma definição de classe cria um objeto de classe.
326 | 327 |
objeto de classe
328 |
Objeto que contém a informação sobre um tipo definido pelo programador. O objeto de classe pode ser usado para criar instâncias do tipo.
329 | 330 |
instância
331 |
Objeto que pertence a uma classe.
332 | 333 |
instanciar
334 |
Criar um objeto.
335 | 336 |
atributo
337 |
Um dos valores denominados associados a um objeto.
338 | 339 |
objeto integrado
340 |
Objeto que é armazenado como um atributo de outro objeto.
341 | 342 |
cópia superficial
343 |
Copiar o conteúdo de um objeto, inclusive qualquer referência a objetos integrados; implementada pela função copy no módulo copy.
344 | 345 |
cópia profunda
346 |
Copiar o conteúdo de um objeto, bem como qualquer objeto integrado, e qualquer objeto integrado a estes, e assim por diante; implementado pela função deepcopy no módulo copy.
347 | 348 |
diagrama de objeto
349 |
Diagrama que mostra objetos, seus atributos e os valores dos atributos.
350 | 351 |
352 | 353 | ## 15.9 - Exercícios 354 | 355 | ### Exercício 15.1 356 | 357 | 1. Escreva uma definição para uma classe denominada `Circle`, com os atributos center e radius, onde center é um objeto `Point` e radius é um número. 358 | 359 | 2. Instancie um objeto `Circle`, que represente um círculo com o centro em 150, 100 e raio 75. 360 | 361 | 3. Escreva uma função denominada `point_in_circle`, que tome um `Circle` e um `Point` e retorne `True`, se o ponto estiver dentro ou no limite do círculo. 362 | 363 | 4. Escreva uma função chamada `rect_in_circle`, que tome um `Circle` e um Rectangle e retorne `True`, se o retângulo estiver totalmente dentro ou no limite do círculo. 364 | 365 | 5. Escreva uma função denominada `rect_circle_overlap`, que tome um `Circle` e um Rectangle e retorne `True`, se algum dos cantos do retângulo cair dentro do círculo. Ou, em uma versão mais desafiadora, retorne `True` se alguma parte do retângulo cair dentro do círculo. 366 | 367 | Solução: http://thinkpython2.com/code/Circle.py. 368 | 369 | ### Exercício 15.2 370 | 371 | 1. Escreva uma função chamada `draw_rect` que receba um objeto `Turtle` e um `Rectangle` e use o `Turtle` para desenhar o retângulo. Veja no Capítulo 4 os exemplos de uso de objetos `Turtle`. 372 | 373 | 2. Escreva uma função chamada `draw_circle`, que tome um Turtle e um `Circle` e desenhe o círculo. 374 | -------------------------------------------------------------------------------- /docs/16-classes-funcoes.md: -------------------------------------------------------------------------------- 1 | # Capítulo 16: Classes e funções 2 | 3 | Agora que sabemos como criar tipos, o próximo passo deve ser escrever funções que recebam objetos definidos pelo programador como parâmetros e os retornem como resultados. Neste capítulo também vou apresentar o “estilo funcional de programação” e dois novos planos de desenvolvimento de programas. 4 | 5 | Os exemplos de código deste capítulo estão disponíveis em http://thinkpython2.com/code/Time1.py. As soluções para os exercícios estão em http://thinkpython2.com/code/Time1\_soln.py. 6 | 7 | ## 16.1 - Time 8 | 9 | Para ter mais um exemplo de tipo definido pelo programador, criaremos uma classe chamada `Time` (hora), que registra um horário no dia. A definição da classe é assim: 10 | 11 | 12 | ```python 13 | class Time: 14 |     """Represents the time of day. 15 |     attributes: hour, minute, second 16 |     """ 17 | ``` 18 | 19 | Podemos criar um objeto `Time` e ter atributos para horas, minutos e segundos: 20 | 21 | ```python 22 | time = Time() 23 | time.hour = 11 24 | time.minute = 59 25 | time.second = 30 26 | ``` 27 | 28 | O diagrama de estado do objeto Time está na Figura 16.1. 29 | 30 | ![Figura 16.1 – Diagrama de um objeto Time.](https://github.com/PenseAllen/PensePython2e/raw/master/fig/tnkp_1601.png) 31 |
_Figura 16.1 – Diagrama de um objeto_ `Time`. 32 | 33 | Como exercício, escreva uma função chamada `print_time`, que receba um objeto Time e o exiba na forma hour:minute:second. Dica: a sequência de formatação `'%.2d'` exibe um número inteiro com, pelo menos, dois dígitos, incluindo um zero à esquerda, se for necessário. 34 | 35 | Escreva uma função booleana chamada `is_after`, que receba dois objetos Time, `t1` e `t2`, e devolva `True` se `t1` for cronologicamente depois de `t2` e `False` se não for. Desafio: não use uma instrução `if`. 36 | 37 | ## 16.2 - Funções puras 38 | 39 | Nas próximas seções, vamos escrever duas funções que adicionam valores de tempo. Elas demonstram dois tipos de funções: funções puras e modificadores. Também demonstram um plano de desenvolvimento que chamarei de protótipo e correção, que é uma forma de atacar um problema complexo começando com um protótipo simples e lidando com as complicações de forma incremental. 40 | 41 | Aqui está um protótipo simples de `add_time`: 42 | 43 | ```python 44 | def add_time(t1, t2): 45 |     sum = Time() 46 |     sum.hour = t1.hour + t2.hour 47 |     sum.minute = t1.minute + t2.minute 48 |     sum.second = t1.second + t2.second 49 |     return sum 50 | ``` 51 | 52 | A função cria um novo objeto `Time`, inicializa seus atributos e retorna uma referência ao novo objeto. A função pura é chamada assim porque não altera nenhum dos objetos passados a ela como argumentos; além disso, ela não tem efeitos, como exibir um valor ou receber entradas de usuário, apenas retorna um valor. 53 | 54 | Para testar esta função, criarei objetos `Time`: `start`, que contém o tempo de início de um filme, como _Monty Python e o cálice sagrado_, e `duration`, que contém o tempo de execução do filme, que é de 1 hora e 35 minutos. 55 | 56 | `add_time` calcula quando o filme acaba: 57 | 58 | ```python 59 | >>> start = Time() 60 | >>> start.hour = 9 61 | >>> start.minute = 45 62 | >>> start.second = 0 63 | >>> duration = Time() 64 | >>> duration.hour = 1 65 | >>> duration.minute = 35 66 | >>> duration.second = 0 67 | >>> done = add_time(start, duration) 68 | >>> print_time(done) 69 | 10:80:00 70 | ``` 71 | 72 | O resultado, 10:80:00, pode não ser o que você esperava. O problema é que esta função não trata casos onde o número de segundos ou minutos é maior que 60. Quando isso acontece, precisamos transportar os segundos extras à coluna dos minutos ou os minutos extras à coluna das horas. 73 | 74 | Aqui está uma versão melhorada: 75 | 76 | ```python 77 | def add_time(t1, t2): 78 |     sum = Time() 79 |     sum.hour = t1.hour + t2.hour 80 |     sum.minute = t1.minute + t2.minute 81 |     sum.second = t1.second + t2.second 82 |     if sum.second >= 60: 83 |         sum.second -= 60 84 |         sum.minute += 1 85 |     if sum.minute >= 60: 86 |         sum.minute -= 60 87 |         sum.hour += 1 88 |     return sum 89 | ``` 90 | 91 | Embora esta função esteja correta, é um pouco extensa. Veremos uma alternativa menor mais adiante. 92 | 93 | ## 16.3 - Modificadores 94 | 95 | Às vezes é útil uma função alterar os objetos que recebe como parâmetros. Nesse caso, as mudanças são visíveis a quem chama a função. As funções que fazem isso chamam-se modificadores. 96 | 97 | `increment`, que acrescenta um dado número de segundos a um objeto `Time`, pode ser escrita naturalmente como um modificador. Aqui está um primeiro esboço: 98 | 99 | ```python 100 | def increment(time, seconds): 101 |     time.second += seconds 102 |     if time.second >= 60: 103 |         time.second -= 60 104 |         time.minute += 1 105 |     if time.minute >= 60: 106 |         time.minute -= 60 107 |         time.hour += 1 108 | ``` 109 | 110 | A primeira linha executa a operação básica; o resto lida com os casos especiais que vimos antes. 111 | 112 | Esta função está correta? O que acontece se `second` for muito mais que 60? 113 | 114 | Neste caso não basta transportar uma vez, temos que continuar fazendo isso até que time.second seja menos de 60. Uma solução é substituir a instrução `if` pela instrução `while`. Isso tornaria a função correta, mas não muito eficiente. Como exercício, escreva uma versão correta de `increment` que não contenha loops. 115 | 116 | O que se faz com modificadores também pode ser feito com funções puras. Na verdade, algumas linguagens de programação só permitem funções puras. Há evidências de que os programas que usam funções puras são mais rápidos para serem desenvolvidos e menos propensos a erros que programas que usam modificadores. No entanto, modificadores são convenientes de vez em quando, e os programas funcionais tendem a ser menos eficientes. 117 | 118 | De forma geral, recomendo que você escreva funções puras sempre que achar razoável e recorra a modificadores só se houver alguma vantagem clara. Esta abordagem pode ser chamada de __programação funcional__. 119 | 120 | Como exercício, escreva uma versão “pura” de increment que cria e retorna um objeto `Time` em vez de alterar o parâmetro. 121 | 122 | ## 16.4 - Prototipação versus planejamento 123 | 124 | O plano de desenvolvimento que estou demonstrando chama-se “protótipo e correção”. Para cada função, escrevi um protótipo que executa o cálculo básico e então testa a função, corrigindo erros no decorrer do caminho. 125 | 126 | Esta abordagem pode ser eficaz, especialmente se você ainda não tem uma compreensão profunda do problema. Porém, as correções incrementais podem gerar código que se complica desnecessariamente (pois trata de muitos casos especiais) e pouco confiáveis (já que é difícil saber se todos os erros foram encontrados). 127 | 128 | Uma alternativa é o desenvolvimento planejado, no qual a compreensão de alto nível do problema pode facilitar muito a programação. Neste caso, descobre-se que um objeto Time é, na verdade, um número de três dígitos na base 60 (veja http://en.wikipedia.org/wiki/Sexagesimal)! O atributo second é a “coluna de unidades”, o atributo minute é a “coluna dos 60”, e o atributo hour é a “coluna do 3.600”. 129 | 130 | Quando escrevemos `add_time` e `increment`, estávamos na verdade fazendo adições na base 60, e por isso transportávamos os resultados de uma coluna à seguinte. 131 | 132 | Essa observação sugere outra abordagem para o problema inteiro – podemos converter objetos `Time` em números inteiros e aproveitar o fato de que o computador sabe trabalhar com aritmética de números inteiros. 133 | 134 | Aqui está uma função que converte objetos `Time` em números inteiros: 135 | 136 | 137 | ```python 138 | def time_to_int(time): 139 |     minutes = time.hour * 60 + time.minute 140 |     seconds = minutes * 60 + time.second 141 |     return seconds 142 | ``` 143 | 144 | E aqui está uma função que converte um número inteiro em um `Time` (lembre-se de que `divmod` divide o primeiro argumento pelo segundo e devolve o quociente e o resto como uma tupla): 145 | 146 | ```python 147 | def int_to_time(seconds): 148 |     time = Time() 149 |     minutes, time.second = divmod(seconds, 60) 150 |     time.hour, time.minute = divmod(minutes, 60) 151 |     return time 152 | ``` 153 | 154 | Você pode ter que pensar um pouco e fazer alguns testes, para se convencer de que essas funções estão corretas. Um modo de testá-las é ver se `time_to_int(int_to_time(x)) == x` para muitos valores de `x`. Este é um exemplo de uma verificação de consistência. 155 | 156 | Uma vez que esteja convencido de que estão corretas, você pode usá-las para reescrever `add_time`: 157 | 158 | ```python 159 | def add_time(t1, t2): 160 |     seconds = time_to_int(t1) + time_to_int(t2) 161 |     return int_to_time(seconds) 162 | ``` 163 | 164 | Esta versão é mais curta que a original, e mais fácil de verificar. Como exercício, reescreva `increment` usando `time_to_int` e `int_to_time`. 165 | 166 | Em algumas situações, converter da base 60 para a base 10 e de volta é mais difícil que apenas lidar com as horas. A conversão de base é mais abstrata; nossa intuição para lidar com valores temporais é melhor. 167 | 168 | No entanto, se tivermos discernimento para lidar com horas como números de base 60 e investirmos esforço em escrever as funções de conversão (`time_to_int` e `int_to_time`), chegamos a um programa que é mais curto, mais fácil de ler e depurar, e mais confiável. 169 | 170 | Também é mais fácil acrescentar recursos depois. Por exemplo, imagine subtrair dois objetos `Time` para encontrar a duração entre eles. Uma abordagem ingênua seria implementar a subtração com transporte. Porém, usar funções de conversão seria mais fácil e, provavelmente, mais correto. 171 | 172 | Ironicamente, tornar um problema mais difícil (ou mais geral) facilita (porque há menos casos especiais e menos oportunidades de erro). 173 | 174 | ## 16.5 - Depuração 175 | 176 | Um objeto `Time` é bem formado se os valores de `minute` e `second` estiverem entre 0 e 60 (incluindo 0, mas não 60) e se `hour` for positivo. `hour` e `minute` devem ser valores inteiros, mas podemos permitir que `second` tenha uma parte fracionária. 177 | 178 | Requisitos como esses chamam-se invariáveis porque sempre devem ser verdadeiros. Para dizer de outra forma, se não forem verdadeiros, algo deu errado. 179 | 180 | Escrever código para verificar requisitos invariáveis pode ajudar a descobrir erros e encontrar suas causas. Por exemplo, você pode ter uma função como valid\_time, que receba um objeto Time e retorne False se ele violar um requisito invariável: 181 | 182 | ```python 183 | def valid_time(time): 184 |     if time.hour < 0 or time.minute < 0 or time.second < 0: 185 |         return False 186 |     if time.minute >= 60 or time.second >= 60: 187 |         return False 188 |     return True 189 | ``` 190 | 191 | No início de cada função você pode verificar os argumentos para ter certeza de que são válidos: 192 | 193 | ```python 194 | def add_time(t1, t2): 195 |     if not valid_time(t1) or not valid_time(t2): 196 |         raise ValueError('invalid Time object in add_time') 197 | 198 |     seconds = time_to_int(t1) + time_to_int(t2) 199 |     return int_to_time(seconds) 200 | ``` 201 | 202 | Ou você pode usar uma instrução `assert`, que verifica determinado requisito invariável e cria uma exceção se ela falhar: 203 | 204 | ```python 205 | def add_time(t1, t2): 206 |     assert valid_time(t1) and valid_time(t2) 207 |     seconds = time_to_int(t1) + time_to_int(t2) 208 |     return int_to_time(seconds) 209 | ``` 210 | 211 | Instruções assert são úteis porque distinguem o código que lida com condições normais do código que verifica erros. 212 | 213 | ## 16.6 - Glossário 214 | 215 |
216 |
protótipo e correção
217 |
Plano de desenvolvimento no qual a escrita do programa parte de um esboço inicial, e depois segue ao teste e correção de erros, conforme sejam encontrados.
218 | 219 |
desenvolvimento planejado
220 |
Plano de desenvolvimento que implica uma compreensão de alto nível do problema e mais planejamento que desenvolvimento incremental ou desenvolvimento prototipado.
221 | 222 |
função pura
223 |
Função que não altera nenhum dos objetos que recebe como argumento. A maior parte das funções puras gera resultado.
224 | 225 |
modificador
226 |
Função que modifica um ou vários dos objetos que recebe como argumento. A maior parte dos modificadores são nulos; isto é, retornam None.
227 | 228 |
programação funcional
229 |
Estilo de projeto de programa no qual a maioria das funções são puras.
230 | 231 |
invariável
232 |
Condição que sempre deve ser verdadeira durante a execução de um programa.
233 | 234 |
instrução assert
235 |
Instrução que verifica uma condição e levanta uma exceção se esta falhar.
236 | 237 |
238 | 239 | ## 16.7 - Exercícios 240 | 241 | Os exemplos de código deste capítulo estão disponíveis em http://thinkpython2.com/code/Time1.py; as soluções para os exercícios estão disponíveis em http://thinkpython2.com/code/Time1_soln.py. 242 | 243 | ### Exercício 16.1 244 | 245 | Escreva uma função chamada `mul_time` que receba um objeto `Time` e um número e retorne um novo objeto `Time` que contenha o produto do `Time` original e do número. 246 | 247 | Então use `mul_time` para escrever uma função que receba um objeto `Time` representando o tempo até o fim de uma corrida e um número que represente a distância, e retorne um objeto `Time` com o passo médio (tempo por milha). 248 | 249 | ### Exercício 16.2 250 | 251 | O módulo `datetime` fornece objetos `time` que são semelhantes aos objetos `Time` deste capítulo, mas ele oferece um grande conjunto de métodos e operadores. Leia a documentação em http://docs.python.org/3/library/datetime.html. 252 | 253 | 1. Use o módulo `datetime` para escrever um programa que receba a data atual e exiba o dia da semana. 254 | 255 | 2. Escreva um programa que receba um aniversário como entrada e exiba a idade do usuário e o número de dias, horas, minutos e segundos até o seu próximo aniversário. 256 | 257 | 3. Para duas pessoas nascidas em dias diferentes, há um dia em que a idade de uma equivale a duas vezes a da outra. Este é o Dia Duplo delas. Escreva um programa que receba dois aniversários e calcule o Dia Duplo dos aniversariantes. 258 | 259 | 4. Para um desafio um pouco maior, escreva a versão mais geral que calcule o dia em que uma pessoa é N vezes mais velha que a outra. 260 | -------------------------------------------------------------------------------- /docs/C-colofao-autor.md: -------------------------------------------------------------------------------- 1 | # Colofão 2 | 3 | 4 | 5 | O animal na capa de Pense em Python é um papagaio-da-carolina, também conhecido como periquito-da-carolina (Conuropsis carolinensis). Este papagaio habitava o sudeste dos Estados Unidos e foi o único papagaio continental a habitar regiões acima do norte do México. Um dia, vivia no norte, em locais tão distantes quanto Nova Iorque e os Grandes Lagos, embora fosse encontrado principalmente na região da Flórida às Carolinas. 6 | 7 | O papagaio-da-carolina era quase todo verde com a cabeça amarela e, na maturidade, tinha uma coloração laranja na testa e na face. Seu tamanho médio variava de 31 a 33 cm. Tinha uma voz alta, ruidosa e palrava constantemente enquanto se alimentava. Habitava troncos de árvores ocos perto de brejos e barrancos. O papagaio-da-carolina era um animal muito gregário, que vivia em pequenos grupos os quais podiam chegar a várias centenas quando se alimentavam. 8 | 9 | Infelizmente, essas áreas de alimentação muitas vezes eram as plantações de agricultores, que disparavam nos pássaros para mantê-los longe das plantas. A natureza social dos pássaros fazia com que eles voassem ao resgate de qualquer papagaio ferido, permitindo aos agricultores derrubar bandos inteiros de cada vez. Além disso, suas penas eram usadas para embelezar chapéus de senhoras, e alguns papagaios eram mantidos como mascotes. Uma combinação desses fatores levou o papagaio-da-carolina a tornar-se raro no fim dos anos 1800, e as doenças de aves domésticas podem ter contribuído para diminuir seu número. Pelos anos 1920, a espécie estava extinta. 10 | 11 | Hoje, há mais de 700 espécimes de papagaios-da-carolina conservados em museus no mundo inteiro. 12 | 13 | Muitos dos animais nas capas de livros da O’Reilly estão em perigo de extinção; todos eles são importantes para o mundo. Para saber mais sobre como você pode ajudar, acesse animals.oreilly.com. A imagem da capa é do livro Johnson’s Natural History. 14 | 15 | ## Sobre o autor 16 | 17 | Allen Downey é professor de Ciência da Computação no Olin College of Engineering. Ele já ensinou no Wellesley College, Colby College e na U.C. Berkeley. É doutor em Ciência da Computação pela U.C. Berkeley e mestre e graduado pelo MIT. 18 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Pense em Python 2 | 3 | ### Pense como um cientista da computação 4 | 5 | 6 | 7 | Este livro ensina programação para quem nunca programou, usando [Python 3](https://www.python.org/) nos exemplos. É aplicado no Olin College, IBMEC e outras faculdades de engenharia de primeira linha. 8 | 9 | > __DICA__: Você pode comprar um exemplar impresso de [__Pense em Python__](https://novatec.com.br/livros/pense-em-python/) no site da [Editora Novatec](https://novatec.com.br/livros/pense-em-python/) ou em livrarias. [ISBN: 978-85-7522-508-0](https://novatec.com.br/livros/pense-em-python/). 10 | 11 | [__Pense em Python__](https://novatec.com.br/livros/pense-em-python/) é uma tradução do livro [Think Python](http://shop.oreilly.com/product/0636920045267.do) (2ª edição), de __Allen B. Downey__, traduzido e publicado no Brasil pela [Editora Novatec](https://novatec.com.br) sob licença da O'Reilly Media. 12 | 13 | ## Sumário 14 | 15 | * [Prefácio](00-prefacio.md) 16 | 17 | 18 | 1. [A jornada do programa](01-jornada.md) 19 | 2. [Variáveis, expressões e instruções](02-vars-expr-instr.md) 20 | 3. [Funções](03-funcoes.md) 21 | 4. [Estudo de caso: projeto de interface](04-caso-interface.md) 22 | 5. [Condicionais e recursividade](05-cond-recur.md) 23 | 6. [Funções com resultado](06-funcoes-result.md) 24 | 7. [Iteração](07-iteracao.md) 25 | 8. [Strings](08-strings.md) 26 | 9. [Estudo de caso: jogos de palavras](09-caso-palavras.md) 27 | 10. [Listas](10-listas.md) 28 | 11. [Dicionários](11-dicionarios.md) 29 | 12. [Tuplas](12-tuplas.md) 30 | 13. [Estudo de caso: seleção de estrutura de dados](13-caso-estruturas.md) 31 | 14. [Arquivos](14-arquivos.md) 32 | 15. [Classes e objetos](15-classes-objetos.md) 33 | 16. [Classes e funções](16-classes-funcoes.md) 34 | 17. [Classes e métodos](17-classes-metodos.md) 35 | 18. [Herança](18-heranca.md) 36 | 19. [Extra](19-extra.md) 37 | 38 | 39 | * [Apêndice A: Depuração](A-depuracao.md) 40 | * [Apêndice B: Análise de algoritmos](B-analise-algorit.md) 41 | * [Colofão / Sobre o Autor](C-colofao-autor.md) 42 | 43 | ## Créditos da edição brasileira 44 | 45 | Editor: Rubens Prates
46 | Tradução: Sheila Gomes
47 | Revisão Gramatical: Smirna Cavalheiro
48 | Editoração Eletrônica: Carolina Kuwabata
49 | Assistente Editorial: Priscila A. Yoshimatsu 50 | 51 | 52 | ## Histórico 53 | 54 | Allen Downey publicou o [original em inglês](http://greenteapress.com/wp/think-python-2e/) sob uma licença Creative Commons Atribuição-NãoComercial [CC BY-NC 3.0](https://github.com/PenseAllen/PensePython2/blob/master/LICENSE.md). A Novatec oferece à comunidade esta tradução nos termos da mesma licença do original, [CC BY-NC 3.0](https://github.com/PenseAllen/PensePython2/blob/master/LICENSE.md), atendendo ao desejo do autor oferecer seu trabalho através de uma licença livre. 55 | 56 | Esta versão digital de __Pense em Python__ em português foi gerada por [Luciano Ramalho](https://twitter.com/ramalhoorg) da [ThoughtWorks](https://www.thoughtworks.com/) a partir de arquivos cedidos por [Rubens Prates](https://novatec.com.br/autores/rprates.php) da [Editora Novatec](https://novatec.com.br). 57 | -------------------------------------------------------------------------------- /ebooks/PenseEmPython2e.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/ebooks/PenseEmPython2e.epub -------------------------------------------------------------------------------- /ebooks/metadata.xml: -------------------------------------------------------------------------------- 1 | Pense em Python 2 | Allen Downey 3 | Creative Commons 4 | pt-BR -------------------------------------------------------------------------------- /fig/p19f1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/p19f1.png -------------------------------------------------------------------------------- /fig/p242f1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/p242f1.png -------------------------------------------------------------------------------- /fig/p63f1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/p63f1.png -------------------------------------------------------------------------------- /fig/p72f1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/p72f1.png -------------------------------------------------------------------------------- /fig/p79f1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/p79f1.png -------------------------------------------------------------------------------- /fig/p79f2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/p79f2.png -------------------------------------------------------------------------------- /fig/p80f1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/p80f1.png -------------------------------------------------------------------------------- /fig/p83f1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/p83f1.png -------------------------------------------------------------------------------- /fig/tnkp_0201.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_0201.png -------------------------------------------------------------------------------- /fig/tnkp_0301.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_0301.png -------------------------------------------------------------------------------- /fig/tnkp_0401.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_0401.png -------------------------------------------------------------------------------- /fig/tnkp_0402.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_0402.png -------------------------------------------------------------------------------- /fig/tnkp_0501.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_0501.png -------------------------------------------------------------------------------- /fig/tnkp_0502.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_0502.png -------------------------------------------------------------------------------- /fig/tnkp_0601.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_0601.png -------------------------------------------------------------------------------- /fig/tnkp_0701.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_0701.png -------------------------------------------------------------------------------- /fig/tnkp_0801.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_0801.png -------------------------------------------------------------------------------- /fig/tnkp_0802.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_0802.png -------------------------------------------------------------------------------- /fig/tnkp_1001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1001.png -------------------------------------------------------------------------------- /fig/tnkp_1002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1002.png -------------------------------------------------------------------------------- /fig/tnkp_1003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1003.png -------------------------------------------------------------------------------- /fig/tnkp_1004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1004.png -------------------------------------------------------------------------------- /fig/tnkp_1005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1005.png -------------------------------------------------------------------------------- /fig/tnkp_1101.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1101.png -------------------------------------------------------------------------------- /fig/tnkp_1102.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1102.png -------------------------------------------------------------------------------- /fig/tnkp_1201.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1201.png -------------------------------------------------------------------------------- /fig/tnkp_1202.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1202.png -------------------------------------------------------------------------------- /fig/tnkp_1501.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1501.png -------------------------------------------------------------------------------- /fig/tnkp_1502.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1502.png -------------------------------------------------------------------------------- /fig/tnkp_1503.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1503.png -------------------------------------------------------------------------------- /fig/tnkp_1601.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1601.png -------------------------------------------------------------------------------- /fig/tnkp_1801.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1801.png -------------------------------------------------------------------------------- /fig/tnkp_1802.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_1802.png -------------------------------------------------------------------------------- /fig/tnkp_2101.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/fig/tnkp_2101.png -------------------------------------------------------------------------------- /img/Capa_PenseEmPython167x232.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/img/Capa_PenseEmPython167x232.png -------------------------------------------------------------------------------- /img/Capa_PenseEmPython332x461-borda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/img/Capa_PenseEmPython332x461-borda.png -------------------------------------------------------------------------------- /img/Capa_PenseEmPython667x927.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/img/Capa_PenseEmPython667x927.png -------------------------------------------------------------------------------- /recebido/capitulos.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/capitulos.ods -------------------------------------------------------------------------------- /recebido/capitulos.txt: -------------------------------------------------------------------------------- 1 | 0 Prefácio 2 | 1 A jornada do programa 3 | 2 Variáveis, expressões e instruções 4 | 3 Funções 5 | 4 Estudo de caso: projeto de interface 6 | 5 Condicionais e recursividade 7 | 6 Funções com resultado 8 | 7 Iteração 9 | 8 Strings 10 | 9 Estudo de caso: jogos de palavras 11 | 10 Listas 12 | 11 Dicionários 13 | 12 Tuplas 14 | 13 Estudo de caso: seleção de estrutura de dados 15 | 14 Arquivos 16 | 15 Classes e objetos 17 | 16 Classes e funções 18 | 17 Classes e métodos 19 | 18 Herança 20 | 19 Extra 21 | A Depuração 22 | B Análise de algoritmos 23 | -------------------------------------------------------------------------------- /recebido/capitulos/02-vars-expr-instr.md: -------------------------------------------------------------------------------- 1 | # Capítulo 2: Variáveis, expressões e instruções 2 | 3 | Um dos recursos mais eficientes de uma linguagem de programação é a capacidade de manipular variáveis. Uma variável é um nome que se refere a um valor. 4 | 5 | Instruções de atribuição 6 | 7 | Uma instrução de atribuição cria uma nova variável e dá um valor a ela: 8 | 9 | >>> message = 'And now for something completely different' 10 | 11 | >>> n = 17 12 | 13 | >>> pi = 3.141592653589793 14 | 15 | Esse exemplo faz três atribuições. A primeira atribui uma string a uma nova variável chamada message; a segunda dá o número inteiro 17 a n; a terceira atribui o valor (aproximado) de π a pi. 16 | 17 | Uma forma comum de representar variáveis por escrito é colocar o nome com uma flecha apontando para o seu valor. Este tipo de número é chamado de diagrama de estado porque mostra o estado no qual cada uma das variáveis está (pense nele como o estado de espírito da variável). A Figura 2.1 mostra o resultado do exemplo anterior. 18 | 19 | Figura 2.1 – Diagrama de estado. 20 | 21 | Nomes de variáveis 22 | 23 | Os programadores geralmente escolhem nomes significativos para as suas variáveis – eles documentam o uso da variável. 24 | 25 | Nomes de variáveis podem ser tão longos quanto você queira. Podem conter tanto letras como números, mas não podem começar com um número. É legal usar letras maiúsculas, mas a convenção é usar apenas letras minúsculas para nomes de variáveis. 26 | 27 | O caractere de sublinhar (\_) pode aparecer em um nome. Muitas vezes é usado em nomes com várias palavras, como your\_name ou airspeed\_of\_unladen\_swallow. 28 | 29 | Se você der um nome ilegal a uma variável, recebe um erro de sintaxe: 30 | 31 | >>> 76trombones = 'big parade' 32 | 33 | SyntaxError: invalid syntax 34 | 35 | >>> more@ = 1000000 36 | 37 | SyntaxError: invalid syntax 38 | 39 | >>> class = 'Advanced Theoretical Zymurgy' 40 | 41 | SyntaxError: invalid syntax 42 | 43 | 76trombones é ilegal porque começa com um número. more@ é ilegal porque contém um caractere ilegal, o @. Mas o que há de errado com class? 44 | 45 | A questão é que class é uma das palavras-chave do Python. O interpretador usa palavras-chave para reconhecer a estrutura do programa e elas não podem ser usadas como nomes de variável. 46 | 47 | O Python 3 tem estas palavras-chave: 48 | 49 | False     class      finally    is         return 50 | 51 | None      continue   for       lambda     try 52 | 53 | True      def        from      nonlocal   while 54 | 55 | and       del        global    not        with 56 | 57 | as        elif       if        or         yield 58 | 59 | assert    else       import    pass 60 | 61 | break     except     in        raise 62 | 63 | Você não precisa memorizar essa lista. Na maior parte dos ambientes de desenvolvimento, as palavras-chave são exibidas em uma cor diferente; se você tentar usar uma como nome de variável, vai perceber. 64 | 65 | Expressões e instruções 66 | 67 | Uma expressão é uma combinação de valores, variáveis e operadores. Um valor por si mesmo é considerado uma expressão, assim como uma variável, portanto as expressões seguintes são todas legais: 68 | 69 | >>> 42 70 | 71 | 42 72 | 73 | >>> n 74 | 75 | 17 76 | 77 | >>> n + 25 78 | 79 | 42 80 | 81 | Quando você digita uma expressão no prompt, o interpretador a avalia, ou seja, ele encontra o valor da expressão. Neste exemplo, o n tem o valor 17 e n + 25 tem o valor 42. 82 | 83 | Uma instrução é uma unidade de código que tem um efeito, como criar uma variável ou exibir um valor. 84 | 85 | >>> n = 17 86 | 87 | >>> print(n) 88 | 89 | A primeira linha é uma instrução de atribuição que dá um valor a n. A segunda linha é uma instrução de exibição que exibe o valor de n. 90 | 91 | Quando você digita uma instrução, o interpretador a executa, o que significa que ele faz o que a instrução diz. Em geral, instruções não têm valores. 92 | 93 | Modo script 94 | 95 | Até agora executamos o Python no modo interativo, no qual você interage diretamente com o interpretador. O modo interativo é uma boa forma de começar, mas se estiver trabalhando com mais do que algumas linhas do código, o processo pode ficar desorganizado. 96 | 97 | A alternativa é salvar o código em um arquivo chamado script e então executar o interpretador no modo script para executá-lo. Por convenção, os scripts no Python têm nomes que terminam com .py. 98 | 99 | Se souber como criar e executar um script no seu computador, você está pronto. Senão, recomendo usar o PythonAnywhere novamente. Inseri instruções sobre como executar programas no modo script em http://tinyurl.com/thinkpython2e. 100 | 101 | Como o Python oferece os dois modos, você pode testar pedaços do código no modo interativo antes de colocá-los em um script. Mas há diferenças entre o modo interativo e o modo script que podem confundir as pessoas. 102 | 103 | Por exemplo, se estiver usando o Python como uma calculadora, você poderia digitar: 104 | 105 | >>> miles = 26.2 106 | 107 | >>> miles \* 1.61 108 | 109 | 42.182 110 | 111 | A primeira linha atribui um valor a miles, mas não tem efeito visível. A segunda linha é uma expressão, então o interpretador a avalia e exibe o resultado. No fim, chega-se ao resultado de que uma maratona tem aproximadamente 42 quilômetros. 112 | 113 | Mas se você digitar o mesmo código em um script e executá-lo, não recebe nenhuma saída. Uma expressão, por conta própria, não tem efeito visível no modo script. O Python, na verdade, avalia a expressão, mas não exibe o valor a menos que você especifique: 114 | 115 | miles = 26.2 116 | 117 | print(miles \* 1.61) 118 | 119 | Este comportamento pode confundir um pouco no início. 120 | 121 | Um script normalmente contém uma sequência de instruções. Se houver mais de uma instrução, os resultados aparecem um após o outro, conforme as instruções sejam executadas. 122 | 123 | Por exemplo, o script 124 | 125 | print(1) 126 | 127 | x = 2 128 | 129 | print(x) 130 | 131 | produz a saída 132 | 133 | 1 134 | 135 | 2 136 | 137 | A instrução de atribuição não produz nenhuma saída. 138 | 139 | Para verificar sua compreensão, digite as seguintes instruções no interpretador do Python e veja o que fazem: 140 | 141 | 5 142 | 143 | x = 5 144 | 145 | x + 1 146 | 147 | Agora ponha as mesmas instruções em um script e o execute. Qual é a saída? Altere o script transformando cada expressão em uma instrução de exibição e então o execute novamente. 148 | 149 | Ordem das operações 150 | 151 | Quando uma expressão contém mais de um operador, a ordem da avaliação depende da ordem das operações. Para operadores matemáticos, o Python segue a convenção matemática. O acrônimo PEMDAS pode ser útil para lembrar das regras: 152 | 153 | •        Os Parênteses têm a precedência mais alta e podem ser usados para forçar a avaliação de uma expressão na ordem que você quiser. Como as expressões em parênteses são avaliadas primeiro, 2 \* (3-1) é 4, e (1+1)\*\*(5-2) é 8. Também é possível usar parênteses para facilitar a leitura de uma expressão, como no caso de (minute \* 100) / 60, mesmo se o resultado não for alterado. 154 | 155 | •        A Exponenciação tem a próxima precedência mais alta, então 1 + 2\*\*3 é 9, não 27, e 2 \* 3\*\*2 é 18, não 36. 156 | 157 | •        A Multiplicação e a Divisão têm precedência mais alta que a Adição e a Subtração. Assim, 2\*3-1 é 5, não 4, e 6+4/2 é 8, não 5. 158 | 159 | •        Os operadores com a mesma precedência são avaliados da esquerda para a direita (exceto na exponenciação). Assim, na expressão degrees/ 2 \* pi, a divisão acontece primeiro e o resultado é multiplicado por pi. Para dividir por 2π, você pode usar parênteses ou escrever degrees / 2 / pi. 160 | 161 | Eu não fico sempre tentando lembrar da precedência de operadores. Se a expressão não estiver clara à primeira vista, uso parênteses para fazer isso. 162 | 163 | Operações com strings 164 | 165 | Em geral, não é possível executar operações matemáticas com strings, mesmo se elas parecerem números, então coisas assim são ilegais: 166 | 167 | '2'-'1'    'eggs'/'easy'    'third'\*'a charm' 168 | 169 | Mas há duas exceções, + e \*. 170 | 171 | O operador + executa uma concatenação de strings, ou seja, une as strings pelas extremidades. Por exemplo: 172 | 173 | >>> first = 'throat' 174 | 175 | >>> second = 'warbler' 176 | 177 | >>> first + second 178 | 179 | throatwarbler 180 | 181 | O operador \* também funciona em strings; ele executa a repetição. Por exemplo, 'Spam'\*3 é 'SpamSpamSpam'. Se um dos valores for uma string, o outro tem de ser um número inteiro. 182 | 183 | Este uso de + e \* faz sentido por analogia com a adição e a multiplicação. Tal como 4\*3 é equivalente a 4+4+4, esperamos que 'Spam'\*3 seja o mesmo que 'Spam'+'Spam'+'Spam', e assim é. Por outro lado, há uma diferença significativa entre a concatenação de strings e a repetição em relação à adição e à multiplicação de números inteiros. Você consegue pensar em uma propriedade que a adição tem, mas a concatenação de strings não tem? 184 | 185 | Comentários 186 | 187 | Conforme os programas ficam maiores e mais complicados, eles são mais difíceis de ler. As linguagens formais são densas e muitas vezes é difícil ver um pedaço de código e compreender o que ele faz ou por que faz isso. 188 | 189 | Por essa razão, é uma boa ideia acrescentar notas aos seus programas para explicar em linguagem natural o que o programa está fazendo. Essas notas são chamadas de comentários, e começam com o símbolo \#: 190 | 191 | \# computa a percentagem da hora que passou 192 | 193 | percentage = (minute \* 100) / 60 194 | 195 | Nesse caso, o comentário aparece sozinho em uma linha. Você também pode pôr comentários no fim das linhas: 196 | 197 | percentage = (minute \* 100) / 60    \# percentagem de uma hora 198 | 199 | Tudo do \# ao fim da linha é ignorado – não tem efeito na execução do programa. 200 | 201 | Os comentários tornam-se mais úteis quando documentam algo no código que não está óbvio. Podemos supor que o leitor compreenda o que o código faz; assim, é mais útil explicar porque faz o que faz. 202 | 203 | Este comentário é redundante em relação ao código, além de inútil: 204 | 205 | v = 5    \# atribui 5 a v 206 | 207 | Este comentário contém informações úteis que não estão no código: 208 | 209 | v = 5    \# velocidade em metros/segundo. 210 | 211 | Bons nomes de variáveis podem reduzir a necessidade de comentários, mas nomes longos podem tornar expressões complexas difíceis de ler, então é preciso analisar o que vale mais a pena. 212 | 213 | Depuração 214 | 215 | Há três tipos de erros que podem ocorrer em um programa: erros de sintaxe, erros de tempo de execução e erros semânticos. É útil distinguir entre eles para rastreá-los mais rapidamente. 216 | 217 | Erro de sintaxe: 218 | 219 | A “sintaxe” refere-se à estrutura de um programa e suas respectivas regras. Por exemplo, os parênteses devem vir em pares correspondentes, então (1 + 2) é legal, mas 8) é um erro de sintaxe. 220 | 221 | Se houver um erro de sintaxe em algum lugar no seu programa, o Python exibe uma mensagem de erro e para, e não será possível executar o programa. Nas primeiras poucas semanas da sua carreira em programação, você pode passar muito tempo rastreando erros de sintaxe. Ao adquirir experiência, você fará menos erros e os encontrará mais rápido. 222 | 223 | Erro de tempo de execução: 224 | 225 | O segundo tipo de erro é o erro de tempo de execução, assim chamado porque o erro não aparece até que o programa seja executado. Esses erros também se chamam de exceções porque normalmente indicam que algo excepcional (e ruim) aconteceu. 226 | 227 | Os erros de tempo de execução são raros nos programas simples que veremos nos primeiros capítulos, então pode demorar um pouco até você encontrar algum. 228 | 229 | Erro semântico: 230 | 231 | O terceiro tipo do erro é “semântico”, ou seja, relacionado ao significado. Se houver um erro semântico no seu programa, ele será executado sem gerar mensagens de erro, mas não vai fazer a coisa certa. Vai fazer algo diferente. Especificamente, vai fazer o que você disser para fazer. 232 | 233 | Identificar erros semânticos pode ser complicado, porque é preciso trabalhar de trás para a frente, vendo a saída do programa e tentando compreender o que ele está fazendo. 234 | 235 | Glossário 236 | 237 | variável: 238 | 239 | Um nome que se refere a um valor. 240 | 241 | atribuição: 242 | 243 | Uma instrução que atribui um valor a uma variável. 244 | 245 | diagrama de estado: 246 | 247 | Uma representação gráfica de um grupo de variáveis e os valores a que se referem. 248 | 249 | palavra-chave: 250 | 251 | Uma palavra reservada, usada para analisar um programa; não é possível usar palavras-chave como if, def e while como nomes de variáveis. 252 | 253 | operando: 254 | 255 | Um dos valores que um operador produz. 256 | 257 | expressão: 258 | 259 | Uma combinação de variáveis, operadores e valores que representa um resultado único. 260 | 261 | avaliar: 262 | 263 | Simplificar uma expressão executando as operações para produzir um valor único. 264 | 265 | instrução: 266 | 267 | Uma seção do código que representa um comando ou ação. Por enquanto, as instruções que vimos são instruções de atribuições e de exibição. 268 | 269 | executar: 270 | 271 | Executar uma instrução para fazer o que ela diz. 272 | 273 | modo interativo: 274 | 275 | Um modo de usar o interpretador do Python, digitando o código no prompt. 276 | 277 | modo script: 278 | 279 | Um modo de usar o interpretador do Python para ler código em um script e executá-lo. 280 | 281 | script: 282 | 283 | Um programa armazenado em um arquivo. 284 | 285 | ordem das operações: 286 | 287 | As regras que governam a ordem na qual as expressões que envolvem vários operadores e operandos são avaliadas. 288 | 289 | concatenar: 290 | 291 | Juntar dois operandos pelas extremidades. 292 | 293 | comentários: 294 | 295 | Informações em um programa destinadas a outros programadores (ou qualquer pessoa que leia o texto fonte) que não têm efeito sobre a execução do programa. 296 | 297 | erro de sintaxe: 298 | 299 | Um erro em um programa que torna sua análise impossível (e por isso impossível de interpretar). 300 | 301 | exceção: 302 | 303 | Um erro que se descobre quando o programa é executado. 304 | 305 | semântica: 306 | 307 | O significado de um programa. 308 | 309 | erro semântico: 310 | 311 | Um erro que faz com que um programa faça algo diferente do que o programador pretendia. 312 | 313 | Exercícios 314 | 315 | Exercício 2.1 316 | 317 | Repetindo o meu conselho do capítulo anterior, sempre que você aprender um recurso novo, você deve testá-lo no modo interativo e fazer erros de propósito para ver o que acontece. 318 | 319 | •        Vimos que n = 42 é legal. E 42 = n? 320 | 321 | •        Ou x = y = 1? 322 | 323 | •        Em algumas linguagens, cada instrução termina em um ponto e vírgula ;. O que acontece se você puser um ponto e vírgula no fim de uma instrução no Python? 324 | 325 | •        E se puser um ponto no fim de uma instrução? 326 | 327 | •        Em notação matemática é possível multiplicar x e y desta forma: xy. O que acontece se você tentar fazer o mesmo no Python? 328 | 329 | Exercício 2.2 330 | 331 | Pratique o uso do interpretador do Python como uma calculadora: 332 | 333 | 1.        O volume de uma esfera com raio r é . Qual é o volume de uma esfera com raio 5? 334 | 335 | 2.        Suponha que o preço de capa de um livro seja R$ 24,95, mas as livrarias recebem um desconto de 40%. O transporte custa R$ 3,00 para o primeiro exemplar e 75 centavos para cada exemplar adicional. Qual é o custo total de atacado para 60 cópias? 336 | 337 | 3.        Se eu sair da minha casa às 6:52 e correr 1 quilômetro a um certo passo (8min15s por quilômetro), então 3 quilômetros a um passo mais rápido (7min12s por quilômetro) e 1 quilômetro no mesmo passo usado em primeiro lugar, que horas chego em casa para o café da manhã? 338 | 339 | -------------------------------------------------------------------------------- /recebido/capitulos/07-iteracao.md: -------------------------------------------------------------------------------- 1 | # Capítulo 7: Iteração 2 | 3 | Este capítulo é sobre a iteração, a capacidade de executar um bloco de instruções repetidamente. Vimos um tipo de iteração, usando a recursividade, em “Recursividade”, na página 81. Vimos outro tipo, usando um loop for, em “Repetição simples”, na página 65. Neste capítulo veremos ainda outro tipo, usando a instrução while. Porém, primeiro quero falar um pouco mais sobre a atribuição de variáveis. 4 | 5 | Reatribuição 6 | 7 | Pode ser que você já tenha descoberto que é legal fazer mais de uma atribuição para a mesma variável. Uma nova atribuição faz uma variável existente referir-se a um novo valor (e deixar de referir-se ao valor anterior). 8 | 9 | >>> x = 5 10 | 11 | >>> x 12 | 13 | 5 14 | 15 | >>> x = 7 16 | 17 | >>> x 18 | 19 | 7 20 | 21 | A primeira vez que exibimos x, seu valor é 5; na segunda vez, seu valor é 7. 22 | 23 | A Figura 7.1 mostra que a reatribuição parece um diagrama de estado. 24 | 25 | Neste ponto quero tratar de uma fonte comum de confusão. Como o Python usa o sinal de igual (=) para atribuição, é tentador interpretar uma afirmação como a = b como uma proposição matemática de igualdade; isto é, a declaração de que a e b são iguais. Mas esta é uma interpretação equivocada. 26 | 27 | Em primeiro lugar, a igualdade é uma relação simétrica e a atribuição não é. Por exemplo, na matemática, se a=7 então 7=a. Mas no Python, a instrução a = 7 é legal e 7 = a não é. 28 | 29 | Além disso, na matemática, uma proposição de igualdade é verdadeira ou falsa para sempre. Se a=b agora, então a sempre será igual a b. No Python, uma instrução de atribuição pode tornar duas variáveis iguais, mas elas não precisam se manter assim: 30 | 31 | >>> a = 5 32 | 33 | >>> b = a    \# a e b agora são iguais 34 | 35 | >>> a = 3    \# a e b não são mais iguais 36 | 37 | >>> b 38 | 39 | 5 40 | 41 | A terceira linha modifica o valor de a, mas não muda o valor de b, então elas já não são iguais. 42 | 43 | A reatribuição de variáveis muitas vezes é útil, mas você deve usá-la com prudência. Se os valores das variáveis mudarem frequentemente, isso pode dificultar a leitura e depuração do código. 44 | 45 | Figura 7.1 – Diagrama de estado. 46 | 47 | Atualização de variáveis 48 | 49 | Um tipo comum de reatribuição é uma atualização, onde o novo valor da variável depende do velho. 50 | 51 | >>> x = x + 1 52 | 53 | Isso significa “pegue o valor atual de x, acrescente um, e então atualize x para o novo valor”. 54 | 55 | Se você tentar atualizar uma variável que não existe, recebe um erro porque o Python avalia o lado direito antes de atribuir um valor a x: 56 | 57 | >>> x = x + 1 58 | 59 | NameError: name 'x' is not defined 60 | 61 | Antes de poder atualizar uma variável é preciso inicializá-la, normalmente com uma atribuição simples: 62 | 63 | >>> x = 0 64 | 65 | >>> x = x + 1 66 | 67 | Atualizar uma variável acrescentando 1 chama-se incremento; subtrair 1 chama-se decremento. 68 | 69 | Instrução while 70 | 71 | Os computadores muitas vezes são usados para automatizar tarefas repetitivas. A repetição de tarefas idênticas ou semelhantes sem fazer erros é algo que os computadores fazem bem e as pessoas não. Em um programa de computador, a repetição também é chamada de iteração. 72 | 73 | Já vimos duas funções, countdown e print\_n, que se repetem usando recursividade. Como a iteração é bem comum, o Python fornece recursos de linguagem para facilitá-la. Um deles é a instrução for que vimos em “Repetição simples”, na página 65. Voltaremos a isso mais adiante. 74 | 75 | Outra é a instrução while. Aqui está uma versão de countdown que usa a instrução while: 76 | 77 | def countdown(n): 78 | 79 |     while n > 0: 80 | 81 |         print(n) 82 | 83 |         n = n - 1 84 | 85 |     print('Blastoff!') 86 | 87 | Você até pode ler a instrução while como se fosse uma tradução do inglês. Significa “Enquanto n for maior que 0, mostre o valor de n e então decremente n. Quando chegar a 0, mostre a palavra Blastoff!” 88 | 89 | Mais formalmente, aqui está o fluxo de execução para uma instrução while: 90 | 91 | 1.        Determine se a condição é verdadeira ou falsa. 92 | 93 | 2.        Se for falsa, saia da instrução while e continue a execução da próxima instrução. 94 | 95 | 3.        Se a condição for verdadeira, execute o corpo e então volte ao passo 1. 96 | 97 | Este tipo de fluxo chama-se loop, porque o terceiro passo faz um loop de volta ao topo. 98 | 99 | O corpo do loop deve mudar o valor de uma ou mais variáveis para que, a certa altura, a condição fique falsa e o loop termine. Senão o loop vai se repetir para sempre, o que é chamado de loop infinito. Uma fonte infindável de divertimento para cientistas da computação é a observação das instruções no xampu, “Faça espuma, enxágue, repita”, que são parte de um loop infinito. 100 | 101 | No caso de countdown, podemos provar que o loop termina: se n for zero ou negativo, o loop nunca é executado. Senão, n fica cada vez menor ao passar pelo loop, até eventualmente chegar a 0. 102 | 103 | Para alguns outros loops, não é tão fácil perceber isso. Por exemplo: 104 | 105 | def sequence(n): 106 | 107 |     while n != 1: 108 | 109 |         print(n) 110 | 111 |         if n % 2 == 0:        \# n é par 112 | 113 |             n = n / 2 114 | 115 |         else:                 \# n é ímpar 116 | 117 |             n = n\*3 + 1 118 | 119 | A condição deste loop é n != 1, então o loop continuará até que n seja 1, o que torna a condição falsa. 120 | 121 | Cada vez que passa pelo loop, o programa produz o valor de n e então verifica se é par ou ímpar. Se for par, n é dividido por 2. Se for ímpar, o valor de n é substituído por n\*3 + 1. Por exemplo, se o argumento passado a sequence for 3, os valores resultantes de n são 3, 10, 5, 16, 8, 4, 2, 1. 122 | 123 | Como n às vezes aumenta e às vezes diminui, não há nenhuma prova óbvia de que n chegará eventualmente a 1, ou que o programa terminará. Para alguns valores de n, podemos provar o término. Por exemplo, se o valor inicial for uma potência de dois, n será par cada vez que passar pelo loop até que chegue a 1. O exemplo anterior termina com uma sequência assim, que inicia com 16. 124 | 125 | A questão difícil é se podemos provar que este programa termina para todos os valores positivos de n. Por enquanto, ninguém foi capaz de comprovar ou refutar isso! (Veja http://en.wikipedia.org/wiki/Collatz\_conjecture.) 126 | 127 | Como um exercício, reescreva a função print\_n de “Recursividade”, na página 81, usando a iteração em vez da recursividade. 128 | 129 | break 130 | 131 | Às vezes você não sabe que está na hora de terminar um loop até que já esteja na metade do corpo. Neste caso pode usar a instrução break para sair do loop. 132 | 133 | Por exemplo, suponha que você quer receber uma entrada do usuário até que este digite done. Você pode escrever: 134 | 135 | while True: 136 | 137 |     line = input('> ') 138 | 139 |     if line == 'done': 140 | 141 |         break 142 | 143 |     print(line) 144 | 145 | print('Done!') 146 | 147 | A condição do loop é True, que sempre é verdade, então o loop roda até que chegue à instrução de interrupção. 148 | 149 | Cada vez que passa pelo loop, o programa apresenta ao usuário um colchete angular. Se o usuário digitar done, a instrução break sai do loop. Senão, o programa ecoa o que quer que o usuário digite e volta ao topo do loop. Aqui está uma amostra de execução: 150 | 151 | > not done 152 | 153 | not done 154 | 155 | > done 156 | 157 | Done! 158 | 159 | Esta forma de escrever loops while é comum porque podemos verificar a condição em qualquer lugar do loop (não somente no topo) e podemos exprimir a condição de parada afirmativamente (“pare quando isto acontecer”) em vez de negativamente (“continue a seguir até que isto aconteça”). 160 | 161 | Raízes quadradas 162 | 163 | Loops muitas vezes são usados em programas que calculam resultados numéricos, começando com uma resposta aproximada e melhorando-a iterativamente. 164 | 165 | Por exemplo, uma forma de calcular raízes quadradas é o método de Newton. Suponha que você queira saber a raiz quadrada de a. Se começar com quase qualquer estimativa, x, é possível calcular uma estimativa melhor com a seguinte fórmula: 166 | 167 | Por exemplo, se a for 4 e x for 3: 168 | 169 | >>> a = 4 170 | 171 | >>> x = 3 172 | 173 | >>> y = (x + a/x) / 2 174 | 175 | >>> y 176 | 177 | 2.16666666667 178 | 179 | O resultado é mais próximo à resposta correta ( = 2). Se repetirmos o processo com a nova estimativa, chegamos ainda mais perto: 180 | 181 | >>> x = y 182 | 183 | >>> y = (x + a/x) / 2 184 | 185 | >>> y 186 | 187 | 2.00641025641 188 | 189 | Depois de algumas atualizações, a estimativa é quase exata: 190 | 191 | >>> x = y 192 | 193 | >>> y = (x + a/x) / 2 194 | 195 | >>> y 196 | 197 | 2.00001024003 198 | 199 | >>> x = y 200 | 201 | >>> y = (x + a/x) / 2 202 | 203 | >>> y 204 | 205 | 2.00000000003 206 | 207 | Em geral, não sabemos com antecedência quantos passos são necessários para chegar à resposta correta, mas sabemos quando chegamos lá porque a estimativa para de mudar: 208 | 209 | >>> x = y 210 | 211 | >>> y = (x + a/x) / 2 212 | 213 | >>> y 214 | 215 | 2.0 216 | 217 | >>> x = y 218 | 219 | >>> y = (x + a/x) / 2 220 | 221 | >>> y 222 | 223 | 2.0 224 | 225 | Quando y == x, podemos parar. Aqui está um loop que começa com uma estimativa inicial, x, e a melhora até que deixe de mudar: 226 | 227 | while True: 228 | 229 |     print(x) 230 | 231 |     y = (x + a/x) / 2 232 | 233 |     if y == x: 234 | 235 |         break 236 | 237 |     x = y 238 | 239 | Para a maior parte de valores de a funciona bem, mas pode ser perigoso testar a igualdade de um float. Os valores de ponto flutuante são aproximadamente corretos: números mais racionais, como 1/3, e números irracionais, como , não podem ser representados exatamente com um float. 240 | 241 | Em vez de verificar se x e y são exatamente iguais, é mais seguro usar a função integrada abs para calcular o valor absoluto ou magnitude da diferença entre eles: 242 | 243 | if abs(y-x) < epsilon: 244 | 245 |     break 246 | 247 | Quando epsilon tem um valor como 0.0000001, isso determina se está próximo o suficiente. 248 | 249 | Algoritmos 250 | 251 | O método de Newton é um exemplo de um algoritmo: um processo mecânico para resolver uma categoria de problemas (neste caso, calcular raízes quadradas). 252 | 253 | Para entender o que é um algoritmo, pode ser útil começar com algo que não é um algoritmo. Quando aprendeu a multiplicar números de um dígito, você provavelmente memorizou a tabuada. Ou seja, você memorizou 100 soluções específicas. Este tipo de conhecimento não é algorítmico. 254 | 255 | No entanto, se você foi “preguiçoso”, poderia ter aprendido alguns truques. Por exemplo, para encontrar o produto de n e 9, pode escrever n-1 como o primeiro dígito e 10-n como o segundo dígito. Este truque é uma solução geral para multiplicar qualquer número de dígito único por 9. Isto é um algoritmo! 256 | 257 | De forma semelhante, as técnicas que aprendeu, como o transporte na adição, o empréstimo na subtração e a divisão longa são todos algoritmos. Uma das características de algoritmos é que eles não exigem inteligência para serem executados. São processos mecânicos, nos quais cada passo segue a partir do último, de acordo com um conjunto de regras simples. 258 | 259 | A execução de algoritmos é maçante, mas projetá-los é interessante, intelectualmente desafiador e uma parte central da Ciência da Computação. 260 | 261 | Algumas coisas que as pessoas fazem naturalmente, sem dificuldade ou pensamento consciente, são as mais difíceis para exprimir algoritmicamente. A compreensão de linguagem natural é um bom exemplo. Todos nós o fazemos, mas por enquanto ninguém foi capaz de explicar como o fazemos, pelo menos não na forma de um algoritmo. 262 | 263 | Depuração 264 | 265 | Ao começar a escrever programas maiores, pode ser que você passe mais tempo depurando. Mais código significa mais possibilidades fazer erros e mais lugares para esconder defeitos. 266 | 267 | Uma forma de cortar o tempo de depuração é “depurar por bisseção”. Por exemplo, se há 100 linhas no seu programa e você as verifica uma a uma, seriam 100 passos a tomar. 268 | 269 | Em vez disso, tente quebrar o problema pela metade. Olhe para o meio do programa, ou perto disso, para um valor intermediário que possa verificar. Acrescente uma instrução print (ou outra coisa que tenha um efeito verificável) e execute o programa. 270 | 271 | Se a verificação do ponto central for incorreta, deve haver um problema na primeira metade do programa. Se for correta, o problema está na segunda metade. 272 | 273 | Cada vez que executar uma verificação assim, divida ao meio o número de linhas a serem verificadas. Depois de seis passos (que é menos de 100), você teria menos de uma ou duas linhas do código para verificar, pelo menos em teoria. 274 | 275 | Na prática, nem sempre é claro o que representa o “meio do programa” e nem sempre é possível verificá-lo. Não faz sentido contar linhas e encontrar o ponto central exato. Em vez disso, pense em lugares no programa onde poderia haver erros e lugares onde é fácil inserir um ponto de verificação. Então escolha um lugar onde as possibilidades são basicamente as mesmas de que o defeito esteja antes ou depois da verificação. 276 | 277 | Glossário 278 | 279 | reatribuição: 280 | 281 | Atribuir um novo valor a uma variável que já existe. 282 | 283 | atualização: 284 | 285 | Uma atribuição onde o novo valor da variável dependa do velho. 286 | 287 | inicialização: 288 | 289 | Uma atribuição que dá um valor inicial a uma variável que será atualizada. 290 | 291 | incremento: 292 | 293 | Uma atualização que aumenta o valor de uma variável (normalmente por uma unidade). 294 | 295 | decremento: 296 | 297 | Uma atualização que reduz o valor de uma variável. 298 | 299 | iteração: 300 | 301 | Execução repetida de um grupo de instruções, usando uma chamada da função recursiva ou um loop. 302 | 303 | loop infinito: 304 | 305 | Um loop no qual a condição de término nunca é satisfeita. 306 | 307 | algoritmo: 308 | 309 | Um processo geral para resolver uma categoria de problemas. 310 | 311 | Exercícios 312 | 313 | Exercício 7.1 314 | 315 | Copie o loop de “Raízes quadradas”, na página 111, e encapsule-o em uma função chamada mysqrt que receba a como parâmetro, escolha um valor razoável de x e devolva uma estimativa da raiz quadrada de a. 316 | 317 | Para testar, escreva uma função denominada test\_square\_root, que imprime uma tabela como esta: 318 | 319 | a   mysqrt(a)     math.sqrt(a)  diff 320 | 321 | -   ---------     ------------  ---- 322 | 323 | 1.0 1.0           1.0           0.0 324 | 325 | 2.0 1.41421356237 1.41421356237 2.22044604925e-16 326 | 327 | 3.0 1.73205080757 1.73205080757 0.0 328 | 329 | 4.0 2.0           2.0           0.0 330 | 331 | 5.0 2.2360679775  2.2360679775  0.0 332 | 333 | 6.0 2.44948974278 2.44948974278 0.0 334 | 335 | 7.0 2.64575131106 2.64575131106 0.0 336 | 337 | 8.0 2.82842712475 2.82842712475 4.4408920985e-16 338 | 339 | 9.0 3.0           3.0           0.0 340 | 341 | A primeira coluna é um número, a; a segunda coluna é a raiz quadrada de a calculada com mysqrt; a terceira coluna é a raiz quadrada calculada por math.sqrt; a quarta coluna é o valor absoluto da diferença entre as duas estimativas. 342 | 343 | Exercício 7.2 344 | 345 | A função integrada eval toma uma string e a avalia, usando o interpretador do Python. Por exemplo: 346 | 347 | >>> eval('1 + 2 \* 3') 348 | 349 | 7 350 | 351 | >>> import math 352 | 353 | >>> eval('math.sqrt(5)') 354 | 355 | 2.2360679774997898 356 | 357 | >>> eval('type(math.pi)') 358 | 359 | <class 'float'> 360 | 361 | Escreva uma função chamada eval\_loop que iterativamente peça uma entrada ao usuário, a avalie usando eval e imprima o resultado. 362 | 363 | Ela deve continuar até que o usuário digite 'done'; então deverá exibir o valor da última expressão avaliada. 364 | 365 | Exercício 7.3 366 | 367 | O matemático Srinivasa Ramanujan encontrou uma série infinita que pode ser usada para gerar uma aproximação numérica de 1/π: 368 | 369 | Escreva uma função chamada estimate\_pi que use esta fórmula para computar e devolver uma estimativa de π. Você deve usar o loop while para calcular os termos da adição até que o último termo seja menor que 1e-15 (que é a notação do Python para 10−15). Você pode verificar o resultado comparando-o com math.pi. 370 | 371 | Solução: http://thinkpython2.com/code/pi.py. 372 | 373 | -------------------------------------------------------------------------------- /recebido/capitulos/09-caso-palavras.md: -------------------------------------------------------------------------------- 1 | # Capítulo 9: Estudo de caso: jogos de palavras 2 | 3 | Este capítulo apresenta o segundo estudo de caso que envolve solucionar quebra-cabeças usando palavras com certas propriedades. Por exemplo, encontraremos os palíndromos mais longos em inglês e procuraremos palavras cujas letras apareçam em ordem alfabética. E apresentarei outro plano de desenvolvimento de programa: a redução a um problema resolvido anteriormente. 4 | 5 | Leitura de listas de palavras 6 | 7 | Para os exercícios deste capítulo vamos usar uma lista de palavras em inglês. Há muitas listas de palavras disponíveis na internet, mas a mais conveniente ao nosso propósito é uma das listas de palavras disponibilizadas em domínio público por Grady Ward como parte do projeto lexical Moby (ver http://wikipedia.org/wiki/Moby\_Project). É uma lista de 113.809 palavras cruzadas oficiais; isto é, as palavras que se consideram válidas em quebra-cabeças de palavras cruzadas e outros jogos de palavras. Na coleção Moby, o nome do arquivo é 113809of.fic; você pode baixar uma cópia, com um nome mais simples como words.txt, de http://thinkpython2.com/code/words.txt. 8 | 9 | Este arquivo está em texto simples, então você pode abri-lo com um editor de texto, mas também pode lê-lo no Python. A função integrada open recebe o nome do arquivo como um parâmetro e retorna um objeto de arquivo que você pode usar para ler o arquivo. 10 | 11 | >>> fin = open('words.txt') 12 | 13 | fin é um nome comum de objeto de arquivo usado para entrada de dados. O objeto de arquivo oferece vários métodos de leitura, inclusive readline, que lê caracteres no arquivo até chegar a um comando de nova linha, devolvendo o resultado como uma string: 14 | 15 | >>> fin.readline() 16 | 17 | 'aa\\r\\n' 18 | 19 | A primeira palavra nesta lista específica é “aa”, uma espécie de lava. A sequência \\r\\n representa dois caracteres de whitespace, um retorno de carro e uma nova linha, que separa esta palavra da seguinte. 20 | 21 | O objeto de arquivo grava a posição em que está no arquivo, então se você chamar readline mais uma vez, receberá a seguinte palavra: 22 | 23 | >>> fin.readline() 24 | 25 | 'aah\\r\\n' 26 | 27 | A palavra seguinte é “aah”, uma palavra perfeitamente legítima, então pare de olhar para mim desse jeito. Ou, se é o whitespace que está incomodando você, podemos nos livrar dele com o método de string strip: 28 | 29 | >>> line = fin.readline() 30 | 31 | >>> word = line.strip() 32 | 33 | >>> word 34 | 35 | 'aahed' 36 | 37 | Você também pode usar um objeto de arquivo como parte de um loop for. Este programa lê words.txt e imprime cada palavra, uma por linha: 38 | 39 | fin = open('words.txt') 40 | 41 | for line in fin: 42 | 43 |     word = line.strip() 44 | 45 |     print(word) 46 | 47 | Exercícios 48 | 49 | Há soluções para estes exercícios na próxima seção. Mas é bom você tentar fazer cada um antes de ver as soluções. 50 | 51 | Exercício 9.1 52 | 53 | Escreva um programa que leia words.txt e imprima apenas as palavras com mais de 20 caracteres (sem contar whitespace). 54 | 55 | Exercício 9.2 56 | 57 | Em 1939, Ernest Vincent Wright publicou uma novela de 50.000 palavras, chamada Gadsby, que não contém a letra “e”. Como o “e” é a letra mais comum em inglês, isso não é algo fácil de fazer. 58 | 59 | Na verdade, é difícil até construir um único pensamento sem usar o símbolo mais comum do idioma. No início é lento, mas com prudência e horas de treino, vai ficando cada vez mais fácil. 60 | 61 | Muito bem, agora eu vou parar. 62 | 63 | Escreva uma função chamada has\_no\_e que retorne True se a palavra dada não tiver a letra “e” nela. 64 | 65 | Altere seu programa na seção anterior para imprimir apenas as palavras que não têm “e” e calcule a porcentagem de palavras na lista que não têm “e”. 66 | 67 | Exercício 9.3 68 | 69 | Escreva uma função chamada avoids que receba uma palavra e uma série de letras proibidas, e retorne True se a palavra não usar nenhuma das letras proibidas. 70 | 71 | Altere o código para que o usuário digite uma série de letras proibidas e o programa imprima o número de palavras que não contêm nenhuma delas. Você pode encontrar uma combinação de cinco letras proibidas que exclua o menor número possível de palavras? 72 | 73 | Exercício 9.4 74 | 75 | Escreva uma função chamada uses\_only que receba uma palavra e uma série de letras e retorne True, se a palavra só contiver letras da lista. Você pode fazer uma frase usando só as letras acefhlo? Que não seja “Hoe alfalfa?” 76 | 77 | Exercício 9.5 78 | 79 | Escreva uma função chamada uses\_all que receba uma palavra e uma série de letras obrigatórias e retorne True se a palavra usar todas as letras obrigatórias pelo menos uma vez. Quantas palavras usam todas as vogais (aeiou)? E que tal aeiouy? 80 | 81 | Exercício 9.6 82 | 83 | Escreva uma função chamada is\_abecedarian que retorne True se as letras numa palavra aparecerem em ordem alfabética (tudo bem se houver letras duplas). Quantas palavras em ordem alfabética existem? 84 | 85 | Busca 86 | 87 | Todos os exercícios na seção anterior têm algo em comum; eles podem ser resolvidos com o modelo de busca que vimos em “Buscando”, na página 123. O exemplo mais simples é: 88 | 89 | def has\_no\_e(word): 90 | 91 |     for letter in word: 92 | 93 |         if letter == 'e': 94 | 95 |             return False 96 | 97 |     return True 98 | 99 | O loop for atravessa os caracteres em word. Se encontrarmos a letra “e”, podemos retornar False imediatamente; se não for o caso, temos que ir à letra seguinte. Se sairmos do loop normalmente, isso quer dizer que não encontramos um “e”, então retornamos True. 100 | 101 | Você pode escrever esta função de forma mais concisa usando o operador in, mas comecei com esta versão porque ela demonstra a lógica do modelo de busca. 102 | 103 | avoids é uma versão mais geral de has\_no\_e, mas tem a mesma estrutura: 104 | 105 | def avoids(word, forbidden): 106 | 107 |     for letter in word: 108 | 109 |         if letter in forbidden: 110 | 111 |             return False 112 | 113 |     return True 114 | 115 | Podemos retornar False logo que encontrarmos uma letra proibida; se chegarmos ao fim do loop, retornamos True. 116 | 117 | uses\_only é semelhante, exceto pelo sentido da condição, que se inverte: 118 | 119 | def uses\_only(word, available): 120 | 121 |     for letter in word: 122 | 123 |         if letter not in available: 124 | 125 |             return False 126 | 127 |     return True 128 | 129 | Em vez de uma lista de letras proibidas, temos uma lista de letras disponíveis. Se encontrarmos uma letra em word que não está em available, podemos retornar False. 130 | 131 | uses\_all é semelhante, mas invertemos a função da palavra e a string de letras: 132 | 133 | def uses\_all(word, required): 134 | 135 |     for letter in required: 136 | 137 |         if letter not in word: 138 | 139 |             return False 140 | 141 |     return True 142 | 143 | Em vez de atravessar as letras em word, o loop atravessa as letras obrigatórias. Se alguma das letras obrigatórias não aparecer na palavra, podemos retornar False. 144 | 145 | Se você realmente pensasse como um cientista da computação, teria reconhecido que uses\_all foi um exemplo de um problema resolvido anteriormente e escreveria: 146 | 147 | def uses\_all(word, required): 148 | 149 |     return uses\_only(required, word) 150 | 151 | Esse é um exemplo de um plano de desenvolvimento de programa chamado redução a um problema resolvido anteriormente, ou seja, você reconhece o problema no qual está trabalhando como um exemplo de um problema já resolvido e aplica uma solução existente. 152 | 153 | Loop com índices 154 | 155 | Escrevi as funções na seção anterior com loops for porque eu só precisava dos caracteres nas strings; não precisava fazer nada com os índices. 156 | 157 | Para is\_abecedarian temos que comparar letras adjacentes, o que é um pouco complicado para o loop for: 158 | 159 | def is\_abecedarian(word): 160 | 161 |     previous = word\[0\] 162 | 163 |     for c in word: 164 | 165 |         if c < previous: 166 | 167 |             return False 168 | 169 |         previous = c 170 | 171 |     return True 172 | 173 | Uma alternativa é usar a recursividade: 174 | 175 | def is\_abecedarian(word): 176 | 177 |     if len(word) <= 1: 178 | 179 |         return True 180 | 181 |     if word\[0\] > word\[1\]: 182 | 183 |         return False 184 | 185 |     return is\_abecedarian(word\[1:\]) 186 | 187 | Outra opção é usar um loop while: 188 | 189 | def is\_abecedarian(word): 190 | 191 |     i = 0 192 | 193 |     while i < len(word)-1: 194 | 195 |         if word\[i+1\] < word\[i\]: 196 | 197 |             return False 198 | 199 |         i = i+1 200 | 201 |     return True 202 | 203 | O loop começa em i=0 e termina quando i=len(word)-1. Cada vez que passa pelo loop, o programa compara o “i-ésimo” caractere (que você pode considerar o caractere atual) com o caractere de posição i+1(que pode ser considerado o caractere seguinte). 204 | 205 | Se o próximo caractere for de uma posição anterior (alfabeticamente anterior) à atual, então descobrimos uma quebra na tendência alfabética, e retornamos False. 206 | 207 | Se chegarmos ao fim do loop sem encontrar uma quebra, então a palavra passa no teste. Para convencer-se de que o loop termina corretamente, considere um exemplo como 'flossy'. O comprimento da palavra é 6, então o loop é executado pela última vez quando i for igual a 4, que é o índice do segundo caractere de trás para frente. Na última iteração, o programa compara o penúltimo caractere com o último, que é o que queremos. 208 | 209 | Aqui está uma versão de is\_palindrome (veja o Exercício 6.3) que usa dois índices: um começa no início e aumenta; o outro começa no final e diminui. 210 | 211 | def is\_palindrome(word): 212 | 213 |     i = 0 214 | 215 |     j = len(word)-1 216 | 217 |     while i<j: 218 | 219 |         if word\[i\] != word\[j\]: 220 | 221 |             return False 222 | 223 |         i = i+1 224 | 225 |         j = j-1 226 | 227 |     return True 228 | 229 | Ou podemos reduzir a um problema resolvido anteriormente e escrever: 230 | 231 | def is\_palindrome(word): 232 | 233 |     return is\_reverse(word, word) 234 | 235 | Usando is\_reverse da Figura 8.2. 236 | 237 | Depuração 238 | 239 | Testar programas é difícil. As funções neste capítulo são relativamente fáceis para testar porque é possível verificar os resultados à mão. Ainda assim, pode ser difícil ou até impossível escolher um grupo de palavras que teste todos os erros possíveis. 240 | 241 | Tomando has\_no\_e como exemplo, há dois casos óbvios para verificar: as palavras que têm um ‘e’ devem retornar False, e as palavras que não têm devem retornar True. Não deverá ser um problema pensar em um exemplo de cada uma. 242 | 243 | Dentro de cada caso, há alguns subcasos menos óbvios. Entre as palavras que têm um “e”, você deve testar palavras com um “e” no começo, no fim e em algum lugar no meio. Você deve testar palavras longas, palavras curtas e palavras muito curtas, como a string vazia. A string vazia é um exemplo de um caso especial, não óbvio, onde erros muitas vezes espreitam. 244 | 245 | Além dos casos de teste que você gerar, também pode ser uma boa ideia testar seu programa com uma lista de palavras como words.txt. Ao analisar a saída, pode ser que os erros apareçam, mas tenha cuidado: você pode pegar um tipo de erro (palavras que não deveriam ser incluídas, mas foram) e não outro (palavras que deveriam ser incluídas, mas não foram). 246 | 247 | Em geral, o teste pode ajudar a encontrar bugs, mas não é fácil gerar um bom conjunto de casos de teste, e, mesmo se conseguir, não há como ter certeza de que o programa está correto. Segundo um lendário cientista da computação: 248 | 249 | Testar programas pode ser usado para mostrar a presença de bugs, mas nunca para mostrar a ausência deles! – Edsger W. Dijkstra 250 | 251 | Glossário 252 | 253 | objeto de arquivo: 254 | 255 | Um valor que representa um arquivo aberto. 256 | 257 | redução a um problema resolvido anteriormente: 258 | 259 | Um modo de resolver um problema expressando-o como uma instância de um problema resolvido anteriormente. 260 | 261 | caso especial: 262 | 263 | Um caso de teste que é atípico ou não é óbvio (e com probabilidade menor de ser tratado corretamente). 264 | 265 | Exercícios 266 | 267 | Exercício 9.7 268 | 269 | Esta pergunta é baseada em um quebra-cabeça veiculado em um programa de rádio chamado Car Talk (http://www.cartalk.com/content/puzzlers): 270 | 271 | Dê uma palavra com três letras duplas consecutivas. Vou dar exemplos de palavras que quase cumprem a condição, mas não chegam lá. Por exemplo, a palavra committee, c-o-m-m-i-t-t-e-e. Seria perfeita se não fosse aquele ‘i’ que se meteu ali no meio. Ou Mississippi: M-i-s-s-i-s-s-i-p-p-i. Se pudesse tirar aqueles ‘is’, daria certo. Mas há uma palavra que tem três pares consecutivos de letras e, que eu saiba, pode ser a única palavra que existe. É claro que provavelmente haja mais umas 500, mas só consigo pensar nessa. Qual é a palavra? 272 | 273 | Escreva um programa que a encontre. 274 | 275 | Solução: http://thinkpython2.com/code/cartalk1.py. 276 | 277 | Exercício 9.8 278 | 279 | Aqui está outro quebra-cabeça do programa Car Talk (http://www.cartalk.com/content/puzzlers): 280 | 281 | “Estava dirigindo outro dia e percebi algo no hodômetro que chamou a minha atenção. Como a maior parte dos hodômetros, ele mostra seis dígitos, apenas em milhas inteiras. Por exemplo, se o meu carro tivesse 300.000 milhas, eu veria 3-0-0-0-0-0. 282 | 283 | “Agora, o que vi naquele dia foi muito interessante. Notei que os últimos 4 dígitos eram um palíndromo; isto é, podiam ser lidos da mesma forma no sentido correto e no sentido inverso. Por exemplo, 5-4-4-5 é um palíndromo, então no meu hodômetro poderia ser 3-1-5-4-4-5. 284 | 285 | “Uma milha depois, os últimos 5 números formaram um palíndromo. Por exemplo, poderia ser 3-6-5-4-5-6. Uma milha depois disso, os 4 números do meio, dentro dos 6, formavam um palíndromo. E adivinhe só? Um milha depois, todos os 6 formavam um palíndromo! 286 | 287 | “A pergunta é: o que estava no hodômetro quando olhei primeiro?” 288 | 289 | Escreva um programa Python que teste todos os números de seis dígitos e imprima qualquer número que satisfaça essas condições. 290 | 291 | Solução: http://thinkpython2.com/code/cartalk2.py. 292 | 293 | Exercício 9.9 294 | 295 | Aqui está outro problema do Car Talk que você pode resolver com uma busca (http://www.cartalk.com/content/puzzlers): 296 | 297 | “Há pouco tempo recebi uma visita da minha mãe e percebemos que os dois dígitos que compõem a minha idade, quando invertidos, representavam a idade dela. Por exemplo, se ela tem 73 anos, eu tenho 37 anos. Ficamos imaginando com que frequência isto aconteceu nos anos anteriores, mas acabamos mudando de assunto e não chegamos a uma resposta. 298 | 299 | “Quando cheguei em casa, cheguei à conclusão de que os dígitos das nossas idades tinham sido reversíveis seis vezes até então. Também percebi que, se tivéssemos sorte, isso aconteceria novamente dali a alguns anos, e se fôssemos muito sortudos, aconteceria mais uma vez depois disso. Em outras palavras, aconteceria 8 vezes no total. Então a pergunta é: quantos anos tenho agora?” 300 | 301 | Escreva um programa em Python que busque soluções para esse problema. Dica: pode ser uma boa ideia usar o método de string zfill. 302 | 303 | Solução: http://thinkpython2.com/code/cartalk3.py. 304 | 305 | -------------------------------------------------------------------------------- /recebido/capitulos/15-classes-objetos.md: -------------------------------------------------------------------------------- 1 | # Capítulo 15: Classes e objetos 2 | 3 | A esta altura você já sabe como usar funções para organizar código e tipos integrados para organizar dados. O próximo passo é aprender “programação orientada a objeto”, que usa tipos definidos pelos programadores para organizar tanto o código quanto os dados. A programação orientada a objeto é um tópico abrangente; será preciso passar por alguns capítulos para abordar o tema. 4 | 5 | Os exemplos de código deste capítulo estão disponíveis em http://thinkpython2.com/code/Point1.py; as soluções para os exercícios estão disponíveis em http://thinkpython2.com/code/Point1\_soln.py. 6 | 7 | Tipos definidos pelos programadores 8 | 9 | Já usamos muitos tipos integrados do Python; agora vamos definir um tipo próprio. Como exemplo, criaremos um tipo chamado Point, que representa um ponto no espaço bidimensional. 10 | 11 | Na notação matemática, os pontos muitas vezes são escritos entre parênteses, com uma vírgula separando as coordenadas. Por exemplo, (0,0) representa a origem e (x, y) representa o ponto que está x unidades à direita e y unidades a partir da origem. 12 | 13 | Há várias formas para representar pontos no Python: 14 | 15 | •        Podemos armazenar as coordenadas separadamente em duas variáveis, x e y. 16 | 17 | •        Podemos armazenar as coordenadas como elementos em uma lista ou tupla. 18 | 19 | •        Podemos criar um tipo para representar pontos como objetos. 20 | 21 | Criar um tipo é mais complicado que outras opções, mas tem vantagens que logo ficarão evidentes. 22 | 23 | Um tipo definido pelo programador também é chamado de classe. Uma definição de classe pode ser assim: 24 | 25 | class Point: 26 | 27 |     """Represents a point in 2-D space.""" 28 | 29 | O cabeçalho indica que a nova classe se chama Point. O corpo é uma docstring que explica para que a classe serve. Você pode definir variáveis e métodos dentro de uma definição de classe, mas voltaremos a isso depois. 30 | 31 | Definir uma classe denominada Point cria um objeto de classe: 32 | 33 | >>> Point 34 | 35 | <class '\_\_main\_\_.Point'> 36 | 37 | Como Point é definido no nível superior, seu “nome completo” é \_\_main\_\_.Point. 38 | 39 | O objeto de classe é como uma fábrica para criar objetos. Para criar um Point, você chama Point como se fosse uma função: 40 | 41 | >>> blank = Point() 42 | 43 | >>> blank 44 | 45 | <\_\_main\_\_.Point object at 0xb7e9d3ac> 46 | 47 | O valor de retorno é uma referência a um objeto Point, ao qual atribuímos blank. 48 | 49 | Criar um objeto chama-se instanciação, e o objeto é uma instância da classe. 50 | 51 | Quando você exibe uma instância, o Python diz a que classe ela pertence e onde está armazenada na memória (o prefixo o 0x significa que o número seguinte está em formato hexadecimal). 52 | 53 | Cada objeto é uma instância de alguma classe, então “objeto” e “instância” são intercambiáveis. Porém, neste capítulo uso “instância” para indicar que estou falando sobre um tipo definido pelo programador. 54 | 55 | Atributos 56 | 57 | Você pode atribuir valores a uma instância usando a notação de ponto: 58 | 59 | >>> blank.x = 3.0 60 | 61 | >>> blank.y = 4.0 62 | 63 | Essa sintaxe é semelhante à usada para selecionar uma variável de um módulo, como math.pi ou string.whitespace. Nesse caso, entretanto, estamos atribuindo valores a elementos nomeados de um objeto. Esses elementos chamam-se atributos. 64 | 65 | Em inglês, quando é um substantivo, a palavra “AT-trib-ute” é pronunciada com ênfase na primeira sílaba, ao contrário de “a-TRIB-ute”, que é um verbo. 66 | 67 | O diagrama seguinte mostra o resultado dessas atribuições. Um diagrama de estado que mostra um objeto e seus atributos chama-se diagrama de objeto; veja a Figura 15.1. 68 | 69 | Figura 15.1 – Diagrama de objeto. 70 | 71 | A variável blank refere-se a um objeto Point, que contém dois atributos. Cada atributo refere-se a um número de ponto flutuante. 72 | 73 | Você pode ler o valor de um atributo usando a mesma sintaxe: 74 | 75 | >>> blank.y 76 | 77 | 4.0 78 | 79 | >>> x = blank.x 80 | 81 | >>> x 82 | 83 | 3.0 84 | 85 | A expressão blank.x significa “Ir ao objeto a que blank se refere e obter o valor de x”. No exemplo, atribuímos este valor a uma variável x. Não há nenhum conflito entre a variável x e o atributo x. 86 | 87 | Você pode usar a notação de ponto como parte de qualquer expressão. Por exemplo: 88 | 89 | >>> '(%g, %g)' % (blank.x, blank.y) 90 | 91 | '(3.0, 4.0)' 92 | 93 | >>> distance = math.sqrt(blank.x\*\*2 + blank.y\*\*2) 94 | 95 | >>> distance 96 | 97 | 5.0 98 | 99 | Você pode passar uma instância como argumento da forma habitual. Por exemplo: 100 | 101 | def print\_point(p): 102 | 103 |     print('(%g, %g)' % (p.x, p.y)) 104 | 105 | print\_point toma um ponto como argumento e o exibe em notação matemática. Para invocá-lo, você pode passar blank como argumento: 106 | 107 | >>> print\_point(blank) 108 | 109 | (3.0, 4.0) 110 | 111 | Dentro da função, p é um alias para blank, então, se a função altera p, blank também muda. 112 | 113 | Como exercício, escreva uma função chamada distance\_between\_points, que toma dois pontos como argumentos e retorna a distância entre eles. 114 | 115 | Retângulos 116 | 117 | Às vezes, é óbvio quais deveriam ser os atributos de um objeto, mas outras é preciso decidir entre as possibilidades. Por exemplo, vamos supor que você esteja criando uma classe para representar retângulos. Que atributos usaria para especificar a posição e o tamanho de um retângulo? Você pode ignorar ângulo; para manter as coisas simples, suponha que o retângulo seja vertical ou horizontal. 118 | 119 | Há duas possibilidades, no mínimo: 120 | 121 | •        Você pode especificar um canto do retângulo (ou o centro), a largura e a altura. 122 | 123 | •        Você pode especificar dois cantos opostos. 124 | 125 | Nesse ponto é difícil dizer qual opção é melhor, então implementaremos a primeira, como exemplo. 126 | 127 | Aqui está a definição de classe: 128 | 129 | class Rectangle: 130 | 131 |     """Represents a rectangle. 132 | 133 |     attributes: width, height, corner. 134 | 135 |     """ 136 | 137 | A docstring lista os atributos: width e height são números; corner é um objeto Point que especifica o canto inferior esquerdo. 138 | 139 | Para representar um retângulo, você tem que instanciar um objeto Rectangle e atribuir valores aos atributos: 140 | 141 | box = Rectangle() 142 | 143 | box.width = 100.0 144 | 145 | box.height = 200.0 146 | 147 | box.corner = Point() 148 | 149 | box.corner.x = 0.0 150 | 151 | box.corner.y = 0.0 152 | 153 | A expressão box.corner.x significa “Vá ao objeto ao qual box se refere e selecione o atributo denominado corner; então vá a este objeto e selecione o atributo denominado x”. 154 | 155 | A Figura 15.2 mostra o estado deste objeto. Um objeto que é um atributo de outro objeto é integrado. 156 | 157 | Figura 15.2 – Diagrama de objeto. 158 | 159 | Instâncias como valores de retorno 160 | 161 | As funções podem retornar instâncias. Por exemplo, find\_center recebe Rectangle como argumento e retorna Point, que contém as coordenadas do centro de Rectangle: 162 | 163 | def find\_center(rect): 164 | 165 |     p = Point() 166 | 167 |     p.x = rect.corner.x + rect.width/2 168 | 169 |     p.y = rect.corner.y + rect.height/2 170 | 171 |     return p 172 | 173 | Aqui está um exemplo que passa box como um argumento e atribui o ponto resultante a center: 174 | 175 | >>> center = find\_center(box) 176 | 177 | >>> print\_point(center) 178 | 179 | (50, 100) 180 | 181 | Objetos são mutáveis 182 | 183 | Você pode alterar o estado de um objeto fazendo uma atribuição a um dos seus atributos. Por exemplo, para mudar o tamanho de um retângulo sem mudar sua posição, você pode alterar os valores de width e height: 184 | 185 | box.width = box.width + 50 186 | 187 | box.height = box.height + 100 188 | 189 | Você também pode escrever funções que alteram objetos. Por exemplo, grow\_rectangle recebe um objeto Rectangle e dois números, dwidth e dheight, e adiciona os números à largura e altura do retângulo: 190 | 191 | def grow\_rectangle(rect, dwidth, dheight): 192 | 193 |     rect.width += dwidth 194 | 195 |     rect.height += dheight 196 | 197 | Aqui está um exemplo que demonstra o efeito: 198 | 199 | >>> box.width, box.height 200 | 201 | (150.0, 300.0) 202 | 203 | >>> grow\_rectangle(box, 50, 100) 204 | 205 | >>> box.width, box.height 206 | 207 | (200.0, 400.0) 208 | 209 | Dentro da função, rect é um alias de box, então quando a função altera rect, box também muda. 210 | 211 | Como exercício, escreva uma função chamada move\_rectangle que toma um Rectangle e dois números chamados dx e dy. Ela deve alterar a posição do retângulo, adicionando dx à coordenada x de corner e adicionando dy à coordenada y de corner. 212 | 213 | Cópia 214 | 215 | Alias podem tornar um programa difícil de ler porque as alterações em um lugar podem ter efeitos inesperados em outro lugar. É difícil monitorar todas as variáveis que podem referir-se a um dado objeto. 216 | 217 | Em vez de usar alias, copiar o objeto pode ser uma alternativa. O módulo copy contém uma função chamada copy que pode duplicar qualquer objeto: 218 | 219 | >>> p1 = Point() 220 | 221 | >>> p1.x = 3.0 222 | 223 | >>> p1.y = 4.0 224 | 225 | >>> import copy 226 | 227 | >>> p2 = copy.copy(p1) 228 | 229 | p1 e p2 contêm os mesmos dados, mas não são o mesmo Point: 230 | 231 | >>> print\_point(p1) 232 | 233 | (3, 4) 234 | 235 | >>> print\_point(p2) 236 | 237 | (3, 4) 238 | 239 | >>> p1 is p2 240 | 241 | False 242 | 243 | >>> p1 == p2 244 | 245 | False 246 | 247 | O operador is indica que p1 e p2 não são o mesmo objeto, que é o que esperamos. Porém, você poderia ter esperado que == fosse apresentado como True, porque esses pontos contêm os mesmos dados. Nesse caso, pode ficar desapontado ao saber que, para instâncias, o comportamento-padrão do operador == é o mesmo que o do operador is; ele verifica a identidade dos objetos, não a sua equivalência. Isso acontece porque, para tipos definidos pelo programador, o Python não sabe o que deve ser considerado equivalente. Pelo menos, ainda não. 248 | 249 | Se você usar copy.copy para duplicar um retângulo, descobrirá que ele copia o objeto Rectangle, mas não o Point integrado: 250 | 251 | >>> box2 = copy.copy(box) 252 | 253 | >>> box2 is box 254 | 255 | False 256 | 257 | >>> box2.corner is box.corner 258 | 259 | True 260 | 261 | A Figura 15.3 mostra como fica o diagrama de objeto. Esta operação chama-se cópia superficial porque copia o objeto e qualquer referência que contenha, mas não os objetos integrados. 262 | 263 | Figura 15.3 – Diagrama de objeto. 264 | 265 | Para a maior parte das aplicações, não é isso que você quer. Nesse exemplo, invocar grow\_rectangle em um dos Rectangles não afetaria o outro, mas invocar move\_rectangle em qualquer um deles afetaria a ambos! Esse comportamento é confuso e propenso a erros. 266 | 267 | Felizmente, o módulo copy oferece um método chamado deepcopy que copia não só o objeto, mas também os objetos aos quais ele se refere, e os objetos aos quais estes se referem, e assim por diante. Você não se surpreenderá ao descobrir que esta operação se chama cópia profunda. 268 | 269 | >>> box3 = copy.deepcopy(box) 270 | 271 | >>> box3 is box 272 | 273 | False 274 | 275 | >>> box3.corner is box.corner 276 | 277 | False 278 | 279 | box3 e box são objetos completamente separados. 280 | 281 | Como exercício, escreva uma versão de move\_rectangle que cria e retorne um novo retângulo em vez de alterar o antigo. 282 | 283 | Depuração 284 | 285 | Ao começar a trabalhar com objetos, provavelmente você encontrará algumas novas exceções. Se tentar acessar um atributo que não existe, recebe um AttributeError: 286 | 287 | >>> p = Point() 288 | 289 | >>> p.x = 3 290 | 291 | >>> p.y = 4 292 | 293 | >>> p.z 294 | 295 | AttributeError: Point instance has no attribute 'z' 296 | 297 | Se não estiver certo sobre o tipo que um objeto é, pode perguntar: 298 | 299 | >>> type(p) 300 | 301 | <class '\_\_main\_\_.Point'> 302 | 303 | Você também pode usar isinstance para verificar se um objeto é uma instância de uma classe: 304 | 305 | >>> isinstance(p, Point) 306 | 307 | True 308 | 309 | Caso não tenha certeza se um objeto tem determinado atributo, você pode usar a função integrada hasattr: 310 | 311 | >>> hasattr(p, 'x') 312 | 313 | True 314 | 315 | >>> hasattr(p, 'z') 316 | 317 | False 318 | 319 | O primeiro argumento pode ser qualquer objeto; o segundo argumento é uma string que contém o nome do atributo. 320 | 321 | Você também pode usar uma instrução try para ver se o objeto tem os atributos de que precisa: 322 | 323 | try: 324 | 325 |     x = p.x 326 | 327 | except AttributeError: 328 | 329 |     x = 0 330 | 331 | Essa abordagem pode facilitar a escrita de funções que atuam com tipos diferentes; você verá mais informações sobre isso em “Polimorfismo”, na página 248. 332 | 333 | Glossário 334 | 335 | classe: 336 | 337 | Tipo definido pelo programador. Uma definição de classe cria um objeto de classe. 338 | 339 | objeto de classe: 340 | 341 | Objeto que contém a informação sobre um tipo definido pelo programador. O objeto de classe pode ser usado para criar instâncias do tipo. 342 | 343 | instância: 344 | 345 | Objeto que pertence a uma classe. 346 | 347 | instanciar: 348 | 349 | Criar um objeto. 350 | 351 | atributo: 352 | 353 | Um dos valores denominados associados a um objeto. 354 | 355 | objeto integrado: 356 | 357 | Objeto que é armazenado como um atributo de outro objeto. 358 | 359 | cópia superficial: 360 | 361 | Copiar o conteúdo de um objeto, inclusive qualquer referência a objetos integrados; implementada pela função copy no módulo copy. 362 | 363 | cópia profunda: 364 | 365 | Copiar o conteúdo de um objeto, bem como qualquer objeto integrado, e qualquer objeto integrado a estes, e assim por diante; implementado pela função deepcopy no módulo copy. 366 | 367 | diagrama de objeto: 368 | 369 | Diagrama que mostra objetos, seus atributos e os valores dos atributos. 370 | 371 | Exercícios 372 | 373 | Exercício 15.1 374 | 375 | Escreva uma definição para uma classe denominada Circle, com os atributos center e radius, onde center é um objeto Point e radius é um número. 376 | 377 | Instancie um objeto Circle, que represente um círculo com o centro em 150, 100 e raio 75. 378 | 379 | Escreva uma função denominada point\_in\_circle, que tome um Circle e um Point e retorne True, se o ponto estiver dentro ou no limite do círculo. 380 | 381 | Escreva uma função chamada rect\_in\_circle, que tome um Circle e um Rectangle e retorne True, se o retângulo estiver totalmente dentro ou no limite do círculo. 382 | 383 | Escreva uma função denominada rect\_circle\_overlap, que tome um Circle e um Rectangle e retorne True, se algum dos cantos do retângulo cair dentro do círculo. Ou, em uma versão mais desafiadora, retorne True se alguma parte do retângulo cair dentro do círculo. 384 | 385 | Solução: http://thinkpython2.com/code/Circle.py. 386 | 387 | Exercício 15.2 388 | 389 | Escreva uma função chamada draw\_rect que receba um objeto Turtle e um Rectangle e use o Turtle para desenhar o retângulo. Veja no Capítulo 4 os exemplos de uso de objetos Turtle. 390 | 391 | Escreva uma função chamada draw\_circle, que tome um Turtle e um Circle e desenhe o círculo. 392 | 393 | Solução: http://thinkpython2.com/code/draw.py. 394 | 395 | -------------------------------------------------------------------------------- /recebido/capitulos/16-classes-funcoes.md: -------------------------------------------------------------------------------- 1 | # Capítulo 16: Classes e funções 2 | 3 | Agora que sabemos como criar tipos, o próximo passo deve ser escrever funções que recebam objetos definidos pelo programador como parâmetros e os retornem como resultados. Neste capítulo também vou apresentar o “estilo funcional de programação” e dois novos planos de desenvolvimento de programas. 4 | 5 | Os exemplos de código deste capítulo estão disponíveis em http://thinkpython2.com/code/Time1.py. As soluções para os exercícios estão em http://thinkpython2.com/code/Time1\_soln.py. 6 | 7 | Time 8 | 9 | Para ter mais um exemplo de tipo definido pelo programador, criaremos uma classe chamada Time, que registra o período do dia. A definição da classe é assim: 10 | 11 | class Time: 12 | 13 |     """Represents the time of day. 14 | 15 |     attributes: hour, minute, second 16 | 17 |     """ 18 | 19 | Podemos criar um objeto Time e ter atributos para horas, minutos e segundos: 20 | 21 | time = Time() 22 | 23 | time.hour = 11 24 | 25 | time.minute = 59 26 | 27 | time.second = 30 28 | 29 | O diagrama de estado do objeto Time está na Figura 16.1. 30 | 31 | Como exercício, escreva uma função chamada print\_time, que receba um objeto Time e o exiba na forma hour:minute:second. Dica: a sequência de formatação '%.2d' exibe um número inteiro com, pelo menos, dois dígitos, incluindo um zero à esquerda, se for necessário. 32 | 33 | Escreva uma função booleana chamada is\_after, que receba dois objetos Time, t1 e t2, e retorne True se t1 for seguido por t2 cronologicamente e False se não for. Desafio: não use uma instrução if. 34 | 35 | Figura 16.1 – Diagrama de objeto. 36 | 37 | Funções puras 38 | 39 | Nas próximas seções, vamos escrever duas funções que adicionam valores de tempo. Elas demonstram dois tipos de funções: funções puras e modificadores. Também demonstram um plano de desenvolvimento que chamarei de protótipo e correção, que é uma forma de atacar um problema complexo começando com um protótipo simples e lidando com as complicações de forma incremental. 40 | 41 | Aqui está um protótipo simples de add\_time: 42 | 43 | def add\_time(t1, t2): 44 | 45 |     sum = Time() 46 | 47 |     sum.hour = t1.hour + t2.hour 48 | 49 |     sum.minute = t1.minute + t2.minute 50 | 51 |     sum.second = t1.second + t2.second 52 | 53 |     return sum 54 | 55 | A função cria um novo objeto Time, inicializa seus atributos e retorna uma referência ao novo objeto. A função pura é chamada assim porque não altera nenhum dos objetos passados a ela como argumentos; além disso, ela não tem efeitos, como exibir um valor ou receber entradas de usuário, apenas retorna um valor. 56 | 57 | Para testar esta função, criarei objetos Time: start, que contém o tempo de início de um filme, como Monty Python e o cálice sagrado, e duration, que contém o tempo de execução do filme, que é de 1 hora e 35 minutos. 58 | 59 | add\_time calcula quando o filme acaba: 60 | 61 | >>> start = Time() 62 | 63 | >>> start.hour = 9 64 | 65 | >>> start.minute = 45 66 | 67 | >>> start.second = 0 68 | 69 | >>> duration = Time() 70 | 71 | >>> duration.hour = 1 72 | 73 | >>> duration.minute = 35 74 | 75 | >>> duration.second = 0 76 | 77 | >>> done = add\_time(start, duration) 78 | 79 | >>> print\_time(done) 80 | 81 | 10:80:00 82 | 83 | O resultado, 10:80:00, pode não ser o que você esperava. O problema é que esta função não trata casos onde o número de segundos ou minutos é maior que 60. Quando isso acontece, precisamos “transportar” os segundos extras à coluna dos minutos ou os minutos extras à coluna das horas. 84 | 85 | Aqui está uma versão melhorada: 86 | 87 | def add\_time(t1, t2): 88 | 89 |     sum = Time() 90 | 91 |     sum.hour = t1.hour + t2.hour 92 | 93 |     sum.minute = t1.minute + t2.minute 94 | 95 |     sum.second = t1.second + t2.second 96 | 97 |     if sum.second >= 60: 98 | 99 |         sum.second -= 60 100 | 101 |         sum.minute += 1 102 | 103 |     if sum.minute >= 60: 104 | 105 |         sum.minute -= 60 106 | 107 |         sum.hour += 1 108 | 109 |     return sum 110 | 111 | Embora esta função esteja correta, é um pouco extensa. Veremos uma alternativa menor mais adiante. 112 | 113 | Modificadores 114 | 115 | Às vezes é útil uma função alterar os objetos que recebe como parâmetros. Nesse caso, as mudanças são visíveis a quem chama a função. As funções que fazem isso chamam-se modificadores. 116 | 117 | increment, que acrescenta um dado número de segundos a um objeto Time, pode ser escrita naturalmente como um modificador. Aqui está um primeiro esboço: 118 | 119 | def increment(time, seconds): 120 | 121 |     time.second += seconds 122 | 123 |     if time.second >= 60: 124 | 125 |         time.second -= 60 126 | 127 |         time.minute += 1 128 | 129 |     if time.minute >= 60: 130 | 131 |         time.minute -= 60 132 | 133 |         time.hour += 1 134 | 135 | A primeira linha executa a operação básica; o resto lida com os casos especiais que vimos antes. 136 | 137 | Esta função está correta? O que acontece se second for muito mais que 60? 138 | 139 | Neste caso não basta transportar uma vez, temos que continuar fazendo isso até que time.second seja menos de 60. Uma solução é substituir a instrução if pela instrução while. Isso tornaria a função correta, mas não muito eficiente. Como exercício, escreva uma versão correta de increment que não contenha loops. 140 | 141 | O que se faz com modificadores também pode ser feito com funções puras. Na verdade, algumas linguagens de programação só permitem funções puras. Há evidências de que os programas que usam funções puras são mais rápidos para serem desenvolvidos e menos propensos a erros que programas que usam modificadores. No entanto, modificadores são convenientes de vez em quando, e os programas funcionais tendem a ser menos eficientes. 142 | 143 | De forma geral, recomendo que você escreva funções puras sempre que achar razoável e recorra a modificadores só se houver alguma vantagem clara. Esta abordagem pode ser chamada de estilo funcional de programação. 144 | 145 | Como exercício, escreva uma versão “pura” de increment que cria e retorna um objeto Time em vez de alterar o parâmetro. 146 | 147 | Prototipação versus planejamento 148 | 149 | O plano de desenvolvimento que estou demonstrando chama-se “protótipo e correção”. Para cada função, escrevi um protótipo que executa o cálculo básico e então testa a função, corrigindo erros no decorrer do caminho. 150 | 151 | Esta abordagem pode ser eficaz, especialmente se você ainda não tem uma compreensão profunda do problema. Porém, as correções incrementais podem gerar código que se complica desnecessariamente (pois trata de muitos casos especiais) e pouco confiáveis (já que é difícil saber se todos os erros foram encontrados). 152 | 153 | Uma alternativa é o desenvolvimento planejado, no qual a compreensão de alto nível do problema pode facilitar muito a programação. Neste caso, descobre-se que um objeto Time é, na verdade, um número de três dígitos na base 60 (veja http://en.wikipedia.org/wiki/Sexagesimal)! O atributo second é a “coluna de unidades”, o atributo minute é a “coluna dos 60”, e o atributo hour é a “coluna do 3.600”. 154 | 155 | Quando escrevemos add\_time e increment, estávamos na verdade fazendo adições na base 60, e por isso transportávamos os resultados de uma coluna à seguinte. 156 | 157 | Essa observação sugere outra abordagem para o problema inteiro – podemos converter objetos Time em números inteiros e aproveitar o fato de que o computador sabe trabalhar com aritmética de números inteiros. 158 | 159 | Aqui está uma função que converte objetos Time em números inteiros: 160 | 161 | def time\_to\_int(time): 162 | 163 |     minutes = time.hour \* 60 + time.minute 164 | 165 |     seconds = minutes \* 60 + time.second 166 | 167 |     return seconds 168 | 169 | E aqui está uma função que converte um número inteiro em um Time (lembre-se de que divmod divide o primeiro argumento pelo segundo e devolve o quociente e o resto como uma tupla): 170 | 171 | def int\_to\_time(seconds): 172 | 173 |     time = Time() 174 | 175 |     minutes, time.second = divmod(seconds, 60) 176 | 177 |     time.hour, time.minute = divmod(minutes, 60) 178 | 179 |     return time 180 | 181 | Você pode ter que pensar um pouco e fazer alguns testes, para se convencer de que essas funções estão corretas. Um modo de testá-las é ver se time\_to\_int (int\_to\_time (x)) == x para muitos valores de x. Este é um exemplo de uma verificação de consistência. 182 | 183 | Uma vez que esteja convencido de que estão corretas, você pode usá-las para reescrever add\_time: 184 | 185 | def add\_time(t1, t2): 186 | 187 |     seconds = time\_to\_int(t1) + time\_to\_int(t2) 188 | 189 |     return int\_to\_time(seconds) 190 | 191 | Esta versão é mais curta que a original, e mais fácil de verificar. Como exercício, reescreva increment usando time\_to\_int e int\_to\_time. 192 | 193 | Em algumas situações, converter da base 60 para a base 10 e de volta é mais difícil que apenas lidar com as horas. A conversão de base é mais abstrata; nossa intuição para lidar com valores temporais é melhor. 194 | 195 | No entanto, se tivermos discernimento para lidar com horas como números de base 60 e investirmos esforço em escrever as funções de conversão (time\_to\_int e int\_to\_time), chegamos a um programa que é mais curto, mais fácil de ler e depurar, e mais confiável. 196 | 197 | Também é mais fácil acrescentar recursos depois. Por exemplo, imagine subtrair dois objetos Time para encontrar a duração entre eles. Uma abordagem ingênua seria implementar a subtração com transporte. Porém, usar funções de conversão seria mais fácil e, provavelmente, mais correto. 198 | 199 | Ironicamente, tornar um problema mais difícil (ou mais geral) facilita (porque há menos casos especiais e menos oportunidades de erro). 200 | 201 | Depuração 202 | 203 | Um objeto Time é bem formado se os valores de minute e second estiverem entre 0 e 60 (incluindo 0, mas não 60) e se hour for positivo. hour e minute devem ser valores integrais, mas podemos permitir que second tenha uma parte fracionária. 204 | 205 | Requisitos como esses chamam-se invariáveis porque sempre devem ser verdadeiros. Para dizer de outra forma, se não forem verdadeiros, algo deu errado. 206 | 207 | Escrever código para verificar requisitos invariáveis pode ajudar a descobrir erros e encontrar suas causas. Por exemplo, você pode ter uma função como valid\_time, que receba um objeto Time e retorne False se ele violar um requisito invariável: 208 | 209 | def valid\_time(time): 210 | 211 |     if time.hour < 0 or time.minute < 0 or time.second < 0: 212 | 213 |         return False 214 | 215 |     if time.minute >= 60 or time.second >= 60: 216 | 217 |         return False 218 | 219 |     return True 220 | 221 | No início de cada função você pode verificar os argumentos para ter certeza de que são válidos: 222 | 223 | def add\_time(t1, t2): 224 | 225 |     if not valid\_time(t1) or not valid\_time(t2): 226 | 227 |         raise ValueError('invalid Time object in add\_time') 228 | 229 |     seconds = time\_to\_int(t1) + time\_to\_int(t2) 230 | 231 |     return int\_to\_time(seconds) 232 | 233 | Ou você pode usar uma instrução assert, que verifica determinado requisito invariável e cria uma exceção se ela falhar: 234 | 235 | def add\_time(t1, t2): 236 | 237 |     assert valid\_time(t1) and valid\_time(t2) 238 | 239 |     seconds = time\_to\_int(t1) + time\_to\_int(t2) 240 | 241 |     return int\_to\_time(seconds) 242 | 243 | Instruções assert são úteis porque distinguem o código que lida com condições normais do código que verifica erros. 244 | 245 | Glossário 246 | 247 | protótipo e correção: 248 | 249 | Plano de desenvolvimento no qual a escrita do programa parte de um esboço inicial, e depois segue ao teste e correção de erros, conforme sejam encontrados. 250 | 251 | desenvolvimento planejado: 252 | 253 | Plano de desenvolvimento que implica uma compreensão de alto nível do problema e mais planejamento que desenvolvimento incremental ou desenvolvimento prototipado. 254 | 255 | função pura: 256 | 257 | Função que não altera nenhum dos objetos que recebe como argumento. A maior parte das funções puras gera resultado. 258 | 259 | modificador: 260 | 261 | Função que modifica um ou vários dos objetos que recebe como argumento. A maior parte dos modificadores são nulos; isto é, retornam None. 262 | 263 | estilo funcional de programação: 264 | 265 | Estilo de projeto de programa no qual a maioria das funções são puras. 266 | 267 | invariável: 268 | 269 | Condição que sempre deve ser verdadeira durante a execução de um programa. 270 | 271 | instrução assert: 272 | 273 | Instrução que verifica uma condição e levanta uma exceção se esta falhar. 274 | 275 | Exercícios 276 | 277 | Os exemplos de código deste capítulo estão disponíveis em http://thinkpython2.com/code/Time1.py; as soluções para os exercícios estão disponíveis em http://thinkpython2.com/code/Time1\_soln.py. 278 | 279 | Exercício 16.1 280 | 281 | Escreva uma função chamada mul\_time que receba um objeto Time e um número e retorne um novo objeto Time que contenha o produto do Time original e do número. 282 | 283 | Então use mul\_time para escrever uma função que receba um objeto Time representando o tempo até o fim de uma corrida e um número que represente a distância, e retorne um objeto Time com o passo médio (tempo por milha). 284 | 285 | Exercício 16.2 286 | 287 | O módulo datetime fornece objetos time que são semelhantes aos objetos Time deste capítulo, mas ele oferece um grande conjunto de métodos e operadores. Leia a documentação em http://docs.python.org/3/library/datetime.html. 288 | 289 | 1.        Use o módulo datetime para escrever um programa que receba a data atual e exiba o dia da semana. 290 | 291 | 2.        Escreva um programa que receba um aniversário como entrada e exiba a idade do usuário e o número de dias, horas, minutos e segundos até o seu próximo aniversário. 292 | 293 | 3.        Para duas pessoas nascidas em dias diferentes, há um dia em que a idade de uma equivale a duas vezes a da outra. Este é o Dia Duplo delas. Escreva um programa que receba dois aniversários e calcule o Dia Duplo dos aniversariantes. 294 | 295 | 4.        Para um desafio um pouco maior, escreva a versão mais geral que calcule o dia em que uma pessoa é n vezes mais velha que a outra. 296 | 297 | Solução: http://thinkpython2.com/code/double.py. 298 | 299 | -------------------------------------------------------------------------------- /recebido/figuras/p19f1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/p19f1.pdf -------------------------------------------------------------------------------- /recebido/figuras/p242f1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/p242f1.pdf -------------------------------------------------------------------------------- /recebido/figuras/p63f1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/p63f1.pdf -------------------------------------------------------------------------------- /recebido/figuras/p72f1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/p72f1.pdf -------------------------------------------------------------------------------- /recebido/figuras/p79f1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/p79f1.pdf -------------------------------------------------------------------------------- /recebido/figuras/p79f2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/p79f2.pdf -------------------------------------------------------------------------------- /recebido/figuras/p80f1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/p80f1.pdf -------------------------------------------------------------------------------- /recebido/figuras/p83f1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/p83f1.pdf -------------------------------------------------------------------------------- /recebido/figuras/tnkp_0201.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_0201.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_0301.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_0301.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_0401.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_0401.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_0402.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_0402.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_0501.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_0501.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_0502.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_0502.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_0601.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_0601.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_0701.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_0701.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_0801.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_0801.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_0802.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_0802.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1001.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1001.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1002.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1002.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1003.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1003.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1004.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1004.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1005.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1005.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1101.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1101.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1102.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1102.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1201.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1201.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1202.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1202.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1501.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1501.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1502.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1502.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1503.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1503.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1601.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1601.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1801.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1801.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_1802.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_1802.ai -------------------------------------------------------------------------------- /recebido/figuras/tnkp_2101.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/figuras/tnkp_2101.ai -------------------------------------------------------------------------------- /recebido/sumario.md: -------------------------------------------------------------------------------- 1 | # Sumário 2 | 3 | Prefácio        13 4 | 5 | Capítulo 1 ■ A jornada do programa        25 6 | 7 | O que é um programa?        25 8 | 9 | Execução do Python        26 10 | 11 | O primeiro programa        27 12 | 13 | Operadores aritméticos        28 14 | 15 | Valores e tipos        29 16 | 17 | Linguagens formais e naturais        30 18 | 19 | Depuração        32 20 | 21 | Glossário        33 22 | 23 | Exercícios        35 24 | 25 | Capítulo 2 ■ Variáveis, expressões e instruções        37 26 | 27 | Instruções de atribuição        37 28 | 29 | Nomes de variáveis        38 30 | 31 | Expressões e instruções        39 32 | 33 | Modo script        39 34 | 35 | Ordem das operações        41 36 | 37 | Operações com strings        41 38 | 39 | Comentários        42 40 | 41 | Depuração        43 42 | 43 | Glossário        44 44 | 45 | Exercícios        46 46 | 47 | Capítulo 3 ■ Funções        47 48 | 49 | Chamada de função        47 50 | 51 | Funções matemáticas        48 52 | 53 | Composição        49 54 | 55 | Como acrescentar novas funções        50 56 | 57 | Uso e definições        51 58 | 59 | Fluxo de execução        52 60 | 61 | Parâmetros e argumentos        53 62 | 63 | As variáveis e os parâmetros são locais        54 64 | 65 | Diagrama da pilha        55 66 | 67 | Funções com resultado e funções nulas        56 68 | 69 | Por que funções?        57 70 | 71 | Depuração        57 72 | 73 | Glossário        58 74 | 75 | Exercícios        60 76 | 77 | Capítulo 4 ■ Estudo de caso: projeto de interface        63 78 | 79 | Módulo turtle        63 80 | 81 | Repetição simples        65 82 | 83 | Exercícios        66 84 | 85 | Encapsulamento        67 86 | 87 | Generalização        67 88 | 89 | Projeto da interface        68 90 | 91 | Refatoração        70 92 | 93 | Um plano de desenvolvimento        71 94 | 95 | docstring        71 96 | 97 | Depuração        72 98 | 99 | Glossário        73 100 | 101 | Exercícios        74 102 | 103 | Capítulo 5 ■ Condicionais e recursividade        76 104 | 105 | Divisão pelo piso e módulo        76 106 | 107 | Expressões booleanas        77 108 | 109 | Operadores lógicos        78 110 | 111 | Execução condicional        78 112 | 113 | Execução alternativa        79 114 | 115 | Condicionais encadeadas        79 116 | 117 | Condicionais aninhadas        80 118 | 119 | Recursividade        81 120 | 121 | Diagramas da pilha para funções recursivas        83 122 | 123 | Recursividade infinita        83 124 | 125 | Entrada de teclado        84 126 | 127 | Depuração        85 128 | 129 | Glossário        87 130 | 131 | Exercícios        88 132 | 133 | Capítulo 6 ■ Funções com resultado        92 134 | 135 | Valores de retorno        92 136 | 137 | Desenvolvimento incremental        94 138 | 139 | Composição        96 140 | 141 | Funções booleanas        97 142 | 143 | Mais recursividade        98 144 | 145 | Salto de fé        100 146 | 147 | Mais um exemplo        101 148 | 149 | Verificação de tipos        101 150 | 151 | Depuração        103 152 | 153 | Glossário        104 154 | 155 | Exercícios        105 156 | 157 | Capítulo 7 ■ Iteração        107 158 | 159 | Reatribuição        107 160 | 161 | Atualização de variáveis        108 162 | 163 | Instrução while        109 164 | 165 | break        110 166 | 167 | Raízes quadradas        111 168 | 169 | Algoritmos        113 170 | 171 | Depuração        114 172 | 173 | Glossário        115 174 | 175 | Exercícios        115 176 | 177 | Capítulo 8 ■ Strings        118 178 | 179 | Uma string é uma sequência        118 180 | 181 | len         119 182 | 183 | Travessia com loop for        120 184 | 185 | Fatiamento de strings        121 186 | 187 | Strings são imutáveis        122 188 | 189 | Buscando        123 190 | 191 | Loop e contagem        123 192 | 193 | Métodos de strings        124 194 | 195 | Operador in        125 196 | 197 | Comparação de strings        126 198 | 199 | Depuração        126 200 | 201 | Glossário        128 202 | 203 | Exercícios        130 204 | 205 | Capítulo 9 ■ Estudo de caso: jogos de palavras        133 206 | 207 | Leitura de listas de palavras        133 208 | 209 | Exercícios        134 210 | 211 | Busca        136 212 | 213 | Loop com índices        137 214 | 215 | Depuração        139 216 | 217 | Glossário        140 218 | 219 | Exercícios        140 220 | 221 | Capítulo 10 ■ Listas        142 222 | 223 | Uma lista é uma sequência        142 224 | 225 | Listas são mutáveis        143 226 | 227 | Percorrendo uma lista        144 228 | 229 | Operações com listas        145 230 | 231 | Fatias de listas        145 232 | 233 | Métodos de listas        146 234 | 235 | Mapeamento, filtragem e redução        147 236 | 237 | Como excluir elementos        148 238 | 239 | Listas e strings        149 240 | 241 | Objetos e valores        150 242 | 243 | Alias        151 244 | 245 | Argumentos de listas        152 246 | 247 | Depuração        154 248 | 249 | Glossário        156 250 | 251 | Exercícios        157 252 | 253 | Capítulo 11 ■ Dicionários        161 254 | 255 | Um dicionário é um mapeamento        161 256 | 257 | Um dicionário como uma coleção de contadores        163 258 | 259 | Loop e dicionários        165 260 | 261 | Busca reversa        165 262 | 263 | Dicionários e listas        167 264 | 265 | Memos        169 266 | 267 | Variáveis globais        170 268 | 269 | Depuração        172 270 | 271 | Glossário        173 272 | 273 | Exercícios        175 274 | 275 | Capítulo 12 ■ Tuplas        178 276 | 277 | Tuplas são imutáveis        178 278 | 279 | Atribuição de tuplas        180 280 | 281 | Tuplas como valores de retorno        181 282 | 283 | Tuplas com argumentos de comprimento variável        181 284 | 285 | Listas e tuplas        182 286 | 287 | Dicionários e tuplas        184 288 | 289 | Sequências de sequências        186 290 | 291 | Depuração        187 292 | 293 | Glossário        188 294 | 295 | Exercícios        189 296 | 297 | Capítulo 13 ■ Estudo de caso: seleção de estrutura de dados        192 298 | 299 | Análise de frequência de palavras        192 300 | 301 | Números aleatórios        193 302 | 303 | Histograma de palavras        195 304 | 305 | Palavras mais comuns        196 306 | 307 | Parâmetros opcionais        197 308 | 309 | Subtração de dicionário        198 310 | 311 | Palavras aleatórias        199 312 | 313 | Análise de Markov        200 314 | 315 | Estruturas de dados        202 316 | 317 | Depuração        203 318 | 319 | Glossário        205 320 | 321 | Exercícios        206 322 | 323 | Capítulo 14 ■ Arquivos        207 324 | 325 | Persistência        207 326 | 327 | Leitura e escrita        208 328 | 329 | Operador de formatação        208 330 | 331 | Nomes de arquivo e caminhos        210 332 | 333 | Captura de exceções        211 334 | 335 | Bancos de dados        212 336 | 337 | Usando o Pickle        213 338 | 339 | Pipes        214 340 | 341 | Escrevendo módulos        216 342 | 343 | Depuração        217 344 | 345 | Glossário        218 346 | 347 | Exercícios        219 348 | 349 | Capítulo 15 ■ Classes e objetos        221 350 | 351 | Tipos definidos pelos programadores        221 352 | 353 | Atributos        222 354 | 355 | Retângulos        224 356 | 357 | Instâncias como valores de retorno        225 358 | 359 | Objetos são mutáveis        225 360 | 361 | Cópia        226 362 | 363 | Depuração        228 364 | 365 | Glossário        229 366 | 367 | Exercícios        230 368 | 369 | Capítulo 16 ■ Classes e funções        231 370 | 371 | Time        231 372 | 373 | Funções puras        232 374 | 375 | Modificadores        233 376 | 377 | Prototipação versus planejamento        234 378 | 379 | Depuração        236 380 | 381 | Glossário        237 382 | 383 | Exercícios        238 384 | 385 | Capítulo 17 ■ Classes e métodos        240 386 | 387 | Recursos orientados a objeto        240 388 | 389 | Exibição de objetos        241 390 | 391 | Outro exemplo        243 392 | 393 | Um exemplo mais complicado        244 394 | 395 | Método init        244 396 | 397 | Método \_\_str\_\_        245 398 | 399 | Sobrecarga de operadores        246 400 | 401 | Despacho por tipo        247 402 | 403 | Polimorfismo        248 404 | 405 | Interface e implementação        249 406 | 407 | Depuração        250 408 | 409 | Glossário        251 410 | 411 | Exercícios        252 412 | 413 | Capítulo 18 ■ Herança        253 414 | 415 | Objetos Card        253 416 | 417 | Atributos de classe        255 418 | 419 | Comparação de cartas        256 420 | 421 | Baralhos        257 422 | 423 | Exibição do baralho        258 424 | 425 | Adição, remoção, embaralhamento e classificação        258 426 | 427 | Herança        259 428 | 429 | Diagramas de classe        261 430 | 431 | Encapsulamento de dados        262 432 | 433 | Depuração        264 434 | 435 | Glossário        265 436 | 437 | Exercícios        267 438 | 439 | Capítulo 19 ■ Extra        270 440 | 441 | Expressões condicionais        270 442 | 443 | Abrangência de listas        271 444 | 445 | Expressões geradoras        273 446 | 447 | any e all        274 448 | 449 | Conjuntos        274 450 | 451 | Contadores        276 452 | 453 | defaultdict        277 454 | 455 | Tuplas nomeadas        279 456 | 457 | Reunindo argumentos de palavra-chave        280 458 | 459 | Glossário        282 460 | 461 | Exercícios        282 462 | 463 | Capítulo 20 ■ Depuração        284 464 | 465 | Erros de sintaxe        284 466 | 467 | !Continuo fazendo alterações e não faz nenhuma diferença        286 468 | 469 | Erros de tempo de execução        286 470 | 471 | !Meu programa não faz nada        286 472 | 473 | !Meu programa fica suspenso        287 474 | 475 | !Quando executo o programa recebo uma exceção        288 476 | 477 | !Acrescentei tantas instruções print que fui inundado pelos resultados        290 478 | 479 | Erros semânticos        291 480 | 481 | !Meu programa não funciona        291 482 | 483 | !Tenho uma baita expressão cabeluda e ela não faz o que espero        292 484 | 485 | !Tenho uma função que não retorna o que espero        293 486 | 487 | !Estou perdido e preciso de ajuda        293 488 | 489 | !Sério, preciso mesmo de ajuda        293 490 | 491 | Capítulo 21 ■ Análise de algoritmos        295 492 | 493 | Ordem de crescimento        296 494 | 495 | Análise de operações básicas do Python        299 496 | 497 | Análise de algoritmos de busca        301 498 | 499 | Hashtables        302 500 | 501 | Glossário        306 502 | 503 | Sobre o autor        308 504 | -------------------------------------------------------------------------------- /recebido/thinkpython2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PenseAllen/PensePython2e/afa460130599dbde01620e86c38923f785023956/recebido/thinkpython2.pdf -------------------------------------------------------------------------------- /util/epub.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from glob import glob 4 | import shutil 5 | import subprocess 6 | import os 7 | 8 | 9 | URL_REPO = 'https://github.com/PenseAllen/PensePython2e/raw/master' 10 | 11 | 12 | def _project_path(): 13 | return os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 14 | 15 | 16 | def _get_path(p): 17 | return os.path.join(_project_path(), p) 18 | 19 | 20 | def _fix_images_url(files, tmp_dir): 21 | """ Corrige as urls das imagens. 22 | Por algum motivo o pandoc não estava conseguindo baixar as imagens 23 | do site para embedar no epub. Com esse código eu gero arquivos 24 | temporários com as essas referências acertadas para a mesma imagem 25 | dentro do projeto. 26 | """ 27 | os.makedirs(tmp_dir) 28 | fixed_files = [] 29 | fixed_path = os.path.relpath(_project_path()) 30 | for fp in files: 31 | file_name = os.path.split(fp)[1] 32 | output = os.path.join(tmp_dir, file_name) 33 | with open(fp) as input_file: 34 | fixed_str = input_file.read().replace(URL_REPO, fixed_path) 35 | with open(output, 'w') as output_file: 36 | output_file.write(fixed_str) 37 | fixed_files.append(output) 38 | return fixed_files 39 | 40 | 41 | def main(): 42 | glob_filter = _get_path('docs/*.md') 43 | capa = _get_path('img/Capa_PenseEmPython332x461-borda.png') 44 | metadata = _get_path('ebooks/metadata.xml') 45 | output = _get_path('ebooks/PenseEmPython2e.epub') 46 | files = glob(glob_filter) 47 | files.sort() 48 | files.pop() 49 | tmp_dir = _get_path('tmp') 50 | files = _fix_images_url(files, tmp_dir) 51 | # Monta os argumentos do pandoc 52 | args = ['pandoc', '--epub-cover-image=' + capa, '--epub-metadata=' + metadata] 53 | args.extend(files) 54 | args.append('-o') 55 | args.append(output) 56 | # Executa o pandoc 57 | subprocess.call(args) 58 | # Remove arquivos temporários 59 | shutil.rmtree(tmp_dir) 60 | print('Gerado epub em', output) 61 | 62 | 63 | if __name__ == '__main__': 64 | main() 65 | -------------------------------------------------------------------------------- /util/gloss_e_exerc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | 5 | GLOSSARIO_RE = re.compile(r'^## [B|\d]\d?\.\d\d? - Glossário$', re.MULTILINE) 6 | EXERCICIOS_RE = re.compile(r'^## \d\d?\.\d\d? - Exercícios$', re.MULTILINE) 7 | 8 | VERBETE_RE = re.compile(r'^(.+?):\n\n', re.MULTILINE) 9 | VERBETE_REPL = r'__\1__
\n' 10 | 11 | EXERCICIO_RE = re.compile(r'^(Exercício \d\d?\.\d\d?)$', re.MULTILINE) 12 | EXERCICIO_REPL = r'### \1' 13 | 14 | 15 | def marcar_verbetes(md): 16 | casa_glossario = GLOSSARIO_RE.search(md) 17 | assert casa_glossario 18 | inicio = casa_glossario.span()[1] + 1 19 | casa_exercicios = EXERCICIOS_RE.search(md[inicio:]) 20 | if casa_exercicios: 21 | fim = inicio + casa_exercicios.span()[0] 22 | else: 23 | fim = len(md) 24 | corpo = md[inicio:fim] 25 | casa_verbete = VERBETE_RE.search(corpo) 26 | assert casa_verbete 27 | corpo = VERBETE_RE.sub(VERBETE_REPL, corpo) 28 | return md[:inicio] + corpo + md[fim:] 29 | 30 | 31 | def marcar_exercicios(md): 32 | casa_exercicio = EXERCICIO_RE.search(md) 33 | assert casa_exercicio 34 | md = EXERCICIO_RE.sub(EXERCICIO_REPL, md) 35 | return md 36 | 37 | 38 | def main(): 39 | import sys 40 | caminho_arq = sys.argv[1] 41 | with open(caminho_arq, encoding='utf8') as fp: 42 | md = fp.read() 43 | md = marcar_verbetes(md) 44 | md = marcar_exercicios(md) 45 | with open(caminho_arq, 'wt', encoding='utf8') as fp: 46 | fp.write(md) 47 | 48 | 49 | if __name__ == '__main__': 50 | main() 51 | -------------------------------------------------------------------------------- /util/glossario_dl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | 5 | GLOSSARIO_RE = re.compile(r'^## [B|\d]\d?\.\d\d? - Glossário$', re.MULTILINE) 6 | EXERCICIOS_RE = re.compile(r'^## \d\d?\.\d\d? - Exercícios$', re.MULTILINE) 7 | 8 | VERBETE_RE = re.compile(r'\n__(.+?)__
\n([^\n]+)\n') 9 | VERBETE_REPL = r'\n
\1
\n
\2
\n' 10 | 11 | 12 | def marcar_verbetes(md): 13 | casa_glossario = GLOSSARIO_RE.search(md) 14 | assert casa_glossario 15 | inicio = casa_glossario.span()[1] + 1 16 | casa_exercicios = EXERCICIOS_RE.search(md[inicio:]) 17 | if casa_exercicios: 18 | fim = inicio + casa_exercicios.span()[0] 19 | else: 20 | fim = len(md) 21 | corpo = md[inicio:fim] 22 | casa_verbete = VERBETE_RE.search(corpo) 23 | assert casa_verbete 24 | corpo = '\n
' + VERBETE_RE.sub(VERBETE_REPL, corpo) + '
\n\n' 25 | return md[:inicio] + corpo + md[fim:] 26 | 27 | 28 | def main(): 29 | import sys 30 | caminho_arq = sys.argv[1] 31 | with open(caminho_arq, encoding='utf8') as fp: 32 | md = fp.read() 33 | md = marcar_verbetes(md) 34 | with open(caminho_arq.replace('-', 'glos-', 1), 'wt', encoding='utf8') as fp: 35 | fp.write(md) 36 | 37 | 38 | if __name__ == '__main__': 39 | main() 40 | -------------------------------------------------------------------------------- /util/marcar_listagens.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | 5 | from glossario_dl import marcar_verbetes 6 | 7 | MAX_LEN_CODIGO = 50 8 | PREFIXOS_NAO_CODIGO = '# *
'.split() 9 | 10 | def pode_ser_codigo(lin): 11 | if len(lin) > MAX_LEN_CODIGO: 12 | return False 13 | for pre in PREFIXOS_NAO_CODIGO: 14 | if lin.startswith(pre): 15 | return False 16 | return True 17 | 18 | 19 | def marcar_listagens(md): 20 | lin_ant = '' 21 | bloco = [] 22 | saida = [] 23 | for lin in md.split('\n'): 24 | if pode_ser_codigo(lin): 25 | if lin: 26 | lin = lin.replace('>', '>') 27 | lin = lin.replace('<', '<') 28 | lin = lin.replace(r'\_', '_') 29 | lin = lin.replace(r'\#', '#') 30 | lin = lin.replace(r'\*', '*') 31 | bloco.append(lin) 32 | else: 33 | saida.append(lin) 34 | else: 35 | if bloco: 36 | saida.append('```python') 37 | saida.extend(bloco) 38 | saida.append('```\n') 39 | bloco = [] 40 | saida.append(lin) 41 | lin_ant = lin 42 | return '\n'.join(saida).replace('\n\n\n', '\n\n').replace('\n\n\n', '\n\n') 43 | 44 | 45 | def main(): 46 | import sys 47 | caminho_arq = sys.argv[1] 48 | with open(caminho_arq, encoding='utf8') as fp: 49 | md = fp.read() 50 | #md = marcar_verbetes(md) 51 | md = marcar_listagens(md) 52 | with open(caminho_arq.replace('-', 'list-', 1), 'wt', encoding='utf8') as fp: 53 | fp.write(md) 54 | 55 | 56 | if __name__ == '__main__': 57 | main() 58 | -------------------------------------------------------------------------------- /util/marcar_secoes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | import collections 5 | import glob 6 | import os 7 | 8 | from separar_capitulos import NOME_CAPS 9 | 10 | SUMARIO = '../recebido/sumario.md' 11 | DIR_DOCS = '../docs/' 12 | 13 | CAP_RE = re.compile('^Capítulo (\d+)', re.MULTILINE) 14 | SEC_RE = re.compile('(.+?)\s+\d+$', re.MULTILINE) 15 | 16 | Secao = collections.namedtuple('Secao', 'num titulo') 17 | 18 | def id_cap(num_cap): 19 | if num_cap == 20: 20 | return 'A' 21 | elif num_cap == 21: 22 | return 'B' 23 | return str(num_cap) 24 | 25 | 26 | def ler_sumario(): 27 | 28 | sumario = {} 29 | 30 | with open(SUMARIO, encoding='utf8') as fp: 31 | md = fp.read() 32 | 33 | num_cap = None 34 | for lin in md.split('\n\n'): 35 | casa_cap = CAP_RE.search(lin) 36 | if casa_cap: 37 | num_cap = int(casa_cap.group(1)) 38 | num_secao = 0 39 | elif num_cap is not None: 40 | lin = lin.replace('\xa0', ' ') # \xa0 = NBSP 41 | casa_secao = SEC_RE.search(lin) 42 | assert casa_secao, 'NAO CASOU: ' + lin 43 | tit_secao = casa_secao.group(1) 44 | 45 | if tit_secao[0] == '!': 46 | num_subsecao += 1 47 | secao = Secao('{}.{}.{}'.format(id_cap(num_cap), num_secao, num_subsecao), 48 | tit_secao[1:]) 49 | else: 50 | num_secao += 1 51 | num_subsecao = 0 52 | secao = Secao('{}.{}'.format(id_cap(num_cap), num_secao), tit_secao) 53 | # print(secao) 54 | sumario.setdefault(id_cap(num_cap), []).append(secao) 55 | 56 | return sumario 57 | 58 | def marcar(md, sumario_cap): 59 | ultimo_local = 0 60 | for secao in sumario_cap: 61 | local = md.find('\n' + secao.titulo, ultimo_local+1) 62 | assert local > ultimo_local, secao 63 | ultimo_local = local 64 | decoracao = '## {} - '.format(secao.num) 65 | if secao.num.count('.') == 2: 66 | decoracao = '#' + decoracao 67 | md = md[:local+1] + decoracao + md[local+1:] 68 | 69 | return md 70 | 71 | 72 | def marcar_caps(sumario): 73 | for path_arq in glob.glob(DIR_DOCS+'*-*.md'): 74 | nome_arq = os.path.basename(path_arq) 75 | id_cap = nome_arq.split('-')[0].lstrip('0') 76 | if not id_cap: 77 | continue # prefácio não tem seções no sumário 78 | 79 | with open(path_arq, encoding='utf8') as fp: 80 | md = fp.read() 81 | print(nome_arq, id_cap) 82 | md = marcar(md, sumario[id_cap]) 83 | with open(path_arq, 'wt', encoding='utf8') as fp: 84 | fp.write(md) 85 | 86 | 87 | if __name__ == '__main__': 88 | sumario = ler_sumario() 89 | marcar_caps(sumario) 90 | -------------------------------------------------------------------------------- /util/separar_capitulos.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | 5 | NOME_CAPS = { 6 | 0 : 'prefacio', 7 | 1 : 'jornada', 8 | 2 : 'vars-expr-instr', 9 | 3 : 'funcoes', 10 | 4 : 'caso-interface', 11 | 5 : 'cond-recur', 12 | 6 : 'funcoes-result', 13 | 7 : 'iteracao', 14 | 8 : 'strings', 15 | 9 : 'caso-palavras', 16 | 10 : 'listas', 17 | 11 : 'dicionarios', 18 | 12 : 'tuplas', 19 | 13 : 'caso-estruturas', 20 | 14 : 'arquivos', 21 | 15 : 'classes-objetos', 22 | 16 : 'classes-funcoes', 23 | 17 : 'classes-metodos', 24 | 18 : 'heranca', 25 | 19 : 'extra', 26 | 20 : 'depuracao', 27 | 21 : 'analise-algorit', 28 | } 29 | 30 | DIR_CAPITULOS = '../recebido/capitulos/' 31 | 32 | def main(): 33 | with open('../recebido/PenseEmPython.md', encoding='utf8') as fp: 34 | md = fp.read() 35 | 36 | cap_sep = re.compile(r'^capítulo\s+\d+\n\n', re.MULTILINE) 37 | 38 | caps = cap_sep.split(md) 39 | 40 | for i, cap in enumerate(caps): 41 | quebra = cap.find('\n\n') 42 | titulo = cap[:quebra] 43 | corpo = cap[quebra:] 44 | parte = 'Apêndice' 45 | if i == 20: 46 | prefixo = 'A' 47 | elif i == 21: 48 | prefixo = 'B' 49 | else: 50 | parte = 'Capítulo' 51 | prefixo = format(i, '02d') 52 | nome_arq = prefixo + '-' + NOME_CAPS[i] + '.md' 53 | parte += ' ' + prefixo.lstrip('0') 54 | print('{}. [{}]({})'.format(prefixo.lstrip('0'), titulo, nome_arq)) 55 | # ATENÇÃO: as instruções a seguir SOBRESCREVEM os arquivos no diretório 56 | # DIR_CAPITULOS 57 | #with open(DIR_CAPITULOS + nome_arq, 'wt', encoding='utf8') as fp: 58 | # fp.write('# ' + parte + ': ' + titulo + corpo) 59 | 60 | if __name__ == '__main__': 61 | main() 62 | --------------------------------------------------------------------------------