diff --git a/.gitignore b/.gitignore index 096c2c2..053e2e1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,7 @@ _build .ipynb_checkpoints # Ambiente virtual -.venv \ No newline at end of file +.venv + +# Scripts +scripts/ \ No newline at end of file diff --git a/book/09-modulos/03-modulos-proprios.ipynb b/book/09-modulos/03-modulos-proprios.ipynb new file mode 100644 index 0000000..b73ca01 --- /dev/null +++ b/book/09-modulos/03-modulos-proprios.ipynb @@ -0,0 +1,330 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Módulos customizados" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nós já aprendemos sobre funções e módulos nativos. Agora é hora de elevar o nível e aprender a criar nossos próprios módulos. Vamos começar com um exemplo de projeto pra explicar e contextualizar sobre módulos customizados.\n", + "\n", + "```{admonition} Nota (múltiplos arquivos .py)\n", + ":class: attention\n", + "Neste capítulo, vamos trabalhar com múltiplos arquivos *.py*. Para fins didáticos, no início de cada código eu vou colocar o nome do arquivo no qual o código está sendo escrito. Por exemplo, se o código está sendo escrito no arquivo *estoque.py*, eu vou colocar o seguinte comentário no início do código: `# estoque.py`. Ou então se o arquivo está dentro de uma pasta chamada *funcoes*, por exemplo, eu vou informar o caminho relativo do arquivo da seguinte forma: `# funcoes/estoque.py`. Preste atenção nesses comentários para saber em qual arquivo o código está sendo escrito.\n", + "\n", + "Isso é apenas para fins didáticos, pois no mundo real, você não precisa colocar tais comentários.\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## O projeto" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Vamos começar com um exemplo de projeto de um sistema de gerenciamento de vendas online simulando um e-commerce." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Usuário Henrique registrado com sucesso!\n", + "1. Verificar Saldo\n", + "2. Depositar\n", + "3. Sacar\n", + "4. Mostrar Transações\n", + "5. Sair\n", + "Seu saldo é: 0\n" + ] + } + ], + "source": [ + "# sistema_bancario.py\n", + "\n", + "usuarios = {}\n", + "\n", + "\n", + "def registrar_usuario(nome: str) -> None:\n", + " usuarios[nome] = {\"saldo\": 0, \"transacoes\": []}\n", + " print(f\"Usuário {nome} registrado com sucesso!\")\n", + "\n", + "\n", + "def verificar_saldo(nome: str) -> int:\n", + " return usuarios[nome][\"saldo\"]\n", + "\n", + "\n", + "def depositar(nome: str, quantia: int) -> None:\n", + " usuarios[nome][\"saldo\"] += quantia\n", + " usuarios[nome][\"transacoes\"].append(f\"Depositou {quantia}\")\n", + " print(f\"Depositou {quantia} na conta de {nome}.\")\n", + "\n", + "\n", + "def sacar(nome: str, quantia: int) -> None:\n", + " if quantia > usuarios[nome][\"saldo\"]:\n", + " print(\"Saldo insuficiente!\")\n", + " else:\n", + " usuarios[nome][\"saldo\"] -= quantia\n", + " usuarios[nome][\"transacoes\"].append(f\"Sacou {quantia}\")\n", + " print(f\"Sacou {quantia} da conta de {nome}.\")\n", + "\n", + "\n", + "# Histórico de Transações\n", + "def mostrar_transacoes(nome: str) -> list:\n", + " return usuarios[nome][\"transacoes\"]\n", + "\n", + "\n", + "# Descomente a linha abaixo para capturar do terminal um nome\n", + "# nome = input(\"Digite seu nome para registrar: \")\n", + "nome = \"Henrique\"\n", + "registrar_usuario(nome)\n", + "\n", + "while True:\n", + " print(\"1. Verificar Saldo\")\n", + " print(\"2. Depositar\")\n", + " print(\"3. Sacar\")\n", + " print(\"4. Mostrar Transações\")\n", + " print(\"5. Sair\")\n", + "\n", + " # Descomente a linha abaixo para capturar do terminal uma opção\n", + " # opcao = int(input(\"Escolha uma opção: \"))\n", + " opcao = 1\n", + "\n", + " if opcao == 1:\n", + " print(f\"Seu saldo é: {verificar_saldo(nome)}\")\n", + " # Remova a instrução break para o loop funcionar\n", + " break\n", + " elif opcao == 2:\n", + " quantia = float(input(\"Digite a quantia para depositar: \"))\n", + " depositar(nome, quantia)\n", + " # Remova a instrução break para o loop funcionar\n", + " break\n", + " elif opcao == 3:\n", + " quantia = float(input(\"Digite a quantia para sacar: \"))\n", + " sacar(nome, quantia)\n", + " # Remova a instrução break para o loop funcionar\n", + " break\n", + " elif opcao == 4:\n", + " print(f\"Transações: {mostrar_transacoes(nome)}\")\n", + " # Remova a instrução break para o loop funcionar\n", + " break\n", + " elif opcao == 5:\n", + " print(\"Até mais!\")\n", + " # Este break é o de saída do loop! Não remova!\n", + " break\n", + " else:\n", + " print(\"Opção inválida. Tente novamente.\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Tome o tempo que for necessário e leia o código acima. Nesta altura do livro, não há nada acima que não tenha sido ensinado aqui no livro. **Não continue a leitura até que você tenha entendido a ideia do projeto**. Não se preocupe em entender cada detalhe do código, o importante é ter uma visão geral do que está sendo feito. Se você não entendeu algo, volte e revise os capítulos anteriores referentes ao tema que você não entendeu." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Separando o projeto em módulos" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Conforme vimos no final do código, ele funciona, mas o projeto está um pouco longo (mais que 70 linhas) e acaba ficando um pouco confuso e difícil de manter. Vamos dividir o código em módulos customizados para facilitar a manutenção e organização do código.\n", + "\n", + "Se observarmos o nosso projeto, ele contém alguns grandes blocos:\n", + "\n", + "- Controlar e registrar usuários do sistema bancário\n", + "\n", + "- Realizar operações na conta bancária (saque, depósito, ver saldo)\n", + "\n", + "- Ver o histórico de transações\n", + "\n", + "- Fluxo principal do sistema (escolha e execução das operações)\n", + "\n", + "Dada essa divisão, vamos criar um módulo para cada um desses blocos. Cada módulo vai ser um arquivo `.py` separado. Vou criar os sequintes arquivos (a princípio em branco): \n", + "\n", + "- *gerenciamento_usuarios.py*\n", + "- *gerenciamento_contas.py*\n", + "- *historico_transacoes.py*\n", + "- *sistema.py*\n", + " \n", + "Cada um deles vai conter um dos blocos acima. Vamos começar com o arquivo *gerenciamento_usuarios.py*:\n", + "\n", + "```python\n", + "# gerenciamento_usuarios.py\n", + "usuarios = {}\n", + "\n", + "\n", + "def registrar_usuario(nome):\n", + " usuarios[nome] = {\"saldo\": 0, \"transacoes\": []}\n", + " print(f\"Usuário {nome} registrado com sucesso!\")\n", + "```\n", + "\n", + "Até aqui nenhuma novidade. O que vem a seguir representa a importação dos dados em outro módulo.\n", + "\n", + "```python\n", + "# gerenciamento_contas.py\n", + "from gerenciamento_usuarios import usuarios\n", + "\n", + "\n", + "def verificar_saldo(nome):\n", + " return usuarios[nome][\"saldo\"]\n", + "\n", + "\n", + "def depositar(nome, quantia):\n", + " usuarios[nome][\"saldo\"] += quantia\n", + " usuarios[nome][\"transacoes\"].append(f\"Depositou {quantia}\")\n", + " print(f\"Depositou {quantia} na conta de {nome}.\")\n", + "\n", + "\n", + "def sacar(nome, quantia):\n", + " if quantia > usuarios[nome][\"saldo\"]:\n", + " print(\"Saldo insuficiente!\")\n", + " else:\n", + " usuarios[nome][\"saldo\"] -= quantia\n", + " usuarios[nome][\"transacoes\"].append(f\"Sacou {quantia}\")\n", + " print(f\"Sacou {quantia} da conta de {nome}.\")\n", + "```\n", + "\n", + "Em *gerenciamento_contas.py*, logo na primeira linha, estamos importando do módulo `gerenciamento_usuarios` a variável `usuarios`.\n", + "\n", + "Vamos seguir com a divisão.\n", + "\n", + "```python\n", + "# historico_transacoes.py\n", + "from gerenciamento_usuarios import usuarios\n", + "\n", + "\n", + "def mostrar_transacoes(nome):\n", + " return usuarios[nome][\"transacoes\"]\n", + "```\n", + "\n", + "E, finalmente, o arquivo **sistema.py**:\n", + "\n", + "```python\n", + "# sistema.py\n", + "from gerenciamento_contas import depositar, sacar, verificar_saldo\n", + "from gerenciamento_usuarios import registrar_usuario\n", + "from historico_transacoes import mostrar_transacoes\n", + "\n", + "nome = \"Henrique\"\n", + "registrar_usuario(nome)\n", + "\n", + "while True:\n", + " print(\"1. Verificar Saldo\")\n", + " print(\"2. Depositar\")\n", + " print(\"3. Sacar\")\n", + " print(\"4. Mostrar Transações\")\n", + " print(\"5. Sair\")\n", + "\n", + " # Descomente a linha abaixo para capturar do terminal uma opção\n", + " # opcao = int(input(\"Escolha uma opção: \"))\n", + " opcao = 1\n", + "\n", + " if opcao == 1:\n", + " print(f\"Seu saldo é: {verificar_saldo(nome)}\")\n", + " # Remova a instrução break para o loop funcionar\n", + " break\n", + " elif opcao == 2:\n", + " quantia = float(input(\"Digite a quantia para depositar: \"))\n", + " depositar(nome, quantia)\n", + " # Remova a instrução break para o loop funcionar\n", + " break\n", + " elif opcao == 3:\n", + " quantia = float(input(\"Digite a quantia para sacar: \"))\n", + " sacar(nome, quantia)\n", + " # Remova a instrução break para o loop funcionar\n", + " break\n", + " elif opcao == 4:\n", + " print(f\"Transações: {mostrar_transacoes(nome)}\")\n", + " # Remova a instrução break para o loop funcionar\n", + " break\n", + " elif opcao == 5:\n", + " print(\"Até mais!\")\n", + " # Este break é o de saída do loop! Não remova!\n", + " break\n", + " else:\n", + " print(\"Opção inválida. Tente novamente.\")\n", + "```\n", + "\n", + "Quem permite reutilizar funções, variáveis e outras coisas de módulos são as linhas de importações, como em *sistema.py*:\n", + "\n", + "```python\n", + "# sistema.py\n", + "from gerenciamento_contas import depositar, sacar, verificar_saldo\n", + "from gerenciamento_usuarios import registrar_usuario\n", + "from historico_transacoes import mostrar_transacoes\n", + "...\n", + "```\n", + "\n", + "Essas linhas importam as funções `depositar`, `sacar`, `verificar_saldo`, `registrar_usuario` e `mostrar_transacoes` dos respectivos módulos. Cada módulo representa um arquivo `.py`.\n", + "\n", + "Se você executar o script *sistema.py*, o projeto vai funcionar da mesma forma que antes, mas agora está organizado em módulos customizados. Cada módulo é responsável por uma parte do projeto.\n", + "\n", + "No final a organização do nosso projeto ficou conforme a imagem abaixo:\n", + "\n", + "```{image} ../img/09-03-modulos.png\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visão geral" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Poderíamos avançar no tema e aprofundar ainda mais, mas não vamos. A ideia principal é que você compreenda o conceito básico da divisão em módulos, cada um com sua própria responsabilidade.\n", + "\n", + "É possível dividir de várias formas, e não existe uma regra sobre como fazer tal divisão. Normalmente a divisão é baseada em responsabilidades e funcionalidades. Cada módulo deve ser responsável por uma parte ou escopo específico. E quem define isso é você, meu caro leitor! Aqui assumo que é necessário um pouco de criatividade para enxergar tais divisões, sim. Eu nunca disse que quem programa não precisa ser criativo... 😉\n", + "\n", + "É possível organizar ainda o projeto não só em módulos (arquivos `.py` separados) mas também em pastas e subpastas. Mas, por enquanto, vamos ficar com o mais simples." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/book/_toc.yml b/book/_toc.yml index 4a4af0e..d079620 100644 --- a/book/_toc.yml +++ b/book/_toc.yml @@ -58,6 +58,7 @@ parts: chapters: - file: 09-modulos/01-introducao.ipynb - file: 09-modulos/02-modulos-nativos.ipynb + - file: 09-modulos/03-modulos-proprios.ipynb - caption: Pratique chapters: diff --git a/book/img/09-03-modulos.png b/book/img/09-03-modulos.png new file mode 100644 index 0000000..b0004bf Binary files /dev/null and b/book/img/09-03-modulos.png differ diff --git a/book/img/Originals/09-02-distancia-se-congonhas.presso b/book/img/Originals/09-02-distancia-se-congonhas.presso deleted file mode 100644 index 8e6c0a8..0000000 Binary files a/book/img/Originals/09-02-distancia-se-congonhas.presso and /dev/null differ diff --git a/scripts/meu_primeiro_script.py b/scripts/meu_primeiro_script.py deleted file mode 100644 index 5ce9ede..0000000 --- a/scripts/meu_primeiro_script.py +++ /dev/null @@ -1,8 +0,0 @@ -print(5 + 4) # Soma de 5 com 4: 9 -print(5 - 6) # Subtraçaõ de 5 e 6: -1 -print(10 * 20) # Multiplicação entre 10 e 20: 200 -print(1 / 2) # Divisão comum entre 1 e 2: 0.5 -print(50 // 30) # Divisão inteira entre 50 e 30: 1 -print(50 % 30) # Resto da divisão entre 50 e 30: 20 -print(2 ** 3) # 2 elevado à 3: 8 -print(16 ** (1/2)) # Raiz quadrada de 16: 4 \ No newline at end of file