├── Avatar.png
├── src
├── site-icon.png
├── gatsby-theme-document
│ └── logo.mdx
└── gatsby-plugin-theme-ui
│ ├── components.js
│ ├── headings.js
│ ├── colors.js
│ └── index.js
├── README.md
├── package.json
├── content
├── index.mdx
├── while-loops.mdx
├── input.mdx
├── iteradores.mdx
├── for-loops.mdx
├── geradores.mdx
├── ambiente.mdx
├── sets.mdx
├── expressoes-lambda.mdx
├── numeros.mdx
├── if-else.mdx
├── tipos-variaveis.mdx
├── tuplas.mdx
├── dicionarios.mdx
├── operadores.mdx
├── sintaxe.mdx
├── xml.mdx
├── json.mdx
├── decoradores.mdx
├── ambientes-virtuais.mdx
├── introducao.mdx
├── expressoes-regulares.mdx
└── modulos.mdx
├── .gitignore
└── gatsby-config.js
/Avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/the-akira/pythoniluminado/master/Avatar.png
--------------------------------------------------------------------------------
/src/site-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/the-akira/pythoniluminado/master/src/site-icon.png
--------------------------------------------------------------------------------
/src/gatsby-theme-document/logo.mdx:
--------------------------------------------------------------------------------
1 | Python Iluminado
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/gatsby-plugin-theme-ui/components.js:
--------------------------------------------------------------------------------
1 | import Prism from '@theme-ui/prism';
2 | export default {
3 | pre: props => props.children,
4 | code: Prism
5 | };
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | pythoniluminado.netlify.app
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Código fonte do website do projeto Python Iluminado
11 |
12 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gatsby-theme-document-example",
3 | "author": "Code Bushi",
4 | "repository": "https://github.com/codebushi/gatsby-theme-document-example",
5 | "version": "1.0.0",
6 | "license": "MIT",
7 | "scripts": {
8 | "develop": "gatsby develop",
9 | "build": "gatsby build"
10 | },
11 | "dependencies": {
12 | "gatsby": "^2.15.9",
13 | "gatsby-theme-document": "1.0.8",
14 | "react": "^16.9.0",
15 | "react-dom": "^16.9.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/content/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Python Iluminado"
3 | description: "Guia para iniciantes com programação!"
4 | ---
5 |
6 | 
7 |
8 | Python Iluminado é um Guia construído especialmente para Iniciantes com a Linguagem Python. O objetivo é explorar conceitos fundamentais de programação e compreender o funcionamento da linguagem e suas capacidades e potencial, bem como apresentar uma vasta lista de materiais de estudos qualificados para você ampliar e aperfeiçoar o seu conhecimento.
9 |
--------------------------------------------------------------------------------
/src/gatsby-plugin-theme-ui/headings.js:
--------------------------------------------------------------------------------
1 | const headingBase = {
2 | fontFamily: 'heading',
3 | lineHeight: 'heading',
4 | fontWeight: 'heading',
5 | mt: 0,
6 | mb: 3,
7 | '::before': {
8 | content: '" "',
9 | display: 'block',
10 | paddingTop: 30,
11 | marginBottom: 40,
12 | borderBottom: '1px solid',
13 | borderBottomColor: 'borderColor'
14 | }
15 | };
16 |
17 | export default {
18 | h1: {
19 | ...headingBase,
20 | fontSize: 5
21 | },
22 | h2: {
23 | ...headingBase,
24 | fontSize: 4
25 | },
26 | h3: {
27 | ...headingBase,
28 | fontSize: 3
29 | },
30 | h4: {
31 | ...headingBase,
32 | fontSize: 2
33 | },
34 | h5: {
35 | ...headingBase,
36 | fontSize: 1
37 | },
38 | h6: {
39 | ...headingBase,
40 | fontSize: 0
41 | },
42 | img: {
43 | maxWidth: '100%',
44 | height: 'auto',
45 | }
46 | };
47 |
--------------------------------------------------------------------------------
/src/gatsby-plugin-theme-ui/colors.js:
--------------------------------------------------------------------------------
1 | export default {
2 | text: "#000",
3 | background: "#fff",
4 | primary: "#e63b19",
5 | secondary: "#c70d3a",
6 | sidebar: "#eee",
7 | borderColor: "rgba(0, 0, 0, 0.15)",
8 | modes: {
9 | dark: {
10 | text: "#fff",
11 | background: "#182952",
12 | primary: "#f638dc",
13 | secondary: "#ff7976",
14 | sidebar: "#101d3c",
15 | borderColor: "rgba(255, 255, 255, 0.15)"
16 | },
17 | cool: {
18 | text: "#fff",
19 | background: "#05386b",
20 | primary: "#5cdb95",
21 | secondary: "#bef992",
22 | sidebar: "#052e56",
23 | borderColor: "rgba(255, 255, 255, 0.15)"
24 | },
25 | deep: {
26 | text: "#fff",
27 | background: "hsl(230,25%,18%)",
28 | primary: "hsl(260, 100%, 80%)",
29 | secondary: "hsl(290, 100%, 80%)",
30 | sidebar: "hsla(230, 20%, 0%, 20%)",
31 | borderColor: "rgba(255, 255, 255, 0.15)"
32 | }
33 | }
34 | };
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .env.production
2 | .env.development
3 |
4 | # Logs
5 | logs
6 | *.log
7 | npm-debug.log*
8 | yarn-debug.log*
9 | yarn-error.log*
10 |
11 | # Runtime data
12 | pids
13 | *.pid
14 | *.seed
15 | *.pid.lock
16 |
17 | # Directory for instrumented libs generated by jscoverage/JSCover
18 | lib-cov
19 |
20 | # Coverage directory used by tools like istanbul
21 | coverage
22 |
23 | # nyc test coverage
24 | .nyc_output
25 |
26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
27 | .grunt
28 |
29 | # Bower dependency directory (https://bower.io/)
30 | bower_components
31 |
32 | # node-waf configuration
33 | .lock-wscript
34 |
35 | # Compiled binary addons (http://nodejs.org/api/addons.html)
36 | build/Release
37 |
38 | # Dependency directories
39 | node_modules/
40 | jspm_packages/
41 | package.lock
42 |
43 | # Typescript v1 declaration files
44 | typings/
45 |
46 | # Optional npm cache directory
47 | .npm
48 |
49 | # Optional eslint cache
50 | .eslintcache
51 |
52 | # Optional REPL history
53 | .node_repl_history
54 |
55 | # Output of 'npm pack'
56 | *.tgz
57 |
58 | # dotenv environment variables file
59 | .env
60 |
61 | # gatsby files
62 | .cache/
63 | public
64 |
65 | # Mac files
66 | .DS_Store
67 |
68 | # Yarn
69 | yarn-error.log
70 | .pnp/
71 | .pnp.js
72 | # Yarn Integrity file
73 | .yarn-integrity
74 | yarn.lock
--------------------------------------------------------------------------------
/gatsby-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | siteMetadata: {
3 | title: `Python Iluminado`,
4 | name: `Gabriel Felippe`,
5 | siteUrl: `https://github.com/the-akira/Python-Iluminado`,
6 | description: `Guia para Iniciantes com a Linguagem Python`,
7 | social: [
8 | {
9 | name: `github`,
10 | url: `https://github.com/the-akira`
11 | },
12 | {
13 | name: `twitter`,
14 | url: `https://twitter.com/akirascientist`
15 | }
16 | ],
17 | sidebarConfig: {
18 | forcedNavOrder: [
19 | "introducao",
20 | "ambiente",
21 | "sintaxe",
22 | "tipos-variaveis",
23 | "numeros",
24 | "strings",
25 | "operadores",
26 | "listas",
27 | "tuplas",
28 | "dicionarios",
29 | "sets",
30 | "input",
31 | "if-else",
32 | "for-loops",
33 | "while-loops",
34 | "funcoes",
35 | "expressoes-lambda",
36 | "modulos",
37 | "input-output-arquivos",
38 | "erros-excecoes-testes",
39 | "data-tempo",
40 | "classes-objetos",
41 | "expressoes-regulares",
42 | "json",
43 | "xml",
44 | "iteradores",
45 | "geradores",
46 | "decoradores",
47 | "ambientes-virtuais",
48 | "mysql",
49 | "mongodb",
50 | "grandes-bibliotecas",
51 | "referencias-online"
52 | ],
53 | ignoreIndex: true
54 | }
55 | },
56 | plugins: [{ resolve: `gatsby-theme-document` }]
57 | };
58 |
--------------------------------------------------------------------------------
/src/gatsby-plugin-theme-ui/index.js:
--------------------------------------------------------------------------------
1 | import nightOwl from "@theme-ui/prism/presets/night-owl.json";
2 | import colors from "./colors";
3 | import headings from "./headings";
4 |
5 | const transition = "0.2s ease-out";
6 | const systemFonts =
7 | "-apple-system, BlinkMacSystemFont, San Francisco, Helvetica Neue, Helvetica, Ubuntu, Roboto, Noto, Segoe UI, Arial, sans-serif";
8 |
9 | export default {
10 | initialColorMode: `dark`,
11 | colors,
12 | fonts: {
13 | body: systemFonts,
14 | heading: systemFonts,
15 | monospace: "Menlo, monospace"
16 | },
17 | fontSizes: [12, 14, 16, 24, 28, 36, 48, 64],
18 | fontWeights: {
19 | body: 400,
20 | heading: 700,
21 | bold: 700
22 | },
23 | lineHeights: {
24 | body: 1.5,
25 | heading: 1.125
26 | },
27 | letterSpacings: {
28 | body: "normal",
29 | caps: "0.2em"
30 | },
31 | breakpoints: [
32 | ["phone_small", 320],
33 | ["phone", 376],
34 | ["phablet", 540],
35 | ["tablet", 735],
36 | ["desktop", 1070],
37 | ["desktop_medium", 1280],
38 | ["desktop_large", 1440]
39 | ],
40 | transition,
41 | styles: {
42 | root: {
43 | fontFamily: "body",
44 | lineHeight: "body",
45 | fontWeight: "body",
46 | ...headings
47 | },
48 | ...headings,
49 | p: {
50 | my: 4
51 | },
52 | a: {
53 | color: "secondary",
54 | transition: `color ${transition}`,
55 | ":hover,:focus": {
56 | color: "text"
57 | }
58 | },
59 | pre: {
60 | ...nightOwl,
61 | fontFamily: `"Operator Mono", monospace`,
62 | fontSize: "0.9rem",
63 | tabSize: 4,
64 | hyphens: `none`,
65 | overflow: `auto`,
66 | borderRadius: 6,
67 | p: 3,
68 | my: 4
69 | },
70 | inlineCode: {
71 | color: `primary`,
72 | background: `rgba(233, 218, 172, 0.15)`,
73 | borderRadius: 3,
74 | px: `0.4rem`,
75 | py: `0.2rem`
76 | },
77 | table: {
78 | width: "100%",
79 | borderCollapse: "separate",
80 | borderSpacing: 0
81 | },
82 | th: {
83 | textAlign: "left",
84 | borderBottomStyle: "solid"
85 | },
86 | td: {
87 | textAlign: "left",
88 | borderBottomStyle: "solid"
89 | }
90 | }
91 | };
92 |
--------------------------------------------------------------------------------
/content/while-loops.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'While Loops'
3 | description: 'Aprenda sobre While Loops'
4 | ---
5 |
6 | O **while loop** em **Python** é utilizado para iterar em cima de um bloco de código enquanto determinada **Expressão de Teste** (condição) for avaliada como **True**.
7 |
8 | **While** é normalmente usado quando não sabemos de ante-mão o número de vezes no qual vamos iterar.
9 |
10 | Python primeiro verifica a condição:
11 |
12 | - Se for **False**, o loop será encerrado e o controle será passado para a próxima instrução após o corpo do While Loop.
13 | - Se a condição for **True**, o corpo do While Loop será executado e a condição será verificada novamente.
14 |
15 | Este procedimento continua enquanto a condição for **True**. Quando a condição se torna **False**, o loop termina e o controle é passado para a próxima instrução após o loop.
16 |
17 | ### Estrutura Básica do While
18 |
19 | 
20 |
21 | ```
22 | while :
23 |
24 |
25 | ...
26 | ```
27 |
28 | - `` é avaliado para um **booleano**
29 | - Se a `` for **True**, executa-se todas as `` dentro do bloco de código while
30 | - Checa a `` novamente
31 | - Repete até que a `` seja **False**
32 |
33 | Vejamos um exemplo prático:
34 |
35 | ```python
36 | i = 1
37 | while i < 10:
38 | print(i)
39 | i += 1
40 | ```
41 |
42 | Observe que `i += 1` é o mesmo que `i = i + 1`, precisamos dessa expressão, caso contrário teremos um loop infinito.
43 |
44 | Também podemos definir o while loop em um único statement, da seguinte forma:
45 |
46 | ```python
47 | count = 0
48 | while (count < 5): count += 1; print("Hello World")
49 | ```
50 |
51 | A palavra-chave **break** também pode ser utilizada em conjunto com o **while**:
52 |
53 | ```python
54 | a = 1
55 | while a < 10:
56 | print(a)
57 | if a == 5:
58 | break
59 | a += 1
60 | ```
61 |
62 | Neste caso só serão impressos os números de 1 até 5, pois quando `a == 5` o loop irá encerrar.
63 |
64 | Podemos também usar a palavra-chave **continue**:
65 |
66 | ```python
67 | x = 0
68 | while x < 10:
69 | x += 1
70 | if x == 5:
71 | continue
72 | print(x)
73 | ```
74 |
75 | Neste caso o número 5 não será impresso, pois quando `x == 5` o comando **print()** não será executado.
76 |
77 | O while loop também pode ser usado para computarmos a [Sequência de Fibonacci](https://en.wikipedia.org/wiki/Fibonacci):
78 |
79 | ```python
80 | n = int(input("Informe o número de termos: "))
81 |
82 | a, b = 0, 1
83 | count = 0
84 |
85 | while count < n:
86 | print(a)
87 | c = a + b
88 | a, b = b, c
89 | count += 1
90 | ```
91 |
92 | Com ele podemos facilmente definir o algoritmo de [Euclides](https://en.wikipedia.org/wiki/Euclid) para buscar o máximo divisor comum entre dois números:
93 |
94 | ```python
95 | def gcd(x, y):
96 | while y != 0:
97 | (x, y) = (y, x % y)
98 | return x
99 |
100 | print(gcd(155,70)) # 5
101 | print(gcd(77,33)) # 11
102 | print(gcd(400,140)) # 20
103 | print(gcd(97,13)) # 1
104 | ```
105 |
106 | ### For vs While
107 |
108 | #### for
109 |
110 | - Número de iterações é **conhecido**
111 | - Pode finalizar antecipadamente através do **break**
112 | - Utiliza um **contador**
113 |
114 | #### while
115 |
116 | - Número de iterações **ilimitados**
117 | - Pode finalizar antecipadamente através do **break**
118 | - Pode utilizar um **contador**, porém é necessário inicializar ele antes do loop e incrementá-lo dentro do loop
119 |
120 | Como vimos, **while loops** não são muito misteriosos, porém a utilidade deles pode ser muito grande em nossos programas!
121 |
--------------------------------------------------------------------------------
/content/input.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Input de Dados'
3 | description: 'Aprenda a coletar dados dos usuários'
4 | ---
5 |
6 | Desenvolvedores geralmente precisam interagir com os usuários, seja para obter dados ou fornecer algum tipo de resultado. A maioria dos programas hoje em dia usam uma caixa de diálogo como uma forma de solicitar ao usuário algum tipo de *input* (entrada) do usuário.
7 |
8 | Na maioria dos casos, o *input* vem do teclado. Para este propósito, Python fornece a função `input()`, que possui um parâmetro opcional, que é a string que será enviada para o usuário.
9 |
10 | Até então todos os nossos programas foram **estáticos**, os valores das variáveis foram definidos por nós no código fonte. De forma a aumentar nossas opções de criações, vamos então aprender como podemos coletar dados dos usuários.
11 |
12 | ### Exemplos Input
13 |
14 | Começaremos chamando a função `input()`, passando como argumento uma string que será retornada como feedback ao usuário e armazenaremos o valor digitado pelo usuário na variável `n` que será impressa na sequência.
15 |
16 | ```python
17 | n = input("Insira um número: ")
18 | print(n)
19 | ```
20 |
21 | Ao executarmos o código acima, o prompt de comandos aguardará pela entrada de dados por parte de usuário, uma vez informado o valor e enviado, ele será impresso. Vamos agora ver qual o tipo de dados que temos em **n**:
22 |
23 | ```python
24 | print(type(n)) #
25 | ```
26 |
27 | Como podemos ver, embora tenhamos digitado um **número**, ele nos retorno uma **string**, para obtermos um número podemos utilizar as funções **int()** ou **float()** para fazer a conversão.
28 |
29 | ```python
30 | n = int(input("Insira um número: "))
31 | print(type(n)) #
32 | ```
33 |
34 | O método **eval()** também é capaz de solucionar o nosso problema e até mesmo resolver expressões, muito útil, mas tenha cuidado com ele!
35 |
36 | ```python
37 | eval('2+3') # 5
38 | numero = eval(input("Digite um valor: "))
39 | print(numero) # 2.3
40 | print(type(numero)) #
41 | ```
42 |
43 | ### Pedra, Papel e Tesoura
44 |
45 | Uma vez que sabemos como coletar dados de usuários, podemos agora criar jogos. Neste exemplo vamos construir o clássico Pedra, Papel e Tesoura, também conhecido como Jankenpon.
46 |
47 | 
48 |
49 | Para nos auxiliar neste pequeno projeto, vamos contar com a ajuda da função **choice()** da biblioteca [random](https://docs.python.org/3/library/random.html), ela será responsável por emular uma escolha pseudo-aleatória da máquina, entre as três opções disponíveis (Pedra, Papel e Tesoura).
50 |
51 | Também iremos utilizar um **While Loop** para manter o jogo executando até que o usuário deseje sair.
52 |
53 | Coletaremos o input do usuário através da função `input()` e testaremos uma série de `if`, `elif` e `else` para sabermos quem é o vitorioso.
54 |
55 | ```python
56 | from random import choice
57 |
58 | opcoes = ['pedra', 'papel', 'tesoura']
59 | maquina = choice(opcoes)
60 | jogando = True
61 |
62 | while jogando:
63 | print("# pedra\n# papel\n# tesoura\n# sair")
64 | player = input('Escolha entre uma das opções: ')
65 | if maquina == player.lower():
66 | print(f'Ocorreu um empate!')
67 | elif player.lower() == 'pedra':
68 | if maquina == 'papel':
69 | print(f'Você perdeu! {maquina} cobre {player.lower()}!')
70 | else:
71 | print(f'Parabéns! Você venceu! {player.lower()} quebra {maquina}!')
72 | elif player.lower() == 'papel':
73 | if maquina == 'tesoura':
74 | print(f'Você perdeu! {maquina} corta {player.lower()}!')
75 | else:
76 | print(f'Parabéns! Você venceu! {player.lower()} cobre {maquina}!')
77 | elif player.lower() == 'tesoura':
78 | if maquina == 'pedra':
79 | print(f'Você perdeu! {maquina} esmaga {player.lower()}!')
80 | else:
81 | print(f'Parabéns! Você venceu! {player.lower()} corta {maquina}!')
82 | elif player.lower() == 'sair':
83 | jogando = False
84 | else:
85 | print('Jogada inválida, verifique se digitou a opção corretamente!')
86 | print('-'*45)
87 | maquina = choice(opcoes)
88 | ```
89 |
90 | Como podemos ver, a função **input()** pode nos auxiliar na questão de receber dados de usuários e através dos diversos métodos vistos, podemos converter os dados recebidos para trabalharmos com eles de forma adequada.
91 |
--------------------------------------------------------------------------------
/content/iteradores.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Iteradores'
3 | description: 'Aprenda sobre Iteradores'
4 | ---
5 |
6 | Iteradores são objetos que podem ser iterados. Nesse guia vamos estudá-los e aprender como eles funcionam construindo um iterador usando os métodos `__iter__` e `__next__`.
7 |
8 | - Um objeto iterável é um objeto que implementa `__iter__`, que deve retornar um objeto iterador.
9 | - Um iterador é um objeto que implementa **next**, que deve retornar o próximo elemento do objeto iterável que o retornou e gerar uma exceção **StopIteration** quando não houver mais elementos disponíveis.
10 |
11 | ## Introdução
12 |
13 | **Iteradores** sempre estiveram conosco em Python, eles estão implementados nos **for loops**, **geradores**, etc, porém estão "escondidos". Um iterador é simplesmente um objeto que podemos iterar nele, ou seja, um objeto que retornará dados, um elemento de cada vez.
14 |
15 | O objeto iterador implementa dois métodos especiais `__iter__()` e `__next__()`, que são conhecidos como o protocolo do iterador. Um objeto é chamado de iterável se formos capazes de obter um iterador dele, estruturas como **lista**, **tupla** e **string** são iteráveis. A função **iter()** (que chama o método `__iter__`) retorna um iterador delas.
16 |
17 | Vamos então aos experimentos para entendermos melhor os iteradores, usaremos a função **next()** para iterar manualmente através de todos os itens de um iterador. Quando chegarmos ao fim e não houver mais dados para retorno, ocorrerá um erro **StopIteration**.
18 |
19 | ```python
20 | lista = [1,2,3,4]
21 |
22 | iterador = iter(lista)
23 |
24 | print(next(iterador)) # 1
25 | print(next(iterador)) # 2
26 | print(iterador.__next__()) # 3
27 | print(iterador.__next__()) # 4
28 |
29 | next(iterador) # Sem mais itens para iterar, erro StopIteration ocorre
30 | ```
31 |
32 | Uma forma melhor e mais simples de iterar automaticamente seria usando um for loop. Usando ele, nós podemos iterar sob qualquer objeto que retorne um iterador, por exemplo uma lista, string, arquivo, etc.
33 |
34 | ```python
35 | for elemento in lista:
36 | print(lista)
37 | # 1
38 | # 2
39 | # 3
40 | # 4
41 | ```
42 |
43 | Vimos que o **for** foi capaz de iterar automaticamente através da **lista**, agora vamos analisar como ele faz essa mágica internamente no Python:
44 |
45 | ```python
46 | for elemento in iteravel:
47 | # faça algo com o elemento
48 | ```
49 |
50 | É na verdade:
51 |
52 | ```python
53 | # cria um objeto iterador do iteravel
54 | objeto_iteravel = iter(iteravel)
55 |
56 | # Loop infinito
57 | while True:
58 | try:
59 | # obtém o novo item
60 | elemento = next(objeto_iteravel)
61 | # faz algo com o elemento
62 | except StopIteration:
63 | # Se o StopIteration ocorrer, break no loop
64 | break
65 | ```
66 |
67 | Veja que internamente o **for loop** cria um objeto iterador **objeto_iteravel** chamando o método **iter()** nele, e que na verdade ele é um **while loop**. Dentro desse while loop ele chama **next()** para pegar o próximo elemento e executar o for loop com esse valor, assim que todos os itens forem percorridos, StopIteration é acionado que é capturado internamente e o loop acaba, perceba que qualquer outra exceção irá passar.
68 |
69 | ## Criando um Iterador
70 |
71 | Para criar um **objeto**/**classe** como um iterador nós precisamos implementar os métodos `__iter__()` e `__next__()` no nosso objeto. Como aprendemos no nosso capítulo de Classes e Objetos, todas as classes possuem uma função chamada `__init__()`, que possibilita a inicialização quando o objeto é criado. O método `__iter__()` age similar, pode executar operações (inicializações, etc), mas sempre deve retornar o objeto iterador. O método `__next__()` também possibilita operações e deve retornar o próximo item na sequência.
72 |
73 | ```python
74 | class Numeros:
75 | def __iter__(self):
76 | self.x = 1
77 | return self
78 |
79 | def __next__(self):
80 | y = self.x
81 | self.x += 1
82 | return y
83 |
84 | n = Numeros()
85 | iterador = iter(n)
86 |
87 | print(next(iterador))
88 | print(next(iterador))
89 | print(next(iterador))
90 | print(next(iterador))
91 | print(next(iterador))
92 | # 1
93 | # 2
94 | # 3
95 | # 4
96 | # 5
97 | ```
98 |
99 | ## StopIteration
100 |
101 | O exemplo acima pode ser executado infinitamente, especialmente se aplicarmos um **for loop**. Para previnirmos que a iteração ocorra eternamente, podemos usar o comando **StopIteration** no método `__next__()`, nós podemos adicionar a condição de término para que o erro seja disparado caso a iteração ultrapasse a condição.
102 |
103 | ```python
104 | class Numeros:
105 | def __iter__(self):
106 | self.x = 1
107 | return self
108 |
109 | def __next__(self):
110 | if self.x <= 6:
111 | y = self.x
112 | self.x +=1
113 | return y
114 | else:
115 | raise StopIteration
116 |
117 | n = Numeros()
118 | iterador = iter(n)
119 |
120 | for elemento in iterador:
121 | print(elemento)
122 | # 1
123 | # 2
124 | # 3
125 | # 4
126 | # 5
127 | # 6
128 | ```
129 |
130 | ## Iterador Aleatório
131 |
132 | Vejamos um iterador que nos retorna sequências de comprimento aleatórios de **1**'s.
133 |
134 | ```python
135 | import random
136 |
137 | class RandomIterable:
138 | def __iter__(self):
139 | return self
140 | def __next__(self):
141 | if random.choice(["go", "go", "stop"]) == "stop":
142 | raise StopIteration # finaliza o iterador
143 | return 1
144 |
145 | for x in RandomIterable():
146 | print(x)
147 | # 1
148 | # 1
149 | # 1
150 | ```
151 |
152 | Esses foram os iteradores, conceito importante e muito presente em nossos estudos, central na linguagem Python, vamos então continuar **iterando** nosso conhecimento.
153 |
--------------------------------------------------------------------------------
/content/for-loops.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'For Loops'
3 | description: 'Aprenda sobre For Loops'
4 | ---
5 |
6 | 
7 |
8 | O **For Loop** em Python é usado para iterar sob uma sequência (lista, tupla, string) ou outros objetos iteráveis. A iteração sob uma sequência também é conhecida como travessia.
9 |
10 | O **For Loop** já é um conhecido nosso, pois utilizamos ele para percorrer nossas listas no passado, porém agora veremos ele com uma maior riqueza de detalhes e veremos que ele é muito importante, uma vez que nos permite percorrer diversas sequências (**listas**, **tuplas**, **dicionários**, **sets** e até mesmo **strings**).
11 |
12 | Para escrevermos o **for** Loop devemos obedecer a seguinte sintaxe:
13 |
14 | ```
15 | for seq in sequencia:
16 | print(seq)
17 | ```
18 |
19 | Onde `seq` é a variável que recebe o valor do item dentro da sequência em cada iteração, o loop continua até alcançarmos o último item da sequência.
20 |
21 | É válido lembrar que o **for** em **Python** difere um pouco de outras linguagens como por exemplo **C**, onde nós podemos definir os passos de **iteração** e o momento de parada, em **Python** o **for** faz a iteração em cima dos itens de uma sequência, na ordem que eles aparecem naquela sequência, por exemplo:
22 |
23 | ```python
24 | animais = ["cachorro", "gato", "elefante"]
25 |
26 | for animal in animais:
27 | print(animal)
28 | ```
29 |
30 | Simples, não? Também podemos percorrer **strings**:
31 |
32 | ```python
33 | for string in "Programação com Python":
34 | print(string)
35 | ```
36 |
37 | Se quisermos evitar a quebra de linha `\n`, podemos alterar o valor do argumento **end**:
38 |
39 | ```python
40 | for string in "Programação com Python":
41 | print(string,end='')
42 | ```
43 |
44 | ### A Função **range()**
45 |
46 | Nós podemos gerar sequências de números através da função **range()**. Por exemplo, **range(10)** irá gerar números de 0 até 9 (10 números). A função **range()** também nos permite definir o começo da nossa sequência, o fim e os passos que serão dados como por exemplo range(começo,fim,passos), caso não venhamos a definir os passos, o padrão é que seja de 1 em 1.
47 |
48 | Importante lembrar que a função não guarda todos os valores em memória por questões de eficiência, para forçarmos que a função imprima os itens, nós podemos utilizar a função **list()**, veja:
49 |
50 | ```python
51 | x = range(0,10)
52 | print(type(x)) # veja que o tipo retornado é 'range'
53 | print(list(x)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
54 |
55 | y = range(4,30,2)
56 | print(list(y)) # [4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]
57 | ```
58 |
59 | Podemos aplicar a função **range()** em conjunto com o **for**:
60 |
61 | ```python
62 | for i in range(10):
63 | print(i)
64 |
65 | for data in range(1995,2018):
66 | print(data)
67 | ```
68 |
69 | ### Condicionais
70 |
71 | A palavra-chave **break** nos permite parar o loop antes que ele passe por todos os itens
72 |
73 | ```python
74 | paises = ['China', 'Índia', 'Tailândia']
75 |
76 | for pais in paises:
77 | print(pais)
78 | if pais == "Índia":
79 | break
80 | ```
81 |
82 | Como podemos ver só serão impressos os países **China** e **Índia**, quando **pais** tiver o valor de **Índia** o loop irá parar e não será capaz de imprimir **Tailândia**.
83 |
84 | A palavra-chave **continue** nos permite parar a iteração atual do loop e continuar para a próxima:
85 |
86 | ```python
87 | linguagens = ['C','Javascript','Python','Lua']
88 |
89 | for linguagem in linguagens:
90 | if linguagem == "Javascript":
91 | continue
92 | print(linguagem)
93 | ```
94 |
95 | Como podem ver, ao chegamos em **Javascript** o loop pára e vai para a próxima impressão, nos retornando apenas 'C', 'Python' e 'Lua'.
96 |
97 | Dessa forma é muito fácil criarmos um **for loop** para imprimir apenas números pares:
98 |
99 | ```python
100 | for x in range(10):
101 | if x % 2 == 1:
102 | continue
103 | print(x)
104 | ```
105 |
106 | Nos serão trazidos todos os números pares de 0 até 9.
107 |
108 | **Python** nos permite também usarmos a palavra-chave **else** em conjunto com o **for**, por exemplo:
109 |
110 | ```python
111 | for x in range(10):
112 | print(x)
113 | else:
114 | print("Loop finalizado com sucesso!")
115 | ```
116 |
117 | ### Loops Encadeados
118 |
119 | Loops encadeados são loops dentro de loops, o "loop de dentro" será executado uma vez para cada iteração do "loop de fora".
120 |
121 | ```python
122 | cores = ['azul','verde','amarelo']
123 | numeros = [1,2,3]
124 |
125 | for cor in cores:
126 | for numero in numeros:
127 | print(f'{cor.capitalize()} - {numero}')
128 | ```
129 |
130 | ### Enumerando Valores
131 |
132 | O método **enumerate()** adiciona um contador a um iterável e o retorna o objeto enumerate.
133 |
134 | O método **enumerate()** recebe dois parâmetros:
135 |
136 | - **iterable**: Uma sequência, um iterator, ou objetos que suportam iteração
137 | - **start** (opcional): É o número que o método **enumerate()** iniciará contando, se **start** for omitido, 0 será o valor padrão.
138 |
139 | Vejamos um exemplo de como podemos usá-lo:
140 |
141 | ```python
142 | alimentos = ['arroz','feijão','batata']
143 |
144 | for indice,alimento in enumerate(alimentos):
145 | print(f'{indice} -> {alimento}')
146 | ```
147 |
148 | Informando o parâmetro start:
149 |
150 | ```python
151 | for indice,alimento in enumerate(alimentos,10):
152 | print(f'{indice} -> {alimento}')
153 | ```
154 |
155 | Dessa vez ele começará a contar a partir do número **10**.
156 |
157 | Vimos nestes exemplos que as utilidades do **for** são imensas e podem nos ajudar bastante no sentido de percorrer sequências e até mesmo gerá-las com **range()**.
158 |
--------------------------------------------------------------------------------
/content/geradores.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Geradores'
3 | description: 'Aprenda sobre Geradores'
4 | ---
5 |
6 | Introduzidos no [PEP 255](https://www.python.org/dev/peps/pep-0255), as funções geradoras são um tipo especial de função que retorna um [lazy iterator](https://en.wikipedia.org/wiki/Lazy_evaluation). Esses são objetos que você pode percorrer como uma lista. No entanto, ao contrário das listas, os lazy iterators não armazenam seu conteúdo na memória.
7 |
8 | Em outras palavras, **Geradores** são **iteradores**, porém só podemos iterar sob eles uma vez, pelo fato deles não guardarem todos os valores em memória, eles vão gerando os valores conforme instruímos. Nós usamos os geradores iterando sob eles, seja com um **for loop** ou passando eles para uma função ou constructo que seja capaz de iterar.
9 |
10 | Na maioria das vezes os geradores são implementados como **funções**, entretanto, eles não retornam um valor com **return**, eles usam a palavra chave **yield**, que seria uma forma de ir guardando os valores.
11 |
12 | Veja agora um exemplo de uma função geradora.
13 |
14 | ```python
15 | def gerador():
16 | for e in range(5):
17 | yield e
18 |
19 | for item in gerador():
20 | print(item)
21 | # 0
22 | # 1
23 | # 2
24 | # 3
25 | # 4
26 | ```
27 |
28 | Veja que nesse caso não há muita utilidade, geradores são melhores para calcular **grandes quantidades** de resultados (particularmente cálculos que envolvem loops) onde não queremos alocar memória para todos os resultados ao mesmo tempo, trata-se de **eficiência**.
29 |
30 | Agora veja um gerador que é capaz de calcular números **fibonacci**:
31 |
32 | ```python
33 | def fib_gen(n):
34 | a = b = 1
35 | for e in range(n):
36 | a, b = b, a + b
37 | yield a
38 |
39 | for x in fib_gen(7):
40 | print(x)
41 | # 1
42 | # 1
43 | # 2
44 | # 3
45 | # 5
46 | # 8
47 | # 13
48 | ```
49 |
50 | Também podemos definir um gerador que irá gerar uma **sequência infinita**:
51 |
52 | ```python
53 | def sequencia_infinita():
54 | num = 0
55 | while True:
56 | yield num
57 | num +=1
58 |
59 | for i in sequencia_infinita():
60 | print(i,end=' ')
61 | ```
62 |
63 | Este programa irá executar infinitamente até que o paremos, podemos usar o comando `CTRL + C` para isso. Outra opção que temos é usar o método **next()**, dessa vez vamos controlar o número de iterações:
64 |
65 | ```python
66 | gen = sequencia_infinita()
67 | for _ in range(501):
68 | print(next(gen),end=',')
69 | ```
70 |
71 | Dessa vez serão gerados números de 0 até 500.
72 |
73 | ## Expressões Geradoras
74 |
75 | **Python** nos permite criar simples geradores usando **expressões geradoras**, fazendo com que o processo de criação de geradores seja muito mais simples. Assim como as funções lambda criam funções anônimas, expressões geradoras criam funções geradoras anônimas.
76 |
77 | A sintaxe da expressão geradora nos lembra as **list comprehensions**, porém os colchetes são alterados para parênteses. A grande diferença entre os dois é que a compreensão de lista produz a lista inteira de uma só vez, enquanto que a expressão geradora produz um item de cada vez, fazendo dela muito mais eficiente em questões de desempenho e memória.
78 |
79 | Para o exemplo, vamos começar inicializando uma lista:
80 |
81 | ```python
82 | lista = [1, 3, 6, 10, 14]
83 | ```
84 |
85 | Elevamos ao cubo cada elemento da lista, usando uma list comprehension:
86 |
87 | ```python
88 | [x**3 for x in lista] # [1, 27, 216, 1000, 2744]
89 | ```
90 |
91 | Veja que de imediato obtemos uma nova lista com todos os elementos elevados ao cubo. Se quisermos alterar para uma expressão geradora, apenas precisamos trocar os colchetes por parênteses:
92 |
93 | ```python
94 | gerador = (x**3 for x in lista)
95 | print(gerador) # at 0x7fd0067de9d0>
96 | ```
97 |
98 | Dessa vez nos é retornado um objeto generator, que podemos iterar sob ele:
99 |
100 | ```python
101 | for gen in gerador:
102 | print(gen)
103 | # 1
104 | # 27
105 | # 216
106 | # 1000
107 | # 2744
108 | ```
109 |
110 | Observe que a **expressão geradora** não produziu o resultado que esperávamos de forma imediata, na verdade retornou um **objeto gerador**, que é capaz de produzir items sob demanda.
111 |
112 | Inicializamos agora uma outra lista para vermos como um gerador funciona ao usarmos o método **next()**:
113 |
114 | ```python
115 | l = [2,3,6,9] #
116 |
117 | a = (x**4 for x in l)
118 |
119 | print(next(a)) # 16
120 | print(next(a)) # 81
121 | print(next(a)) # 1296
122 | print(next(a)) # 6561
123 | print(next(a))
124 | # Traceback (most recent call last):
125 | # File "", line 1, in
126 | # StopIteration
127 | ```
128 |
129 | Veja que ao atingirmos o limite da lista, o erro **StopIteration** ocorre.
130 |
131 | As **expressões geradoras** também podem ser usadas dentro de funções, por exemplo:
132 |
133 | ```python
134 | numeros = [4,5,6,7]
135 |
136 | print(sum(x**4 for x in numeros)) # 4578
137 | print(max(x**4 for x in numeros)) # 2401
138 | ```
139 |
140 | ## Importância dos Geradores
141 |
142 | Agora uma questão importante. Por que geradores são usados em Python?
143 |
144 | 1. Fácil de implementar, geradores podem ser implementados de maneira clara e concisa, de forma muito mais simples que os iteradores
145 | 2. Eficiência de memória, por produzirem um item por vez e não gerarem toda a sequência de uma só vez, os geradores nos trazem bastante perfomance.
146 | 3. Nos permitem produzir um fluxo infinito de dados, uma vez que esses fluxos não podem ser guardados em memória por serem infinitos, os geradores nos permitem trabalhar com eles, uma vez que itens serão gerados um por vez.
147 |
148 | Para entendermos a eficiência de memória de um gerador, vamos compará-lo com uma list comprehension para observarmos a diferença de tamanho entre eles. Vamos começar definindo uma função geradora:
149 |
150 | ```python
151 | def gen(n):
152 | for i in range(n):
153 | yield i**2
154 | ```
155 |
156 | Agora vamos construir uma list comprehension com 100.000 elementos e um gerador com o mesmo número e usaremos a função **getsizeof** do módulo **sys** para obtermos a quantidade ocupada de memória do objeto em bytes:
157 |
158 | ```python
159 | import sys
160 |
161 | x = [i**2 for i in range(100_000)]
162 | g = gen(100_000)
163 |
164 | print(sys.getsizeof(x)) # 824472
165 | print(sys.getsizeof(g)) # 128
166 | ```
167 |
168 | Veja que temos uma diferença substancial, com este exemplo, concluímos que os geradores são extremamente eficientes!
169 |
--------------------------------------------------------------------------------
/content/ambiente.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Ambiente de Programação'
3 | description: 'Aprenda sobre Ambientes de Programação'
4 | ---
5 |
6 | Obter **Python** é muito fácil, para isso precisamos acessar o site oficial e fazer o download: **[python.org](https://www.python.org/downloads/)**. Recomendamos que você faça o download da versão mais recente e siga as *instruções de instalação*. Vale lembrar que se você usa o sistema operacional **MacOS** ou **Linux**, existem grandes chances do **Python** já estar instalado.
7 |
8 | Caso queira confirmar se **Python** está instalado no seu sistema, abra sua **[interface de linha de comando](https://pt.wikipedia.org/wiki/Interface_de_linha_de_comandos)** e digite:
9 |
10 | ```
11 | python --version
12 | ```
13 |
14 | Como você pôde observar, será retornada a versão atual do Python em sua máquina.
15 |
16 | ## Iniciando
17 |
18 | Antes de começarmos a programar, é de extrema importância que tenhamos um editor de texto eficiente e leve, para isso existem muitas opções excelentes:
19 |
20 | - [Sublime Text](https://www.sublimetext.com/)
21 | - [Brackets](http://brackets.io/)
22 | - [Notepad++](https://notepad-plus-plus.org/)
23 | - [Gedit](https://wiki.gnome.org/Apps/Gedit)
24 | - [Visual Studio Code](https://code.visualstudio.com/)
25 | - [Vim](https://www.vim.org/)
26 | - [Light Table](http://lighttable.com/)
27 | - [GNU Emacs](https://www.gnu.org/software/emacs/)
28 |
29 | Caso você tenha preferências por [Ambientes de Desenvolvimento Integrado](https://pt.wikipedia.org/wiki/Ambiente_de_desenvolvimento_integrado) mais robustos e completos, você pode optar por:
30 |
31 | - [Thonny](https://thonny.org/)
32 | - [PyCharm](https://www.jetbrains.com/pycharm/download/)
33 | - [IPython](https://ipython.org/)
34 | - [PyDev](http://www.pydev.org/)
35 | - [Spyder](https://www.spyder-ide.org/)
36 |
37 | Se eventualmente você desejar executar seus scripts Python em um ambiente online usando o seu Web Browser, você pode usar uma das seguintes opções:
38 |
39 | - [Python Shell](https://www.python.org/shell/)
40 | - [Repl.it](https://repl.it/languages/python3)
41 | - [Python Online Compiler](https://www.programiz.com/python-programming/online-compiler/)
42 | - [Python Tryit Editor](https://www.w3schools.com/python/trypython.asp?filename=demo_compiler)
43 | - [Online Python Interpreter](https://www.onlinegdb.com/online_python_interpreter)
44 |
45 | Nesse guia iremos utilizar o **Sublime Text**, porém sinta-se livre para escolher o editor que mais lhe agrada. Faça o download, siga os passos da instalação e vamos começar a nossa aventura!
46 |
47 | Assumindo que você está com o **Python** instalado em sua máquina e já tem um editor de texto em mãos, inicie o editor de Texto (a partir daqui assumiremos o Sublime Text como exemplo) e vá até `File -> New File`. Nesse arquivo vamos digitar nosso primeiro programa, o tradicional *Hello World*:
48 |
49 | ```python
50 | print("Hello World") # Hello World
51 | ```
52 |
53 | Salve o arquivo, `File -> Save` ou através do atalho `CTRL + S`, importante você lembrar que a **[extensão dos arquivos](https://pt.wikipedia.org/wiki/Extensão_de_nome_de_ficheiro)** Python termina com `.py`, nesse caso nosso arquivo será chamado de **`hello.py`**, em seguida vá até `Tools -> Build System -> Python`. Agora que o Sublime Text está configurado para interpretar todos os nossos *scripts*, para executarmos ele devemos ir até `Tools -> Build` ou simplesmente através do atalho `CTRL + B`.
54 |
55 | Feito! Você acabou de escrever o seu primeiro programa em Python, se tudo ocorreu como esperado, aparecerá no console do **Sublime Text** a mensagem **Hello World**!
56 |
57 | ## Python Interativo
58 |
59 | Vale ressaltar também, como antes já citado, que o Python é capaz de rodar na **[interface de linha de comando](https://pt.wikipedia.org/wiki/Interface_de_linha_de_comandos)**, abra a sua e faça o teste digitando:
60 |
61 | ```python
62 | python3
63 | ```
64 |
65 | Aparecerão algumas informações, como a versão do Python, sua data e você verá **`>>>`**, esse é o **interpretador** do Python, agora é só digitarmos:
66 |
67 | ```python
68 | >>> print("Hello World") # Hello World
69 | ```
70 |
71 | Para obter ajuda no **interpretador** nós podemos utilizar a função **help()**, que recebe como parâmetro um **objeto** que desejamos entender melhor, por exemplo:
72 |
73 | ```python
74 | >>> help(float) # Nos trará informações sobre a classe float
75 | >>> help(print) # Nos trará informações sobre a função print
76 | ```
77 |
78 | ## Filosofia Python
79 |
80 | Para conhecer a Essência & Filosofia da Linguagem Python você pode digitar o seguinte comando:
81 |
82 | ```python
83 | >>> import this
84 | ```
85 |
86 | Nos será retornado:
87 |
88 | ```
89 | The Zen of Python, by Tim Peters
90 |
91 | Beautiful is better than ugly.
92 | Explicit is better than implicit.
93 | Simple is better than complex.
94 | Complex is better than complicated.
95 | Flat is better than nested.
96 | Sparse is better than dense.
97 | Readability counts.
98 | Special cases aren't special enough to break the rules.
99 | Although practicality beats purity.
100 | Errors should never pass silently.
101 | Unless explicitly silenced.
102 | In the face of ambiguity, refuse the temptation to guess.
103 | There should be one-- and preferably only one --obvious way to do it.
104 | Although that way may not be obvious at first unless you're Dutch.
105 | Now is better than never.
106 | Although never is often better than *right* now.
107 | If the implementation is hard to explain, it's a bad idea.
108 | If the implementation is easy to explain, it may be a good idea.
109 | Namespaces are one honking great idea -- let's do more of those!
110 | ```
111 |
112 | O **[Zen of Python](https://en.wikipedia.org/wiki/Zen_of_Python)**, escrito por Tim Peters descreve a filosofia e os princípios que guiam boas práticas da linguagem Python.
113 |
114 | Existe um *easter egg* muito divertido no Python, conhecido como *antigravity*, que nos redireciona para um quadrinho que ilustra o potencial da linguagem. Para vermos ele, devemos simplesmente importar o seguinte comando:
115 |
116 | ```python
117 | import antigravity
118 | ```
119 |
120 | Nos será apresentado:
121 |
122 | 
123 |
124 | Para sair do **interpretador** basta digitar o comando `exit()`, `quit()` ou `CTRL + D`. Agora que temos nosso ambiente de programação estabelecido, já estamos prontos para mergulhar em mares mais profundos e explorar as diversas capacidades que **Python** tem a nos oferecer, bem como todos os seus detalhes!
125 |
--------------------------------------------------------------------------------
/content/sets.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Sets'
3 | description: 'Aprenda sobre Sets em Python'
4 | ---
5 |
6 | Sets são **coleções não-ordenadas** de itens **ÚNICOS**, embora um Set possa ser modificado, os elementos contidos dentro do Set devem ser imutáveis. Sets são definidos por valores separados por vírgula dentro de chaves `{}`.
7 |
8 | **Importante:** Cuidado para não confundir os Sets com os dicionários!
9 |
10 | A principal vantagem de usar um **Set**, ao contrário de uma lista, é que ele possui um mecanismo altamente otimizado para verificar se um elemento específico está contido nele.
11 |
12 | Talvez você lembre dos Sets através da **[famosa teoria matemática dos conjuntos](https://pt.wikipedia.org/wiki/Teoria_dos_conjuntos)**.
13 |
14 | 
15 |
16 | Os Sets podem ser usados para executarmos operações matemáticas de conjuntos como **união**, **intersecção**, **diferença simétrica**, etc.
17 |
18 | ### Definindo um Set
19 |
20 | Para definirmos um **Set** é muito simples:
21 |
22 | ```python
23 | s = {1,1,2,3,3,4}
24 | print(type(s)) #
25 | print(s) # {1, 2, 3, 4}
26 | ```
27 |
28 | Observe que os valores repetidos foram eliminados de nosso set.
29 |
30 | Também podemos criar um set através do método **set()**:
31 |
32 | ```python
33 | k = set([1,2,3,4,5])
34 | print(type(k)) #
35 | print(k) # {1, 2, 3, 4, 5}
36 | ```
37 |
38 | Lembrando que podemos iterar sob um set com um **for loop**:
39 |
40 | ```python
41 | for itens in k:
42 | print(itens)
43 | ```
44 |
45 | ### Operações com Sets
46 |
47 | O método **add()** nos possibilita adicionar um item ao set:
48 |
49 | ```python
50 | k.add(8)
51 | print(k) # {1, 2, 3, 4, 5, 8}
52 | ```
53 |
54 | O método **discard()** nos permite remover itens de um set:
55 |
56 | ```python
57 | k.discard(1)
58 | print(k) # {2, 3, 4, 5, 8}
59 | ```
60 |
61 | Para remover todos os elementos do set podemos usar o método **clear()**:
62 |
63 | ```python
64 | k.clear()
65 | print(k) # set()
66 | ```
67 |
68 | Também podemos usar os sets para eliminar letras repetidas de uma palavra:
69 |
70 | ```python
71 | print(set('cachorro')) # {'o', 'a', 'c', 'r', 'h'}
72 | ```
73 |
74 | Para sabermos o número de elementos em um set usamos o método **len()**:
75 |
76 | ```python
77 | len(set('cachorro')) # 5
78 | ```
79 |
80 | Vamos agora definir dois novos sets `x` e `y` para testarmos **novas operações**.
81 |
82 | ```python
83 | x = {1,2,3}
84 | y = {2,3,4}
85 | ```
86 |
87 | ### Intersecção
88 |
89 | Para intersecção podemos usar `&` ou o método **intersection()**.
90 |
91 | 
92 |
93 | ```python
94 | print(x & y) # {2, 3}
95 | print(x.intersection(y)) # {2, 3}
96 | ```
97 |
98 | ### Diferença
99 |
100 | Para diferença podemos usar `-` ou o método **difference()**.
101 |
102 | 
103 |
104 | ```python
105 | # Relativo a x
106 | print(x - y) # {1}
107 | x.difference(y) # {1}
108 |
109 | # Relativo a y
110 | print(y - x) # {4}
111 | y.difference(x) # {4}
112 | ```
113 |
114 | ### Diferença Simétrica
115 |
116 | Para diferença simétrica podemos usar `^` ou o método **symmetric_difference()**.
117 |
118 | 
119 |
120 | ```python
121 | print(x.symmetric_difference(y)) # {1, 4}
122 | print(y.symmetric_difference(x)) # {1, 4}
123 | print(x ^ y) # {1, 4}
124 | print(y ^ x) # {1, 4}
125 | ```
126 |
127 | Todos imprimem o mesmo resultado, uma vez que a diferença é simétrica.
128 |
129 | ### União
130 |
131 | Para união podemos usar `|` ou o método **union()**.
132 |
133 | 
134 |
135 | ```python
136 | print(x | y) # {1, 2, 3, 4}
137 | print(x.union(y)) # {1, 2, 3, 4}
138 | ```
139 |
140 | ### Verificando a presença de um Elemento
141 |
142 | Assim como nas outras estruturas de dados compostas, nos sets também é possível verificarmos a **presença** ou **absência** de um determinado elemento com o uso da palavra-chave **in**, por sinal, os sets são muito eficientes para essas operações.
143 |
144 | ```python
145 | print(1 in x) # True
146 | print(5 in x) # False
147 | print(10 not in x) # True
148 | print(1 not in x) # False
149 | ```
150 |
151 | ### Referência dos Sets
152 |
153 | Os Sets nos trazem diversas funcionalidades e nos permitem resolver diversos problemas, para conhecer mais detalhes sobre eles visite a **[documentação oficial](https://docs.python.org/3/tutorial/datastructures.html#sets)**.
154 |
155 | A tabela a seguir apresenta os métodos mais importantes dos sets e suas descrições:
156 |
157 | | Método | Descrição |
158 | |-------------------------------|:--------------------------------------------------------------------------------:|
159 | | add() | Adiciona um elemento ao set |
160 | | clear() | Remove todos os elementos do set |
161 | | copy() | Retorna uma cópia do set |
162 | | difference() | Retorna um set contendo a diferença entre dois ou mais sets |
163 | | difference_update() | Remove os itens desse set que também estão incluídos em outro set especificado |
164 | | discard() | Remove um item específico |
165 | | intersection() | Retorna um set que é intersecção entre dois sets |
166 | | intersection_update() | Remove os itens desse set que não estão presente em outro set especificado |
167 | | isdisjoint() | Retorna se dois sets possuem intersecção ou não |
168 | | issubset() | Retorna se outro set contém esse set ou não |
169 | | issuperset() | Retorna se esse set contém outro set ou não |
170 | | pop() | Remove o item especificado |
171 | | remove() | Remove o item especificado |
172 | | symmetric_difference() | Retorna um set com a diferença simétrica de dois sets |
173 | | symmetric_difference_update() | Insere a diferença simétrica desse set no outro |
174 | | union() | Retorna um set contendo a união de sets |
175 | | update() | Atualiza o set com a união desse set e outros |
176 |
--------------------------------------------------------------------------------
/content/expressoes-lambda.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Expressões Lambda'
3 | description: 'Aprenda sobre Expressões Lambda'
4 | ---
5 |
6 | **Expressões lambda** também são conhecidas como **funções anônimas**, elas diferem das funções comuns por serem declaradas de maneira diferente, sem definirmos nome para criarmos elas, utilizamos a palavra-chave **lambda** para definí-las.
7 |
8 | Python e outras linguagens como Java, C# e até mesmo C++ tiveram as funções lambda adicionadas a sua sintaxe, já linguagens como LISP, ou linguagens da família **[ML](https://en.wikipedia.org/wiki/ML_(programming_language))**: Haskell, OCaml e F# usam lambdas como um conceito central.
9 |
10 | Expressões Lambda em Python e em outras linguagens de programação possuem suas raízes no **[cálculo lambda](https://en.wikipedia.org/wiki/Lambda_calculus)**, um modelo de computação inventando por **[Alonzo Church](https://en.wikipedia.org/wiki/Alonzo_Church)**.
11 |
12 | O cálculo lambda pode codificar qualquer cálculo, é [Turing completo](https://simple.wikipedia.org/wiki/Turing_complete), mas ao contrário do conceito de [máquina de Turing](https://en.wikipedia.org/wiki/Turing_machine), é puro e não guarda nenhum [estado](https://en.wikipedia.org/wiki/Turing_machine#The_%22state%22).
13 |
14 | As linguagens funcionais têm sua origem na lógica matemática e no cálculo lambda, enquanto as linguagens de programação imperativas adotam o modelo de computação baseado em estado inventado por Alan Turing. Os dois modelos de computação, cálculo lambda e máquinas de Turing, podem ser traduzidos um no outro. Essa equivalência é conhecida como [hipótese de Church-Turing](https://en.wikipedia.org/wiki/Church%E2%80%93Turing_thesis).
15 |
16 | As linguagens funcionais herdam diretamente a filosofia do cálculo lambda, adotando uma abordagem declarativa de programação que enfatiza a abstração, a transformação de dados, a composição e a pureza (sem estado e sem efeitos colaterais). Exemplos de linguagens funcionais incluem Haskell e Lisp.
17 |
18 | - Expressões lambdas podem receber qualquer número de argumentos, porém retornam apenas um valor na forma de expressão, elas não podem ter comandos ou multiplas expressões
19 | - Uma função anônima não pode ser chamada diretamente pela função **print()**, pois ela requer uma expressão
20 |
21 | ### Funções Anônimas
22 |
23 | Os seguintes termos são usados de forma de forma intercambiável dependendo da linguagem de programação ou local que você vive:
24 |
25 | - Funções Anônimas
26 | - Funções Lambda
27 | - Expressões Lambda
28 | - Abstrações Lambda
29 | - Forma Lambda
30 | - Literais de Função
31 |
32 | ### Fundamentos Básicos
33 |
34 | 
35 |
36 | A estrutura para utilizarmos as funções lambdas é muito simples
37 |
38 | ```
39 | lambda argumento1, argumento2, argumento3: expressão
40 | ```
41 |
42 | Por exemplo, se quisermos multiplicar o argumento por **3**:
43 |
44 | ```python
45 | triplo = lambda x: x * 3
46 | print(type(triplo)) #
47 | print(triplo(3)) # 9
48 | ```
49 |
50 | Se quisermos elevar o número ao quadrado:
51 |
52 | ```python
53 | quadrado = lambda x: x * x
54 | print(quadrado(5)) # 25
55 | ```
56 |
57 | As expressões lambdas também nos permitem trabalharmos com strings, por exemplo:
58 |
59 | ```python
60 | nome_completo = lambda nome,sobrenome: f'Nome: {nome.title()}\nSobrenome: {sobrenome.title()}'
61 | print(nome_completo('isaac','newton'))
62 | # Nome: Isaac
63 | # Sobrenome: Newton
64 | ```
65 |
66 | Podemos também usar **condicionais** com funções Lambda
67 |
68 | ```python
69 | comeca_com_G = lambda x: True if x.startswith('G') else False
70 | print(comeca_com_G('Gabriel')) # True
71 | print(comeca_com_G('Rafael')) # False
72 | ```
73 |
74 | Se quisermos verificar se um determinado número é ímpar:
75 |
76 | ```python
77 | impar = lambda x: True if x % 2 == 1 else False
78 | print(impar(1)) # True
79 | print(impar(8)) # False
80 | ```
81 |
82 | Até mesmo compor funções mais complexas, neste caso, imprimir a palavra que vem antes da palavra passada via argumento.
83 |
84 | ```python
85 | palavra_antes = lambda s, w: s.split()[s.split().index(w)-1] if w in s else None
86 | sentenca = 'Rato Roeu Roupa Rei Roma'
87 | print(palavra_antes(sentenca,'Roma')) # Rei
88 | ```
89 |
90 | ### Lambda em Python
91 |
92 | Nós normalmente usamos as funções Lambda quando precisamos de uma função por um período curto de tempo, podemos também usá-las como argumentos para funções de **high-order** (funções que recebem outras funções como argumento).
93 |
94 | **Funções lambda** também podem ser usadas com outras funções pré-construídas, como **filter()**, **map()**, etc.
95 |
96 | #### Filtrando
97 |
98 | Por exemplo, com **filter()**, que recebe uma função e uma lista como argumento.
99 |
100 | ```python
101 | lista = [1,2,3,4,5]
102 |
103 | nova_lista = list(filter(lambda x: (x % 2 == 0), lista))
104 |
105 | print(nova_lista) # [2, 4]
106 | ```
107 |
108 | Veja que a expressão lambda calculará o resto de divisão de cada valor da lista, caso o valor seja 0 o número será filtrado para nossa nova lista, formando assim uma lista de números pares.
109 |
110 | #### Mapeando
111 |
112 | Por exemplo, com **map()**, que também recebe uma função e uma lista como argumento.
113 |
114 | ```python
115 | lst = [3,5,6,7,9]
116 |
117 | nova_lst = list(map(lambda y: y * 10, lst))
118 |
119 | print(nova_lst) # [30, 50, 60, 70, 90]
120 | ```
121 |
122 | Dessa vez a expressão lambda multiplicará cada item da lista por 10 e estes serão mapeados em uma nova lista.
123 |
124 | Podemos usar esta ideia para converter de uma lista de temperaturas em grau Celsius para grau Fahrenheit.
125 |
126 | ```python
127 | celsius = [31.5, 22.1, 17.5, 42.8]
128 |
129 | fahrenheit = map(lambda x: (float(9)/5)*x + 32, celsius)
130 |
131 | print(list(fahrenheit)) # [88.7, 71.78, 63.5, 109.03999999999999]
132 | ```
133 |
134 | #### Ordenando
135 |
136 | Através do método **sort()** podemos por exemplo organizar uma **lista** com uma expressão lambda. Vejamos um exemplo para ilustrar esta ideia:
137 |
138 | ```python
139 | alimentos = [('ovos', 10),('pães', 5),('tomate', 6),('cenoura', 4),('maçã', 3)]
140 | ```
141 |
142 | Ordenando os alimentos por ordem alfabética:
143 |
144 | ```python
145 | alimentos.sort(key = lambda x: x[0])
146 | print(alimentos)
147 | # [('cenoura', 4), ('maçã', 3), ('ovos', 10), ('pães', 5), ('tomate', 6)]
148 | ```
149 |
150 | Ordenando os alimentos por quantidade crescente:
151 |
152 | ```python
153 | alimentos.sort(key = lambda x: x[1])
154 | print(alimentos)
155 | # [('maçã', 3), ('cenoura', 4), ('pães', 5), ('tomate', 6), ('ovos', 10)]
156 | ```
157 |
158 | Obtendo o alimento com a maior quantidade:
159 |
160 | ```python
161 | print(max(alimentos, key = lambda x: x[1])) # ('ovos', 10)
162 | ```
163 |
164 | Obtendo o alimento com a menor quantidade:
165 |
166 | ```python
167 | print(min(alimentos, key = lambda x: x[1])) # ('maçã', 3)
168 | ```
169 |
170 | #### Função que cria Funções
171 |
172 | É possível criarmos uma função que nos **retorna** uma expressão lambda para assim realizarmos cálculos:
173 |
174 | ```python
175 | # Função que cria funções
176 | def construcao_quadraticas(a, b, c):
177 | """Retorna a função f(x) = ax^2 + bx + c"""
178 | return lambda x: a*x**2 + b*x + c
179 |
180 | # Constrói uma nova função com os parâmetros (4,7,-6)
181 | f = construcao_quadraticas(4,7,-6)
182 |
183 | print(f(0)) # -6
184 | print(f(3)) # 51
185 | ```
186 |
187 | Muito legal e útil, não? **Expressões lambdas** podem agilizar bastante nossa vida.
188 |
--------------------------------------------------------------------------------
/content/numeros.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Números'
3 | description: 'Introdução aos números'
4 | ---
5 |
6 | 
7 |
8 | Em **Python** existem **três** tipos numéricos, são eles:
9 |
10 | - *int*
11 | - *float*
12 | - *complex*
13 |
14 | É importante lembrarmos que tudo em **Python** é um **objeto**, sendo assim, tipos de dados são **classes** e variáveis são instâncias (objetos) dessas classes, não se preocupe que veremos esses aspectos com mais detalhe ao longo do guia.
15 |
16 | Variáveis do tipo numérico são criadas quando atribuimos valores a elas:
17 |
18 | ```python
19 | a = 27 # int
20 | b = 22.2 # float
21 | c = 3j # complex
22 | ```
23 |
24 | Para verificarmos qual classe a variável pertence, podemos utilizar a função **type()**:
25 |
26 | ```python
27 | print(type(a)) #
28 | print(type(b)) #
29 | print(type(c)) #
30 | ```
31 |
32 | ## Int
33 |
34 | Inteiros são números **positivos**, **negativos**, que não apresentam casas decimais, seu tamanho é limitado apenas pela capacidade de memória disponível:
35 |
36 | ```python
37 | a = 3
38 | b = 342907249723902
39 | c = -100
40 |
41 | print(type(a)) #
42 | print(type(b)) #
43 | print(type(c)) #
44 | ```
45 |
46 | ## Float
47 |
48 | Floats ou **"números de ponto flutuante"** são números positivos ou negativos que podem conter uma ou mais casas decimais:
49 |
50 | ```python
51 | a = 23.3
52 | b = 2.0
53 | c = -17.78
54 |
55 | print(type(a)) #
56 | print(type(b)) #
57 | print(type(c)) #
58 | ```
59 |
60 | Podemos acrescentar o caracter **e** ou **E** seguido por um número inteiro positivo ou negativo para especificar a [notação científica](https://en.wikipedia.org/wiki/Scientific_notation).
61 |
62 | ```python
63 | e = 35e4
64 | print(type(e)) #
65 | print(e) # 350000.0
66 |
67 | E = 3.8e-2
68 | print(type(E)) #
69 | print(E) # 0.038
70 | ```
71 |
72 | O valor máximo que um **float** pode ter é aproximadamente `1.8×10^308`. Qualquer número maior que este é indicado pelo valor **inf** (infinity).
73 |
74 | ```python
75 | print(1.79e308) # 1.79e+308
76 | print(1.8e308) # inf
77 | ```
78 |
79 | Entretanto, o valor mínimo que um **float** pode ter é aproximadamente `5.0×10^-324`. Qualquer número menor que este é considerado **0** (zero).
80 |
81 | ```python
82 | print(5e-324) # 5e-324
83 | print(5e-325) # 0.0
84 | ```
85 |
86 | ## Complex
87 |
88 | Números complexos são escritos com `j` representando a parte imaginária. Eles podem ser escritos `complex(3,4)` ou `3 + 4j`. Um número complexo Python `c` é armazenado internamente usando coordenadas Cartesianas ou Retangulares.
89 |
90 | Vejamos alguns exemplos:
91 |
92 | ```python
93 | a = 2+4j
94 | b = -3j
95 | c = complex(3,4)
96 |
97 | print(type(a)) #
98 | print(type(b)) #
99 | print(type(c)) #
100 | ```
101 |
102 | Obtendo as partes **Real** e **Imaginária** de um número complexo:
103 |
104 | ```python
105 | print(c.real) # 3.0
106 | print(c.imag) # 4.0
107 | ```
108 |
109 | ### Operações
110 |
111 | Realizando a operação de **adição** com números complexos:
112 |
113 | ```python
114 | x = complex(4,3)
115 | y = complex(-1,4)
116 | z = complex(2,1)
117 |
118 | print(x + y) # (3+7j)
119 | ```
120 |
121 | Acrescentando um escalar adicionará à **parte real**:
122 |
123 | ```python
124 | print(x + 1) # (5+3j)
125 | ```
126 |
127 | Também podemos realizar a operação de **multiplicação** com números complexos:
128 |
129 | ```python
130 | print(x * y) # (-16+13j)
131 | ```
132 |
133 | Multiplicação por um Escalar:
134 |
135 | ```python
136 | print(x * 2) # (8+6j)
137 | ```
138 |
139 | ### Extensão
140 |
141 | A função `abs(z)` retorna a extensão do número complexo `z`, em outras palavras, representa o cálculo da seguinte fórmula:
142 |
143 | 
144 |
145 | ```python
146 | print(abs(z)) # 2.23606797749979
147 | ```
148 |
149 | Também podemos realizar este cálculo com o auxílio da função **sqrt()** da biblioteca math.
150 |
151 | ```python
152 | from math import sqrt
153 |
154 | sqrt(z.real**2 + z.imag**2) # 2.23606797749979
155 | ```
156 |
157 | ### Ângulo
158 |
159 | A função `phase()` retorna o ângulo `x` em radianos, porém, para usá-la teremos que importar a biblioteca **[cmath](https://docs.python.org/3/library/cmath.html)** em nosso código.
160 |
161 | Esta biblioteca nos traz funções matemáticas específicas para números complexos.
162 |
163 | ```python
164 | import cmath
165 |
166 | print(cmath.phase(x)) # 0.6435011087932844
167 | print(phase(complex(-1.0, 0.0))) # 3.1415926535897931
168 | print(phase(complex(-1.0, -0.0))) # -3.1415926535897931
169 | ```
170 |
171 | O resultado estará entre [-π, π]
172 |
173 | ### Constante π and e
174 |
175 | A biblioteca cmath também nos traz constantes matemáticas como **e** e **pi**:
176 |
177 | ```python
178 | print(cmath.pi) # 3.141592653589793
179 | print(cmath.e) # 2.718281828459045
180 | ```
181 |
182 | ## Números Aleatórios
183 |
184 | Embora Python não tenha uma função **random()** para nos gerar um número aleatório, existe um módulo construído em Python chamado `random` que nos permite criar números aleatórios:
185 |
186 | ```python
187 | import random
188 |
189 | print(random.randrange(1,10))
190 | ```
191 |
192 | A função acima gera números entre 1 e 9.
193 |
194 | Caso queira saber mais detalhes sobre o módulo `random` você pode visitar sua **[Referência](https://www.w3schools.com/python/module_random.asp)**.
195 |
196 | ## Conversão de Números
197 |
198 | A linguagem Python nos permite converter entre tipos numéricos.
199 |
200 | ```python
201 | k = 3
202 | i = 7.7
203 | z = 4j
204 |
205 | print(type(k)) #
206 | print(type(i)) #
207 | print(type(z)) #
208 | ```
209 |
210 | Convertendo de **int** para **float**:
211 |
212 | ```python
213 | print(float(k)) # 3.0
214 | ```
215 |
216 | Convertendo de **float** para **int**:
217 |
218 | ```python
219 | print(int(i)) # 7
220 | ```
221 |
222 | Convertendo de **int** para **complex**:
223 |
224 | ```python
225 | print(complex(k)) # (3+0j)
226 | ```
227 |
228 | Importante lembrar que não podemos converter um número complexo para outro tipo numérico.
229 |
230 | ## Bases
231 |
232 | Normalmente escrevemos inteiros na base 10. No entanto, Python nos permite escrever inteiros nos formatos **Hexadecimal** (base 16), **Octal** (base 8) e **Binário** (base 2).
233 |
234 | Podemos fazer isso adicionando um dos seguintes prefixos ao número inteiro:
235 |
236 | | Prefixo | Interpretação | Base |
237 | |---|---|--- |
238 | | `0b` ou `0B` | Binário | 2 |
239 | | `0o` ou `0O` | Octal | 8 |
240 | | `0x` or `0X` | Hexadecimal | 16 |
241 |
242 | Para esclarecer o funcionamento, vejamos alguns exemplos:
243 |
244 | ```python
245 | print(0b01111111) # 127
246 | print(0o10) # 8
247 | print(0XFF) # 255
248 | ```
249 |
250 | O método **bin()** converte e retorna a string binária equivalente de um determinado inteiro.
251 |
252 | ```python
253 | bin(255) # '0b11111111'
254 | ```
255 |
256 | Se quisermos convertê-lo de volta para o valor inteiro, podemos usar a função **int()**, passando a base 2 como argumento:
257 |
258 | ```python
259 | int('0b11111111',2) # 255
260 | ```
261 |
262 | O método **oct()** converte e retorna a string octal equivalente de um determinado inteiro.
263 |
264 | ```python
265 | oct(8) # '0o10'
266 | ```
267 |
268 | Se quisermos convertê-lo de volta para o valor inteiro, podemos usar a função **int()**, passando a base 8 como argumento:
269 |
270 | ```python
271 | int('0o10',8) # 8
272 | ```
273 |
274 | O método **hex()** converte e retorna a string hexadecimal equivalente de um determinado inteiro.
275 |
276 | ```python
277 | hex(255) # '0xff'
278 | ```
279 |
280 | Se quisermos convertê-lo de volta para o valor inteiro, podemos usar a função **int()**, passando a base 16 como argumento:
281 |
282 | ```python
283 | int('0xff',16) # 255
284 | ```
285 |
286 | Lembre sempre que números são elementos essenciais e fundamentais na programação e que vamos utilizar muito eles!
287 |
288 |
--------------------------------------------------------------------------------
/content/if-else.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'If... Else'
3 | description: 'Aprenda sobre Tomada de Decisão'
4 | ---
5 |
6 | A tomada de decisão é necessária quando queremos executar um código apenas se uma determinada **condição** for satisfeita.
7 |
8 | As instruções `if`, `elif` e `else` são usadas em Python para nos auxiliar na tomada de decisões.
9 |
10 | 
11 |
12 | A tomada de decisão é um conceito muito importante da programação e representa a capacidade de executarmos determinados comandos apenas se condições especificadas forem satisfeitas.
13 |
14 | Lembrando que Python é capaz de suportar as condições lógicas tradicionais da matemática:
15 |
16 | - Igualdade: `x == y`
17 | - Diferente de: `x != y`
18 | - Menor que: `x < y`
19 | - Menor que ou igual a: `x <= y`
20 | - Maior que: `x > y`
21 | - Maior que ou igual a: `x >= y`
22 |
23 | Essas condições podem ser usadas de várias maneiras, e são comumente utilizadas em instruções **if** e **loops**.
24 |
25 | A sintaxe para construirmos uma estrutura de tomada de decisão funciona então da seguinte forma:
26 |
27 | ```pyhton
28 | if :
29 |
30 | elif :
31 |
32 | else:
33 |
34 | ```
35 |
36 | Neste exemplo, o programa executa a primeira linha `if `, se a `` for avaliada como `True`, os `` dentro do bloco **if** serão executados.
37 |
38 | Caso a `` da primeira linha `if ` seja avaliada como `False`, nosso programa irá pular para a linha `elif ` e irá testar a nova ``:
39 |
40 | - Se ela for avaliada como `True` os comandos do bloco **elif** serão executados.
41 | - Se ela for avaliada como `False` os comandos do bloco **else** serão executados.
42 |
43 | ### Exemplos
44 |
45 | Vamos agora construir exemplos práticos para compreender melhor a ideia de tomada de decisão em nossos códigos.
46 |
47 | ```python
48 | num = 5
49 |
50 | if num > 0:
51 | print("O número é positivo")
52 | print("Esse valor é sempre impresso, pois está fora do bloco if")
53 | ```
54 |
55 | Nesse caso podemos perceber que a expressão dentro do bloco **if** será executa, uma vez que o valor de **num** é maior que **0**, sendo assim, **positivo**.
56 |
57 | Também podemos usar a palavra-chave **elif** para testarmos outras possibilidades, uma vez que nem sempre a primeira pode ser atendida.
58 |
59 | ```python
60 | x = 12
61 | y = 12
62 |
63 | if x > y:
64 | print("x é maior do que y")
65 | elif x == y:
66 | print("x e y são iguais")
67 | ```
68 |
69 | Nesse exemplo a primeira condição não é satisfeita, então pulamos para o **elif** e fazemos o teste, como os valores de **x** e **y** são iguais, temos nossa expressão **"x e y são iguais"** executada.
70 |
71 | Além do **if** e **elif**, temos o **else** que preencherá qualquer situação que o **if** e **elif** não sejam capazes de executar.
72 |
73 | ```python
74 | a = 100
75 | b = 20
76 |
77 | if b > a:
78 | print("b é maior do que a")
79 | elif b == a:
80 | print("b e a são iguais")
81 | else:
82 | print("a é maior do que b")
83 | ```
84 |
85 | Veja que nesse caso o primeiro **if** será avaliado como **False**, pulamos então para o **elif** que também será avaliado como **False**, nos deixando apenas com a execução do **else**.
86 |
87 | Lembrando que é possível utilizarmos o **else** sem o **elif**.
88 |
89 | ```python
90 | k = 30
91 | z = 22
92 |
93 | if z > k:
94 | print("z é maior do que k")
95 | else:
96 | print("k é maior do que z")
97 | ```
98 |
99 | Podemos também encadear multiplos **if**, **elif** e **else**.
100 |
101 | Nesse programa vamos pedir para o usuário entrar com um número, avaliaremos se ele é positivo, negativo ou zero e mostraremos ao usuário a mensagem apropriada.
102 |
103 | ```python
104 | num = int(input("Digite um número: "))
105 |
106 | if num >= 0:
107 | if num == 0:
108 | print("Zero")
109 | else:
110 | print("Número positivo")
111 | else:
112 | print("Número negativo")
113 | ```
114 |
115 | Imagine agora que temos uma string chamada de **senha** e queremos avaliar se ela foi digitada ou não, podemos neste caso usar a palavra-chave **not** que indica a negação de uma expressão, alterando assim seu estado. Por exemplo:
116 |
117 | ```python
118 | senha = ''
119 |
120 | if not senha:
121 | print('Senha inexistente!')
122 | else:
123 | print('Senha existe!')
124 | # Senha inexistente!
125 | ```
126 |
127 | Neste caso específico, o comando `print('Senha inexistente!')` será executado, uma vez que qualquer string vazia é avaliada como `False`, e nesse caso, usamos o **not** para trocar o **False** para **True**.
128 |
129 | Podemos confirmar essa ideia com o seguinte experimento:
130 |
131 | ```python
132 | print(bool('')) # False
133 | print(bool('75966231325')) # True
134 | ```
135 |
136 | Isso quer dizer que se adicionarmos uma senha, o bloco **else** será executado, pois dessa vez temos uma string preenchida, que será avalida como **True** e a palavra-chave **not** irá transformar o **True** em **False**.
137 |
138 | ```python
139 | senha = '75966231325'
140 |
141 | if not senha:
142 | print('Senha inexistente!')
143 | else:
144 | print('Senha existe!')
145 | # Senha existe!
146 | ```
147 |
148 | No caso de números, o que ocorre é que o número **0** é avaliado como `False` e quaisquer outros números são considerados `True`:
149 |
150 | ```python
151 | bool(0) # False
152 | bool(1) # True
153 | bool(-1) # True
154 | bool(3.3) # True
155 | bool(3+1j) # True
156 | ```
157 |
158 | ### Operadores Lógicos
159 |
160 | Anteriormente vimos os **operadores lógicos**, eles também podem ser utilizados em conjunto com **if** para construirmos testes mais elaborados.
161 |
162 | A palavra-chave **and** é um operador lógico e é usado para combinar declarações condicionais:
163 |
164 | ```python
165 | n1 = 15
166 | n2 = 30
167 | n3 = 15
168 |
169 | if n1 < n2 and n3 == n1:
170 | print("Ambas as condições são verdadeiras")
171 | ```
172 |
173 | Neste exemplo o comando **print()** será executado, pois ambas as condições se concretizam como `True` (n1 é **menor** que n2 e n3 é **igual** a n1).
174 |
175 | A palavra-chave **or** é um operador lógico e é usada para combinar declarações condicionais:
176 |
177 | ```python
178 |
179 |
180 | if n1 > n2 or n1 == n3:
181 | print("Pelo menos uma condição é verdadeira")
182 | ```
183 |
184 | Neste exemplo o comando **print()** será executado, mesmo a primeira expressão não sendo avaliada como `True`, a segunda é avaliada, o que é o suficiente para termos nosso comando **print()** executado.
185 |
186 | ### O Desafio FizzBuzz
187 |
188 | Imagine que temos um número **n**. Temos que exibir uma representação em string de todos os números de **1** até **n**, mas existem algumas restrições:
189 |
190 | - Se o número n for divisível por 3, imprimir "Fizz" ao invés do número.
191 | - Se o número n for divisível por 5, imprimir "Buzz" ao invés do número.
192 | - Se o número n for divisível por 3 e 5, imprimir "FizzBuzz" ao invés do número
193 |
194 | Em outras palavras, para múltiplos de três vamos imprimir "Fizz" em vez do número e para múltiplos de cinco vamos imprimir "Buzz". Para números que são múltiplos de três e cinco, imprimir "FizzBuzz".
195 |
196 | Para resolvermos este problema, precisaremos de um **for loop** e uma série de testes com **if**, **elif** e **else**. Vejamos como podemos fazer:
197 |
198 | ```python
199 | n = 35
200 |
201 | for n in range(1,n):
202 | if n % 3 is 0 and n % 5 is 0:
203 | print("FizzBuzz")
204 | elif n % 3 is 0:
205 | print("Fizz")
206 | elif n % 5 is 0:
207 | print("Buzz")
208 | else:
209 | print(n)
210 | ```
211 |
212 | Observe que estamos usando o operador de resto de divisão (`%`) e também a palavra-chave **is**, para verificarmos se o resto de divisão é igual a 0.
213 |
214 | - No primeiro bloco **if** testamos se o número é divisível por 3 e 5.
215 | - No segundo bloco **elif** testamos se o número é divisível por 3.
216 | - No terceiro bloco **elif** testamos se o número é divisível por 5.
217 | - Finalmente, se todas os testes anteriores forem `False`, iremos imprimir o próprio número **n**.
218 |
219 | É importante fixarmos bastante a parte de **tomada de decisão**, pois ela nos dará uma base sólida para construirmos nossos programas, lembre sempre de fazer experimentos.
220 |
--------------------------------------------------------------------------------
/content/tipos-variaveis.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Tipos de Variáveis'
3 | description: 'Aprenda sobre os Tipos de Variáveis em Python'
4 | ---
5 |
6 | **Variáveis** são um conceito de extrema importância nas linguagens de programação.
7 |
8 | Variáveis são usadas para armazenar informações a serem referenciadas e manipuladas em um programa de computador. Elas também fornecem uma maneira de rotular dados com um nome descritivo, para que nossos programas possam ser entendidos mais claramente pelo leitor e por nós mesmos. É útil pensar nas variáveis como contêineres que contêm informações. Seu único objetivo é rotular e armazenar dados na memória. Esses dados podem ser usados em todo o seu programa.
9 |
10 | ## Atribuindo Valores às Variáveis
11 |
12 | As variáveis em **Python** não precisam declaração explícita para reservar espaço em memória, a declaração ocorre automaticamente quando você atribui um valor à variável. O sinal de **(=)** é usado para fazer a atribuição de valores.
13 |
14 | 
15 |
16 | Por exemplo:
17 |
18 | ```python
19 | nome = 'Gabriel' # Uma string
20 | idade = 33 # Um valor inteiro
21 | altura = 1.75 # Um valor em ponto flutuante
22 |
23 | print(nome) # Gabriel
24 | print(idade) # 33
25 | print(altura) # 1.71
26 | ```
27 |
28 | Também é possível atribuir múltiplos valores para múltiplas variáveis:
29 |
30 | ```python
31 | a, b, c = 5, 3.1, "Hello"
32 |
33 | print(a) # 5
34 | print(b) # 3.1
35 | print(c) # Hello
36 | ```
37 |
38 | Um detalhe importante que não podemos esquecer é que devemos dar nomes que façam sentido as nossas variáveis, existem também notações que são usadas por programadores, por exemplo **camelCase**, onde a variável começa com uma letra em lowercase, por exemplo:
39 |
40 | ```python
41 | meuNome = "Gabriel"
42 | minhaIdade = 33
43 | meuEndereco = "Avenida Castelo"
44 | ```
45 |
46 | Letras capitalizadas podem ser usadas para declarar **constantes**, valores que não variam, exemplo:
47 |
48 | ```python
49 | PI = 3.14
50 | GRAVIDADE = 9.8
51 | ```
52 |
53 | ## Tipos de Variáveis em Python
54 |
55 | Em muitas linguagens de programação, as variáveis são [statically typed](https://en.wikipedia.org/wiki/Type_system#Static_type_checking). Isso significa que uma variável é inicialmente declarada como tendo um tipo de dados específico e qualquer valor atribuído a ela durante sua vida útil deve sempre ter esse tipo.
56 |
57 | Variáveis em Python não estão sujeitas a esta restrição. No Python, uma variável pode ser atribuída a um valor de um tipo e, posteriormente, re-atribuída a um valor de um tipo diferente:
58 |
59 | ```python
60 | v = 100
61 | print(v) # 100
62 |
63 | v = 'agora sou uma string'
64 | print(v) # agora sou uma string
65 | ```
66 |
67 | ## Referências a Objetos
68 |
69 | Python é uma linguagem [orientada a objetos](https://en.wikipedia.org/wiki/Object-oriented_programming). De fato, praticamente todos os itens de dados em um programa Python são objetos de um tipo ou classe específica.
70 |
71 | Consideramos agora o seguinte código
72 |
73 | ```python
74 | print(33)
75 | ```
76 |
77 | Ao apresentarmos o interpretador o seguinte [statement](https://en.wikipedia.org/wiki/Statement_(computer_science)) `print(33)`, ele executará as seguintes ações:
78 |
79 | - Criará um objeto inteiro
80 | - Dará a ele o valor 33
81 | - Apresentará ele no console
82 |
83 | Podemos usar a função construída **type()** para confirmarmos
84 |
85 | ```python
86 | type(33) #
87 | ```
88 |
89 | Uma variável Python é um nome simbólico que é uma referência ou ponteiro para um objeto. Uma vez que um objeto é atribuído a uma variável, você pode se referir ao objeto com esse nome. Mas os dados em si ainda estão contidos no objeto.
90 |
91 | Consideramos o seguinte exemplo:
92 |
93 | ```python
94 | x = 33
95 | ```
96 |
97 | Esta atribuição cria um **objeto integer** com o valor `33` e atribui a variável `x` para apontar para este objeto
98 |
99 | 
100 |
101 | Agora vamos considerar o seguinte statement
102 |
103 | ```python
104 | y = x
105 | ```
106 |
107 | Ao executarmos ele, Python não criará outro objeto, ele simplesmente criará um nome simbólico ou referência `y`, no qual aponta para o mesmo objeto que aponta para `x`.
108 |
109 | 
110 |
111 | Imagine agora que façamos essa alteração
112 |
113 | ```python
114 | y = 13
115 | ```
116 |
117 | Dessa vez, Python criará um novo **objeto integer** com o valor `13`, e `y` se tornará uma referência para ele.
118 |
119 | 
120 |
121 | Agora imagine que venhamos a executar o seguinte statement
122 |
123 | ```python
124 | x = 'e'
125 | ```
126 |
127 | Python criará um **objeto string** com o valor `'e'` e fará de `x` uma referência a ele.
128 |
129 | 
130 |
131 | Como podemos observar, não há mais referência ao objeto integer `33`. Quando o número de referências a um objeto cai para zero, ele não está mais acessível. Nesse ponto, sua vida acabou. O Python eventualmente perceberá que é inacessível e recuperará a memória alocada para que possa ser usada para outra coisa. Esse processo é chamado de [garbage collection](https://stackify.com/python-garbage-collection/).
132 |
133 | ## Identidade dos Objetos
134 |
135 | No Python, todo objeto criado recebe um número que o identifica exclusivamente. É garantido que dois objetos não terão o mesmo identificador durante qualquer período em que sua vida útil se sobreponha.
136 |
137 | A função construída **id()** retorna o identificador inteiro de um objeto. Utilizando a função **id()** podemos verificar se duas variáveis realmente apontam para o mesmo objeto:
138 |
139 | ```python
140 | k = 100
141 | t = k
142 | id(k) # 94320283578208
143 | id(t) # 94320283578208
144 | ```
145 |
146 | Perceba que ambas possuem o mesmo número identificador, uma vez que elas apontam para o mesmo objeto. Caso façamos uma alteração em `t`, ele passará a apontar para outro objeto, ganhando assim um **id** diferente.
147 |
148 | ```python
149 | t = 50
150 | id(t) # 94320283576608
151 | ```
152 |
153 | ## Deletando uma Variável
154 |
155 | O comando **del** nos permite deletar variáveis.
156 |
157 | No exemplo abaixo, declaramos uma variável chamada de **numero** e atribuímos um valor ponto flutuante a ela, em seguida, utilizamos o comando **del** para deletá-la.
158 |
159 | ```python
160 | numero = 12.5
161 | del numero
162 | ```
163 |
164 | Se eventualmente tentarmos imprimí-la no console com o comando `print()` nos será retornado um erro: `NameError: name 'numero' is not defined`, nos indicando que ela não está mais definida.
165 |
166 | ## Nomes de Variáveis
167 |
168 | Uma variável pode ter um nome curto (como por exemplo **x** ou **y**) e ou nome mais descritivo (**nome**, **idade**, **resultado**).
169 |
170 | Veja as regras para as variáveis
171 |
172 | - Uma variável deve iniciar com uma letra ou um caracter *underscore* (**_**)
173 | - Uma variável não pode começar com um número
174 | - O nome de uma variável pode conter apenas caracteres alpha-numéricos e *underscores* (A-z, 0-9, e _)
175 | - Nomes de variáveis são *case sensitive* (idade, Idade e IDADE são três variáveis diferentes)
176 |
177 | ## Variáveis Globais
178 |
179 | Em Python, uma variável declarada fora da função ou no escopo global é conhecida como variável global. Isso significa que uma variável global pode ser acessada dentro ou fora da função.
180 |
181 | Vejamos um exemplo de como uma variável global é criada em Python:
182 |
183 | ```python
184 | x = 'global'
185 |
186 | def imprimir():
187 | print(f'{x} na função imprimir()')
188 |
189 | imprimir()
190 | print(f'{x} fora da função')
191 | ```
192 |
193 | No código acima, criamos **x** como uma variável global e definimos `imprimir()` para imprimir a variável global x. Finalmente, chamamos o `imprimir()` que imprimirá o valor de x, além disso, usamos o comando `print()` que também irá imprimir x.
194 |
195 | E se desejarmos alterar o valor de x dentro de uma função?
196 |
197 | ```python
198 | x = 3
199 |
200 | def add():
201 | x = x + 5
202 | print(x)
203 |
204 | add()
205 | ```
206 |
207 | Nos será retornado o seguinte erro:
208 |
209 | ```
210 | UnboundLocalError: local variable 'x' referenced before assignment
211 | ```
212 |
213 | O *output* apresenta um erro porque o Python trata **x** como uma variável local e **x** também não está definido dentro da função `add()`.
214 |
215 | Para solucionar este problema, podemos criar uma variável global dentro de uma função, para isso usamos a palavra-chave **global**:
216 |
217 | ```python
218 | x = 3
219 |
220 | def add():
221 | global x
222 | x = x + 5
223 | print(x)
224 |
225 | add() # 8
226 | ```
227 |
228 | Observe que dessa vez a função tem acesso à variável x, tornando assim possível adicionarmos o número 5.
229 |
230 | Agora que você já consegue armazenar valores em variáveis, vamos ver os tipos de dados que existem em **Python** e suas aplicações!
231 |
--------------------------------------------------------------------------------
/content/tuplas.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Tuplas'
3 | description: 'Aprenda sobre as Tuplas em Python'
4 | ---
5 |
6 | Tuplas são uma sequência de **objetos imutáveis**, em outras palavras, uma vez criadas, tuplas não podem ser modificadas, normalmente são usadas para guardar **dados protegidos**.
7 |
8 | As tuplas são escritas entre parênteses **()**.
9 |
10 | Uma tupla em Python é semelhante a uma lista. A diferença entre os dois é que não podemos alterar os elementos de uma tupla depois de atribuída, enquanto podemos alterar os elementos de uma lista.
11 |
12 | ### Criando uma Tupla
13 |
14 | Podemos definir uma tupla da seguinte maneira:
15 |
16 | ```python
17 | linguagens = ("Python","Ruby","Javascript","Perl","Haskell")
18 | print(linguagens) # ('Python', 'Ruby', 'Javascript', 'Perl', 'Haskell')
19 | ```
20 |
21 | Com o método **type()** podemos confirmar que se trata de uma **'tuple'**:
22 |
23 | ```python
24 | type(linguagens) #
25 | ```
26 |
27 | ### Acessando Itens de uma Tupla
28 |
29 | O acesso aos itens de uma tupla é idêntico ao de uma lista:
30 |
31 | ```python
32 | print(linguagens[0:2]) # ('Python', 'Ruby')
33 | print(linguagens[-1]) # Haskell
34 | print(linguagens[:-2]) # ('Python', 'Ruby', 'Javascript')
35 | print(linguagens[:]) # ('Python', 'Ruby', 'Javascript', 'Perl', 'Haskell')
36 | ```
37 |
38 | ### Atualizando Tuplas
39 |
40 | Lembrando que as tuplas são imutáveis, portanto se tentarmos modificá-la, nos será retornado um erro do tipo **TypeError**:
41 |
42 | ```python
43 | linguagens[0] = "C++"
44 | # TypeError: 'tuple' object does not support item assignment
45 | ```
46 |
47 | Como já mencionado, Tuplas são imutáveis, ou seja, não podemos alterar os seus elementos, porém podemos capturar porções de uma tupla e criar novas tuplas, por exemplo:
48 |
49 | ```python
50 | x = (1,2)
51 | y = (3,4)
52 |
53 | z = x + y
54 | print(z) # (1, 2, 3, 4)
55 | ```
56 |
57 | ### Imprimindo Elementos de uma Tupla
58 |
59 | As tuplas são úteis para representar o que outras linguagens costumam chamar de registros, algumas informações relacionadas que pertencem entre si, como o registro de um **estudante**. Não há descrição do que significa cada um desses campos, mas podemos intuir. Uma tupla nos permite “agrupar” informações relacionadas e usá-las em uma única estrutura.
60 |
61 | ```python
62 | estudante = ('Miguel', 29, 1990, 'Brasil')
63 | ```
64 |
65 | Agora podemos utilizar um **for loop** para imprimir todos os elementos da tupla **estudante**:
66 |
67 | ```python
68 | for e in estudante: # Percorre os valores da tupla estudante
69 | print(e) # Imprime os valores
70 | ```
71 |
72 | Também podemos facilmente converter esta tupla em uma lista usando a técnica list comprehension:
73 |
74 | ```python
75 | print([e for e in estudante]) # ['Miguel', 29, 1990, 'Brasil']
76 | ```
77 |
78 | ### Checando por Valores em uma Tupla
79 |
80 | Assim como nas listas, também podemos checar se determinado item está presente em uma tupla:
81 |
82 | ```python
83 | print('Gabriel' in estudante) # False
84 | ```
85 |
86 | ```python
87 | print(1990 in estudante) # True
88 | ```
89 |
90 | Além disso, podemos checar também a absência de determinado elemento:
91 |
92 | ```python
93 | print('Japão' not in estudante) # True
94 | ```
95 |
96 | ```python
97 | print('Brasil' not in estudante) # False
98 | ```
99 |
100 | ### Verificando o Tamanho de uma Tupla
101 |
102 | Para obtermos o número de itens em uma tupla, podemos usar o método **len()**:
103 |
104 | ```python
105 | print(len(estudante)) # 4
106 | ```
107 |
108 | ### Deletando a Tupla
109 |
110 | Embora seja impossível remover itens da tupla, é possível deletá-la por completo com o uso da palavra-chave **del**. Observe que se tentarmos imprimir ela, ocorrerá um erro do tipo **NameError**, uma vez que a tupla não existe mais.
111 |
112 | ```python
113 | del estudante
114 | print(estudante)
115 | # NameError: name 'estudante' is not defined
116 | ```
117 |
118 | ### Construtor tuple()
119 |
120 | Somos capazes também de construir uma tupla com o uso do construtor **tuple()**:
121 |
122 | ```python
123 | numeros = tuple(x for x in range(1,20,3))
124 | print(numeros) # (1, 4, 7, 10, 13, 16, 19)
125 | ```
126 |
127 | ### Método count()
128 |
129 | O método **count()** nos retorna a quantidade de vezes que determinado valor ocorre em uma tupla
130 |
131 | ```python
132 | print(numeros.count(7)) # 1
133 | ```
134 |
135 | ### Método index()
136 |
137 | O método **index()** nos permite buscar por um determinado elemento e nos retorna o índice dele:
138 |
139 | ```python
140 | numeros.index(4) # 1
141 | ```
142 |
143 | ### Criando uma Função que Retorna uma Tupla
144 |
145 | Funções normalmente retornam apenas um **único valor**, porém ao tornarmos esse valor uma **Tupla**, nós podemos efetivamente agrupar a quantidade de valores que desejarmos e retorná-los juntos. Esta funcionalidade pode nos ser muito útil em casos que queiramos por exemplo encontrar a **média** e o **desvio padrão** ou talvez obter o ano, mês e dia.
146 |
147 | Vejamos um exemplo para ilustrar esta ideia, em que vamos definir uma função de nome **f** que irá calcular a **circunferência** e a **área** de um círculo de raio **r** (o raio será informado via argumento por nós):
148 |
149 | ```python
150 | import math
151 |
152 | def f(r):
153 | """ Retorna (circunferência, área) de um círculo de raio r """
154 | c = 2 * math.pi * r
155 | a = math.pi * r * r
156 | return (c, a)
157 |
158 | print(f(5)) # (31.41592653589793, 78.53981633974483)
159 | print(f(8)) # (50.26548245743669, 201.06192982974676)
160 | ```
161 |
162 | ### Named Tuples
163 |
164 | **Named Tuples** são objetos de fácil criação e leves. Instâncias de Named Tuples podem ser referenciadas utilizando variáveis. Elas podem serem utilizadas como uma espécie de estrutura para agruparmos dados.
165 |
166 | É muito comum representarmos um ponto como uma tupla (x, y).
167 |
168 | A fórmula da distância é uma expressão algébrica usada para determinar a distância entre dois pontos com as coordenadas (x1, y1) e (x2, y2).
169 |
170 | 
171 |
172 | ```python
173 | from math import sqrt
174 |
175 | p1 = (2.0, 7.0)
176 | p2 = (2.5, 3.5)
177 |
178 | comprimento_linha = sqrt((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2)
179 | print(comprimento_linha) # 3.5355339059327378
180 | ```
181 |
182 | Ao utilizarmos uma Named Tuple, nosso código se torna mais legível, porém para usá-la devemos importá-la da biblioteca [collections](https://docs.python.org/3/library/collections.html):
183 |
184 | ```python
185 | from collections import namedtuple
186 |
187 | Ponto = namedtuple('Point', 'x y')
188 | p1 = Ponto(1.5, 5.0)
189 | p2 = Ponto(4.5, 1.5)
190 |
191 | comprimento_linha = sqrt((p1.x-p2.x)**2 + (p1.y-p2.y)**2)
192 | print(comprimento_linha) # 4.6097722286464435
193 | ```
194 |
195 | Podemos usar as Named Tuples para armazenar cores **RGB**:
196 |
197 | ```python
198 | Cor = namedtuple('Cor', ['red', 'green', 'blue'])
199 |
200 | cor = Cor(55,155,255)
201 |
202 | print(cor) # Cor(red=55, green=155, blue=255)
203 | print(cor.red) # 55
204 | ```
205 |
206 | ### Tuplas vs Listas
207 |
208 | Por que devemos usar uma Tupla ao invés de uma Lista?
209 |
210 | - A execução do programa é mais rápida quando manipulamos uma tupla do que uma equivalente lista.
211 | - As vezes desejamos que os dados não sejam modificados, se determinados que valores em uma coleção devem ser constantes no programa, utilizar uma Tupla nos protege contra acidentes de modificação.
212 |
213 | #### Exemplos
214 |
215 | Exemplo de Lista:
216 |
217 | ```python
218 | numeros_primos = [2, 3, 5, 7, 11, 13, 17]
219 | ```
220 |
221 | Mostrando o tamanho:
222 |
223 | ```python
224 | print(f'# Primos: {len(numeros_primos)}')
225 | ```
226 |
227 | Iterando sob a sequência:
228 |
229 | ```python
230 | for p in numeros_primos:
231 | print(f'Primos: {p}')
232 | ```
233 |
234 | Exemplo de Tupla:
235 |
236 | ```python
237 | quadrados_perfeitos = (1, 4, 9, 16, 25, 36)
238 | ```
239 |
240 | Mostrando o tamanho:
241 |
242 | ```python
243 | print(f'# Quadrados Perfeitos: {len(quadrados_perfeitos)}')
244 | ```
245 |
246 | Iterando sob a sequência:
247 |
248 | ```python
249 | for n in quadrados_perfeitos:
250 | print(f'Primos: {n}')
251 | ```
252 |
253 | #### Métodos das Listas e Tuplas
254 |
255 | Podemos usar o método **dir()** para visualizarmos todos os atributos e métodos disponíveis nas listas e tuplas:
256 |
257 | ```python
258 | print('Métodos Lista')
259 | print(dir(numeros_primos))
260 | print('Métodos Tupla')
261 | print(dir(quadrados_perfeitos))
262 | ```
263 |
264 | #### Obtendo o Tamanho em Bytes
265 |
266 | O método **getsizeof()** da biblioteca [sys](https://docs.python.org/3/library/sys.html) nos permite obter o tamanho que um objeto ocupa em bytes. Por exemplo:
267 |
268 | ```python
269 | import sys
270 |
271 | lista_ex = [1, 2, 3, 'x', 'y', 'z', True, 3.14159]
272 | tupla_ex = (1, 2, 3, 'x', 'y', 'z', True, 3.14159)
273 |
274 | print(f'Tamanho da lista = {sys.getsizeof(lista_ex)}') # Tamanho da lista = 136
275 | print(f'Tamanho da tupla = {sys.getsizeof(tupla_ex)}') # Tamanho da tupla = 120
276 | ```
277 |
278 | Como podemos observar, a tupla ocupa menos espaço em memória que uma lista.
279 |
280 | #### Comparando o Tempo
281 |
282 | A biblioteca [timeit](https://docs.python.org/3/library/timeit.html) nos fornece uma maneira simples de cronometrar pequenos trechos de código Python, podemos usá-la para medir a eficiência de estruturas de dados como listas e tuplas:
283 |
284 | ```python
285 | import timeit
286 |
287 | lista_teste = timeit.timeit(stmt='[1,2,3,4,5]', number=1_000_000)
288 | tupla_teste = timeit.timeit(stmt='(1,2,3,4,5)', number=1_000_000)
289 |
290 | print(f'Tempo da lista: {lista_teste}') # Tempo da lista: 0.11356729100225493
291 | print(f'Tempo da tupla: {tupla_teste}') # Tempo da tupla: 0.058329956023953855
292 | ```
293 |
294 | Como podemos ver, as **tuplas** são uma estrutura de dados **imutável** e muito **rápida** que pode nos auxiliar bastante em nossos cálculos.
295 |
--------------------------------------------------------------------------------
/content/dicionarios.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Dicionários'
3 | description: 'Aprenda sobre Dicionários'
4 | ---
5 |
6 | 
7 |
8 | Os **dicionários** são encontrados em outros linguagens de programação como "memórias associativas" ou "matrizes associativas". Ao contrário das seqüências, que são indexadas por um intervalo de números, os dicionários são indexados por **chaves**, que podem ser de qualquer tipo imutável.
9 |
10 | Eles são uma coleção **não-ordenada** de pares de **chave** & **valor**, são normalmente usados quando temos uma grande quantidade de dados.
11 |
12 | Dicionários são otimizados para buscarmos dados e para isso, precisamos saber sua **chave**.
13 |
14 | Dicionários são definidos entre chaves `{}` onde cada item é um par na forma de **chave:valor**, separados por `,`, sendo a chave e o valor podendo ser de qualquer tipo.
15 |
16 | **Chaves**:
17 |
18 | - Devem ser **únicas**
19 | - Tipo **imutável** (int, float, string, tuple, bool)
20 | - Na verdade precisa de um objeto que seja *hashable*, mas imagine como imutável uma vez que todos os tipos imutáveis são *hashable*
21 | - Tenha cuidado com o tipo *float* como chave
22 | - Nenhuma ordem para chaves ou valores
23 |
24 | **Valores**:
25 |
26 | - Qualquer tipo (**imutável** e **mutável**)
27 | - Pode ser **duplicado**
28 | - Valores de dicionários podem ser listas, até mesmo outros dicionários
29 |
30 | Para compreendermos melhor o funcionamento dos dicionários, vamos definir alguns exemplos:
31 |
32 | ```python
33 | album = {'nome':'A Night at the Opera','artista':'Blind Guardian','lançamento':2002}
34 | print(type(album)) #
35 | print(album) # {'nome': 'A Night at the Opera', 'artista': 'Blind Guardian', 'lançamento': 2002}
36 | print(album['nome']) # A Night at the Opera
37 | print(album['artista']) # Blind Guardian
38 | print(album['lançamento']) # 2002
39 | ```
40 |
41 | Também podemos definir um dicionário dessa forma, o que torna ele mais legível:
42 |
43 | ```python
44 | elemento = {
45 | "nome":"Ouro",
46 | "símbolo":"Au",
47 | "número atômico":79
48 | }
49 | ```
50 |
51 | ### Acessando e Manipulando Dados
52 |
53 | Para acessarmos os itens do dicionário, precisamos nos referir a sua chave, por exemplo:
54 |
55 | ```python
56 | print(elemento["nome"]) # Ouro
57 | ```
58 |
59 | Podemos também utilizar o método **get()** para acessarmos:
60 |
61 | ```python
62 | print(elemento.get("nome")) # Ouro
63 | ```
64 |
65 | É possível alterar os valores de um dicionário, podemos fazê-lo da seguinte maneira:
66 |
67 | ```python
68 | elemento["nome"] = "Prata"
69 | elemento["símbolo"] = "Ag"
70 | elemento["número atômico"] = 47
71 | print(elemento) # {'nome': 'Prata', 'símbolo': 'Ag', 'número atômico': 47}
72 | ```
73 |
74 | ### Imprimindo os Valores de um Dicionário
75 |
76 | Podemos usar o **for loop** para imprimir os elementos de um dicionário.
77 |
78 | ```python
79 | personagem = {
80 | "nome" : "Gandalf",
81 | "classe" : "Wizard",
82 | "ordem" : "Istari"
83 | }
84 |
85 | for key in personagem: # Percorre os valores do dicionário
86 | print(personagem[key]) # Imprime os valores do dicionário
87 | ```
88 |
89 | Também podemos usar o método **values()** da seguinte forma:
90 |
91 | ```python
92 | for p in personagem.values(): # Percorre os valores do dicionário
93 | print(p) # Imprime os valores do dicionário
94 | ```
95 |
96 | Além disso é possível percorrer tanto as **chaves** como os **valores**, usando a função **items()**:
97 |
98 | ```python
99 | for chave,valor in personagem.items(): # Percorre as chaves e os valores
100 | print(f'{chave} : {valor}') # Imprime as chaves e os valores
101 | ```
102 |
103 | Caso seja necessário verificar a presença de uma **chave** no dicionário, podemos fazer o teste com a palavra-chave **in**:
104 |
105 | ```python
106 | print('nome' in personagem) # True
107 | ```
108 |
109 | Também podemos testar pela presença de um determinado **valor** no dicionário:
110 |
111 | ```python
112 | print("Gandalf" in personagem.values()) # True
113 | ```
114 |
115 | Assim como nas listas e tuplas, também podemos aplicar o método **len()** nos dicionários:
116 |
117 | ```python
118 | print(len(personagem)) # 3
119 | ```
120 |
121 | ### Adicionando Itens ao Dicionário
122 |
123 | Para adicionarmos um novo item em nosso dicionário usamos uma nova chave e atribuimos um valor a ela
124 |
125 | ```python
126 | personagem['altura'] = 1.85
127 | print(personagem) # {'nome': 'Gandalf', 'classe': 'Wizard', 'Ordem': 'Istari', 'altura': 1.85}
128 | ```
129 |
130 | ### Removendo Itens do Dicionário
131 |
132 | É possível também, de várias formas, remover os itens de um dicionário.
133 |
134 | Usando o método **pop()**, nos será retornado o item removido:
135 |
136 | ```python
137 | personagem.pop('altura') # 1.85
138 | print(personagem) # {'nome': 'Gandalf', 'classe': 'Wizard', 'Ordem': 'Istari'}
139 | ```
140 |
141 | Usando o método **popitem()**, remove o último par de **chave**-**valores** adicionado de **personagem** e o retorna como uma tupla:
142 |
143 | ```python
144 | personagem.popitem() # ('Ordem', 'Istari')
145 | print(personagem) # {'nome': 'Gandalf', 'classe': 'Wizard'}
146 | ```
147 |
148 | A palavra-chave **del** remove um item com a chave especificada:
149 |
150 | ```python
151 | del personagem['classe']
152 | print(personagem) # {'nome': 'Gandalf'}
153 | ```
154 |
155 | Além disso é possível deletar o dicionário por completo com **del**, tenha muita atenção, pois todos os dados serão perdidos.
156 |
157 | ```python
158 | del personagem
159 | print(personagem) # NameError: name 'personagem' is not defined
160 | ```
161 |
162 | ### Construtor dict()
163 |
164 | Através do construtor **dict()** também é possível criarmos dicionários:
165 |
166 | ```python
167 | pessoa = dict(nome="Jesus", idade=33)
168 | print(pessoa) # {'nome': 'Jesus', 'idade': 33}
169 | ```
170 |
171 | Uma outra maneira de atualizarmos os dados de um dicionário é com o uso do método **update()**:
172 |
173 | ```python
174 | pessoa.update({'nome':'Immanuel'})
175 | print(pessoa) # {'nome': 'Immanuel', 'idade': 33}
176 | ```
177 |
178 | ### Método clear()
179 |
180 | O método **clear()** nos permite esvaziar o dicionário por completo:
181 |
182 | ```python
183 | pessoa.clear()
184 | print(pessoa) # {}
185 | ```
186 |
187 | ### Ordenando um Dicionário
188 |
189 | Vamos agora criar um dicionário chamado de **pokedex**, este será um pequeno registro de alguns pokémons, que iremos **ordernar** através de **[expressões lambda](https://python-reference.readthedocs.io/en/latest/docs/operators/lambda.html)**.
190 |
191 | Criando o Dicionário:
192 |
193 | ```python
194 | pokedex = [
195 | {'nome':'pikachu','tipo':'elétrico'},
196 | {'nome':'charizard','tipo':'fogo'},
197 | {'nome':'bulbasaur','tipo':'planta'},
198 | {'nome':'squirtle','tipo':'aquatico'}
199 | ]
200 | ```
201 |
202 | Ordenando os pokémons por **tipo** através de uma expressão lambda:
203 |
204 | ```python
205 | ordenados = sorted(pokedex, key=lambda x: x['tipo'])
206 | print(ordenados)
207 | # [{'nome': 'squirtle', 'tipo': 'aquatico'}, {'nome': 'pikachu', 'tipo': 'elétrico'}, {'nome': 'charizard', 'tipo': 'fogo'}, {'nome': 'bulbasaur', 'tipo': 'planta'}]
208 | ```
209 |
210 | ### Dicionários Comprehensions
211 |
212 | Supondo que tenhamos por exemplo duas listas e desejamos montar um dicionário através delas, podemos usar a técnica de **[comprehensions](https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions)** para executar tal tarefa.
213 |
214 | Para este exemplo, vamos primeiro iniciar duas listas e com elas, construíremos um dicionário:
215 |
216 | ```python
217 | autores = ['Aldous Huxley','George Orwell','Ray Bradbury','William Gibson']
218 | livros = ['Brave New World','1984','Fahrenheit 451','Neuromancer']
219 |
220 | autores_livros = {autor: livro for autor, livro in zip(autores, livros)}
221 | print(autores_livros)
222 | # {'Aldous Huxley': 'Brave New World', 'George Orwell': '1984', 'Ray Bradbury': 'Fahrenheit 451', 'William Gibson': 'Neuromancer'}
223 | ```
224 |
225 | Um *dictionary comprehension* também pode conter o statement **if**, que pode ser usado para filtrarmos itens.
226 |
227 | Vejamos como podemos formar um dicionário apenas com números pares e seus respectivos quadrados:
228 |
229 | ```python
230 | quadrados_pares = {x: x*x for x in range(11) if x % 2 == 0}
231 | print(quadrados_pares) # {0: 0, 2: 4, 4: 16, 6: 36, 8: 64, 10: 100}
232 | ```
233 |
234 | ### Dicionários Aninhados
235 |
236 | Os dicionários são uma estrutura de dados muito flexível e nos permitem até mesmo guardar **dicionários dentro de um dicionário**, de forma que possamos acessá-los através de uma **chave**. Vejamos um exemplo para ilustrar:
237 |
238 | ```python
239 | jogos = {
240 | '1':{'nome':'castlevania','genero':'aventura'},
241 | '2':{'nome':'super mario','genero':'aventura'},
242 | '3':{'nome':'world of warcraft','genero':'MMORPG'}
243 | }
244 |
245 | print(jogos['2']) # {'nome': 'super mario', 'genero': 'aventura'}
246 | print(jogos.get('1')) # {'nome': 'castlevania', 'genero': 'aventura'}
247 | print(jogos['3']['nome']) # world of warcraft
248 | ```
249 |
250 | ### Copiando um Dicionário
251 |
252 | Você não pode copiar um dicionário simplesmente digitando `copia_filme = filme`, porque: **copia_filme** será apenas uma referência para **filme**, e as alterações feitas em **filme** também serão feitas automaticamente em **copia_filme**.
253 |
254 | Uma maneira de copiarmos um dicionário é usando o método interno **copy()**:
255 |
256 | ```python
257 | filme = {'titulo':'Lord of the Rings','Gênero':'Aventura'}
258 | print(filme) # {'titulo': 'Lord of the Rings', 'Gênero': 'Aventura'}
259 | copia_filme = filme.copy()
260 | print(copia_filme) # {'titulo': 'Lord of the Rings', 'Gênero': 'Aventura'}
261 | ```
262 |
263 | Se eventualmente alterarmos o dicionário **filme**, a cópia não será afetada:
264 |
265 | ```python
266 | filme['Gênero'] = 'Fantasia'
267 | print(filme) # {'titulo': 'Lord of the Rings', 'Gênero': 'Fantasia'}
268 | print(copia_filme) # {'titulo': 'Lord of the Rings', 'Gênero': 'Aventura'}
269 | ```
270 |
271 | Uma outra opção para copiarmos um dicionário é com o uso do método **dict()**, ao qual já vimos anteriormente.
272 |
273 | ```python
274 | copia_filme = dict(filme)
275 | print(copia_filme) # {'titulo': 'Lord of the Rings', 'Gênero': 'Fantasia'}
276 | filme['titulo'] = 'The Hobbit: An Unexpected Journey'
277 | print(filme) # {'titulo': 'The Hobbit: An Unexpected Journey', 'Gênero': 'Fantasia'}
278 | print(copia_filme) # {'titulo': 'Lord of the Rings', 'Gênero': 'Fantasia'}
279 | ```
280 |
281 | ### Fibonacci com Dicionários
282 |
283 | Podemos utilizar o poder dos dicionários para otimizar uma função Fibonnaci e tornar seus resultados mais rápidos ao guardarmos os valores já computados em um **dicionário**. Esta técnica é conhecida como [Memoization](https://en.wikipedia.org/wiki/Memoization).
284 |
285 | ```python
286 | def fib_eficiente(n, d):
287 | if n in d:
288 | return d[n]
289 | else:
290 | resposta = fib_eficiente(n-1, d) + fib_eficiente(n-2, d)
291 | d[n] = resposta
292 | return resposta
293 |
294 | d = {1:1, 2:2}
295 | print(fib_eficiente(8, d)) # 34
296 | ```
297 |
298 | Podemos concluir que os dicionários são uma estrutura de dados que nos oferece uma maneira eficaz de **guardar** e **buscar** os dados, considere a importância deles para usos no futuro.
299 |
--------------------------------------------------------------------------------
/content/operadores.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Operadores'
3 | description: 'Introdução aos operadores do Python'
4 | ---
5 |
6 | **Operadores** são **símbolos especiais** capazes de executar computação **aritmética** ou **lógica**.
7 |
8 | Os operadores são usados para realizar operações em variáveis e valores.
9 |
10 | Existem diversos tipos de operadores em **Python**:
11 |
12 | - Operadores Aritméticos
13 | - Operadores de Atribuição
14 | - Operadores de Comparação
15 | - Operadores Lógicos
16 | - Operadores de Identidade
17 | - Operadores de Membros
18 | - Operadores Bitwise
19 |
20 | Vejamos então como eles funcionam em mais detalhes.
21 |
22 | ## Operadores Aritméticos
23 |
24 | Operadores aritméticos são usados com valores numéricos para realizar operações matemáticas comuns:
25 |
26 | | Operador | Descrição | Exemplo |
27 | |----------|----------------------------------------------------------------------------|---------|
28 | | + | Adiciona dois operandos | 2+5 |
29 | | - | Subtrai o operando da direita pelo da esquerda | 7-2 |
30 | | * | Multiplica dois operandos | 3*3 |
31 | | / | Divide o operando da esquerda pelo da direita | 3/2 |
32 | | % | Módulo, resto da divisão do operando da esquerda pelo da direita | 10%3 |
33 | | // | Divisão arredondada, esta divisão retorna um número inteiro | 3//2 |
34 | | ** | Expoente, operando a esquerda elevado à potência do operando a direita | 2**32 |
35 |
36 | Por exemplo:
37 |
38 | ```python
39 | x = 10
40 | y = 6
41 | z = 6.0
42 |
43 | print("x + y = ", x+y) # Nos resulta 16
44 | print("x - y = ", x-y) # Nos resulta 4
45 | print("x * y = ", x*y) # Nos resulta 60
46 | print("x / y = ", x/y) # Nos resulta 1.6666666666666667
47 | print("x / z = ", x/z) # Nos resulta 1.6666666666666667
48 | print("x // y = ", x//y) # Nos resulta 1
49 | print("x ** y = ", x**y) # Nos resulta 1000000
50 | ```
51 |
52 | Observe que definimos a variável **z** com o valor **6.0**, um número ponto flutuante, de forma que Python possa nos trazer um resultado ponto flutuante no momento de fazermos a divisão do valor de **x** por **z**.
53 |
54 | ## Operadores de Atribuição
55 |
56 | Operadores de atribuição são usados para atribuir valores a variáveis:
57 |
58 | | Operador | Exemplo 1 | Exemplo 2 |
59 | |----------|-----------|------------|
60 | | = | x = 3 | x = 3 |
61 | | += | x += 3 | x = x + 3 |
62 | | -= | x -= 3 | x = x - 3 |
63 | | *= | x *= 3 | x = x * 3 |
64 | | /= | x /= 3 | x = x / 3 |
65 | | %= | x %= 3 | x = x % 3 |
66 | | //= | x //= 3 | x = x // 3 |
67 | | **= | x **= 3 | x = x ** 3 |
68 | | &= | x &= 3 | x = x & 3 |
69 | | \|= | x \|= 3 | x = x \| 3 |
70 | | ^= | x ^= 3 | x = x ^ 3 |
71 | | >>= | x >>= 3 | x = x >> 3 |
72 | | <<= | x <<= 3 | x = x << 3 |
73 |
74 | Vejamos um simples exemplo:
75 |
76 | ```python
77 | a = 1
78 | a += 3
79 |
80 | print(a) # 4
81 | ```
82 |
83 | ## Operadores de Comparação
84 |
85 | Operadores de comparação são usados para comparar valores. Retornarão **True** ou **False** de acordo com a condição.
86 |
87 | | Operador | Descrição | Exemplo |
88 | |----------|--------------------------------------------------------------------------------------|---------|
89 | | > | Maior que - True se o operando a esquerda for maior que o da direita | x > y |
90 | | < | Menor que - True se o operando a esquerda for menor que o da direita | x < y |
91 | | == | Igual - True se ambos os operandos forem iguais | x == y |
92 | | != | Não Igual - True se os operandos forem diferentes | x != y |
93 | | >= | Maior que ou Igual - True se o operando da esquerda for maior ou igual ao da direita | x >= y |
94 | | <= | Menor que ou Igual - True se o operando da esquerda for menor ou igual ao da direita | x <= y |
95 |
96 | Vejamos alguns exemplos de comparações:
97 |
98 | ```python
99 | x = 12
100 | y = 3
101 |
102 | print(x>y) # True
103 | print(x=y) # True
107 | print(x<=y) # False
108 | ```
109 |
110 | ## Operadores Lógicos
111 |
112 | Operadores Lógicos são usados para combinar **comandos condicionais**.
113 |
114 | | Operador | Descrição | Exemplo |
115 | |----------|-------------------------------------------------------------------------|------------------|
116 | | and | Retorna True se ambos os comandos são verdadeiros | x < y and x < 10 |
117 | | or | Retorna True se um dos comandos é verdadeiro | x < y or x > 3 |
118 | | not | Reverte o resultado, retorna False se o resultado for True e vice-versa | not(x > 10) |
119 |
120 | Vamos considerar então alguns exemplos com operadores lógicos:
121 |
122 | ```python
123 | n1, n2, n3 = 3, 6, 7
124 |
125 | print(n1 < n2 and n1 < n3) # True
126 | print(n1 == n2 or n3 == n2) # False
127 | print(not True) # False
128 | ```
129 |
130 | ## Operadores de Identidade
131 |
132 | Operadores de identidade são usados para comparar os objetos, não se são iguais, mas se eles forem realmente o mesmo objeto, com o mesmo local de memória.
133 |
134 | **is** e **is not** são operadores de identidade em **Python**, eles são usados para checar se dois valores (ou variáveis) estão localizados na mesma área de memória, *duas variáveis iguais não significam que são idênticas!*
135 |
136 | | Operador | Descrição |
137 | |----------|----------------------------------------------------------------------|
138 | | is | True se os operandos são idênticos (referem ao mesmo objeto) |
139 | | is not | True se os operandos não são idênticos (não referem ao mesmo objeto) |
140 |
141 | Exemplo com números:
142 |
143 | ```python
144 | x = 1
145 | y = 1
146 |
147 | print(x is y) # True
148 | print(x is not y) # False
149 | ```
150 |
151 | Exemplo com strings:
152 |
153 | ```python
154 | a = "cachorro"
155 | b = "cachorro"
156 |
157 | print(a is b) # True
158 | print(a is not b) # False
159 | ```
160 |
161 | Exemplo com listas:
162 |
163 | ```python
164 | z = [1,2,3]
165 | k = [1,2,3]
166 |
167 | print(z is k) # False
168 | print(z is not k) # True
169 | ```
170 |
171 | Perceba aqui que **x** e **y** são inteiros do mesmo valor, então eles são iguais e idênticos, o mesmo vale
172 | para **a** e **b** (strings). Porém o mesmo não ocorre com **z** e **k**, que são iguais, porem não idênticos, isso porque o interpretador localiza eles separadamente em memória, mesmo eles sendo iguais.
173 |
174 | ## Operadores de Membros
175 |
176 | Operadores de membros são usados para testar se uma sequência é apresentada em um objeto.
177 |
178 | | Operador | Descrição | Exemplo |
179 | |----------|-----------------------------------------------------------------|-------------------|
180 | | in | Retorna True se o valor/variável é encontrado na sequência | "c" in "cachorro" |
181 | | not in | Retorna True se o valor/variável não está presenta na sequência | 1 not in [1,2,3] |
182 |
183 | Exemplo básico:
184 |
185 | ```python
186 | a = [1,2,3]
187 | b = "Guilherme"
188 |
189 | print(1 in a) # Retorna True, pois 1 se encontra na lista a
190 | print("o" in b) # Retorna False, pois o não se encontra na string b
191 | ```
192 |
193 | ## Operadores Bitwise
194 |
195 | Os operadores Bitwise atuam nos operandos como se eles fossem strings ou dígitos binários, eles executam operações **bit** por **bit**, por isso levam o nome **Bitwise**.
196 |
197 | Considere o valor 2 que é representado por **10** em binário e 7 que é representado por **111**.
198 |
199 | Vamos utilizar a função **bin()** que nos retorna uma string binária:
200 |
201 | ```python
202 | x = 10
203 | y = 4
204 |
205 | print(bin(x)) # 0b1010
206 | print(bin(y)) # 0b100
207 | ```
208 |
209 | Adaptando-os, temos **(x = 0000 1010)** em binário e **(y = 0000 0100)** em binário, vamos aos operadores:
210 |
211 | | Operador | Descrição | Exemplo |
212 | |----------|---------------------|-------------------------|
213 | | & | Bitwise AND | x & y = 0 (0000 0000) |
214 | | \| | Bitwise OR | x \| y = 14 (0000 1110) |
215 | | ~ | Bitwise NOT | ~x = -11 (1111 0101) |
216 | | ^ | Bitwise XOR | x ^ y = 14 (0000 1110) |
217 | | >> | Bitwise right shift | x >> 2 = 2 (0000 0010) |
218 | | << | Bitwise left shift | x << 2 = 40 (0010 1000) |
219 |
220 | ## Precedência de Operadores
221 |
222 | Vamos agora considerar a seguinte expressão:
223 |
224 | ```python
225 | print(3 + 4 * 5) # 23
226 | ```
227 |
228 | Há ambigüidade nesta expressão. O Python deve realizar a adição `3 + 4` primeiro e depois multiplicar a soma por `5`? Ou a multiplicação de `4 * 5` deve ser realizada primeiro?
229 |
230 | Uma vez que nosso resultado é **23**, significa que Python optou por multiplicar primeiro e depois realizar a adição, este é o procedimento padrão algébrico, encontrado universalmente em todas as linguagens de programação.
231 |
232 | Todos os operadores suportados por Python têm precedência. Em uma expressão, todos os operadores de maior precedência são executados primeiro. Depois que esses resultados são obtidos, os operadores da próxima precedência mais alta são executados. Então continua-se, até que a expressão seja totalmente avaliada. Quaisquer operadores de igual precedência são executados da **esquerda** para a **direita**.
233 |
234 | A tabela a seguir apresenta a ordem de precedência dos operadores Python do menor ao maior:
235 |
236 | | | Operador | Descrição |
237 | |---|---|---|
238 | | menor precedência | or | Boolean OR |
239 | | | and | Boolean AND |
240 | | | not | Boolean NOT |
241 | | | ==, !=, <, <=, >, >=, is, is not | Comparações, Identidade |
242 | | | \| | Bitwise OR |
243 | | | ^ | Bitwise XOR |
244 | | | & | Bitwise AND |
245 | | | <<, >> | Bit Shifts |
246 | | | +, - | Adição, Subtração |
247 | | | *, /, //, % | Multiplicação, Divisão, Floor Division, Modulus |
248 | | | +x, -x, ~x | Unário Positivo, Unário Negativo, Bitwise Negation |
249 | | maior precedência | ** | Exponenciação |
250 |
251 | Os operadores na parte superior da tabela têm a precedência mais baixa e aqueles na parte inferior da tabela têm a mais alta. Quaisquer operadores na mesma linha da tabela têm precedência igual.
252 |
253 | A precedência do operador pode ser substituída usando parênteses. As expressões entre parênteses são sempre executadas primeiro, antes das expressões que não estão entre parênteses. Por exemplo:
254 |
255 | ```python
256 | print(3 + 3 * 5) # 18
257 | print((3 + 3) * 5) # 30
258 | ```
259 |
260 | Lembre sempre que os operadores tem um papel fundamental na programação e que devemos entender o seu funcionamento de maneira plena, *faça experimentos e divirta-se com os cálculos*!
261 |
--------------------------------------------------------------------------------
/content/sintaxe.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Sintaxe'
3 | description: 'Introdução a Sintaxe da linguagem Python'
4 | ---
5 |
6 | Python foi originalmente desenvolvido como uma linguagem de ensino, mas sua facilidade de uso e sintaxe limpa levaram-no a ser adotado por iniciantes e especialistas.
7 |
8 | A **sintaxe** da linguagem de programação Python é o conjunto de regras que define como um programa Python será escrito e interpretado (tanto pelo sistema de execução quanto por leitores humanos).
9 |
10 | ## Palavras-chave em **Python**
11 |
12 | As palavras-chave são as palavras reservadas pela linguagem **Python**, nós não podemos utilizar essas palavras para nomear nossas **[variáveis](https://pt.wikipedia.org/wiki/Variável_(programação))**, **[funções](http://www.inf.ufpr.br/cursos/ci067/Docs/NotasAula/notas-11_Fun_c_coes.html)** ou qualquer outro identificador, elas são usadas para definir a sintaxe e a estrutura da linguagem **Python**, vale lembrar que as palavras-chave são **case sensitive** e devem ser escritas dessa maneira.
13 |
14 | A seguir mostramos a lista de todas as palavras-chave:
15 |
16 | | **Nome** | **Descrição** |
17 | |----------|:-------------------------------------------------------------------------------------------------:|
18 | | and | operador lógico "e" |
19 | | as | capaz de criar um **[alias](https://pt.wikipedia.org/wiki/Alias_(comando))** |
20 | | assert | usado para **[debugging](https://www.inf.pucrs.br/flash/progbio/aulas/seq/build/progbio/WhatisDebugging.html)** |
21 | | async | usado para escrever aplicações **[asyncio](https://docs.python.org/3/library/asyncio-task.html)** |
22 | | await | usado para escrever aplicações **[asyncio](https://docs.python.org/3/library/asyncio-task.html)** |
23 | | break | para sair de um **[loop](https://pt.wikipedia.org/wiki/Loop_(programação))** |
24 | | class | define uma **[classe](https://pt.wikipedia.org/wiki/Classe_(programação))** |
25 | | continue | continua para a nova iteração do **[loop](https://pt.wikipedia.org/wiki/Loop_(programação))** |
26 | | def | define uma **[função](http://www.inf.ufpr.br/cursos/ci067/Docs/NotasAula/notas-11_Fun_c_coes.html)** |
27 | | del | deleta um **[objeto](https://pt.wikipedia.org/wiki/Objeto_(ciência_da_computação))** |
28 | | elif | usado em **[comandos condicionais](https://pt.wikipedia.org/wiki/Estrutura_de_seleção)**, como else e if |
29 | | else | usado em **[comandos condicionais](https://pt.wikipedia.org/wiki/Estrutura_de_seleção)** |
30 | | except | usado com **[exceções](https://pt.wikipedia.org/wiki/Tratamento_de_exceção)**, para tratar possíveis erros |
31 | | False | Valor **[booleano](https://pt.wikipedia.org/wiki/Booleano)**, resulta de operações de comparação |
32 | | finally | utilizado com **[exceções](https://pt.wikipedia.org/wiki/Tratamento_de_exceção)**, um bloco de código que executará independente de ter uma exceção ou não |
33 | | for | usado para criar um **[loop](https://pt.wikipedia.org/wiki/Loop_(programação))** |
34 | | from | para importar partes específicas de um **[módulo](https://pt.wikipedia.org/wiki/Módulo_de_um_programa)** |
35 | | global | declara uma **[variável global](https://pt.wikipedia.org/wiki/Variável_global)** |
36 | | if | usado para **[comandos condicionais](https://pt.wikipedia.org/wiki/Estrutura_de_seleção)** |
37 | | import | usado para importar **[módulos](https://pt.wikipedia.org/wiki/Módulo_de_um_programa)** |
38 | | in | capaz de checar se um valor está presente em uma lista, tupla, etc |
39 | | is | testa se duas **[variáveis](https://pt.wikipedia.org/wiki/Variável_(programação))** são iguais |
40 | | lambda | cria uma **[função anônima](https://github.com/the-akira/Python-Iluminado/blob/master/17.Lambda.md)** |
41 | | None | representa um valor **[null](https://pt.wikipedia.org/wiki/Null_(programação))** |
42 | | nonlocal | declara uma **[variável](https://pt.wikipedia.org/wiki/Variável_(programação))** não-local |
43 | | not | **[operador lógico](https://pt.wikipedia.org/wiki/Operador_lógico)** de negação |
44 | | or | **[operador lógico](https://pt.wikipedia.org/wiki/Operador_lógico)** "ou" |
45 | | pass | comando null, um comando que não faz nada |
46 | | raise | dispara um **[exceção](https://pt.wikipedia.org/wiki/Tratamento_de_exceção)** |
47 | | return | para sair de uma **[função](http://www.inf.ufpr.br/cursos/ci067/Docs/NotasAula/notas-11_Fun_c_coes.html)** e retornar um valor |
48 | | True | Valor **[booleano](https://pt.wikipedia.org/wiki/Booleano)**, resulta de operações de comparação |
49 | | try | Comando de try, usado em conjunto com except |
50 | | while | Cria um **[loop](https://pt.wikipedia.org/wiki/Loop_(programação))** while |
51 | | with | usado para simplificar a lida com **[exceções](https://pt.wikipedia.org/wiki/Tratamento_de_exceção)** |
52 | | yield | finaliza uma **[função](http://www.inf.ufpr.br/cursos/ci067/Docs/NotasAula/notas-11_Fun_c_coes.html)**, retorna um **[gerador](https://pt.wikipedia.org/wiki/Gerador_(ciência_da_computação))** |
53 |
54 | Obtendo as palavras-chave através do **interpretador** Python:
55 |
56 | ```python
57 | >>> import keyword
58 | >>> print(keyword.kwlist)
59 | ```
60 |
61 | Veja que nos é retornado uma **lista** (Estrutura de Dados que veremos com mais detalhes em breve) com todas as palavras-chave da linguagem Python.
62 |
63 | ```
64 | ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
65 | ```
66 |
67 | *Bastante informação, não?* Talvez muito do que foi mostrado não faça sentido para você, porém fique tranquilo que veremos todas as palavras-chave com detalhe, até que você fique acostumado com elas!
68 |
69 | ## Identificadores
70 |
71 | Os identificadores são nomes dados às entidades como **[variáveis](https://pt.wikipedia.org/wiki/Variável_(programação))**, **[funções](http://www.inf.ufpr.br/cursos/ci067/Docs/NotasAula/notas-11_Fun_c_coes.html)**, **[classes](https://pt.wikipedia.org/wiki/Classe_(programação))**, etc, eles nos ajudam a diferenciar uma entidade da outra.
72 |
73 | ## Regras
74 |
75 | Identificadores podem ser escritos com uma combinação de **letras em lowercase (a até z)** ou **uppercase (A até Z)** ou **dígitos (0 até 9)** ou um **underline (_)**. Nomes como **minhaClasse**, **variavel_1** e **minha_variavel** são exemplos válidos de identificadores.
76 |
77 | Variáveis são **case sensitive** (idade, Idade e IDADE são três variáveis diferentes)
78 | Identificadores **não podem começar com dígitos:** 13variavel é inválido, porém variavel13 é aceito!
79 |
80 | Palavras-chave jamais podem ser usadas como identificadores!
81 |
82 | ## Indentação
83 |
84 | Enquanto em outras linguagens de programação a **[indentação](https://pt.wikipedia.org/wiki/Indentação)** é usada apenas para tornar o código mais legível, em **Python** ela é importantíssima, **Python** usa a indentação para indicar blocos de código, por exemplo:
85 |
86 | ```python
87 | vida = 100
88 |
89 | if vida > 0:
90 | print("Você está vivo")
91 | ```
92 |
93 | Caso você não utilize a indentação correta, Python irá disparar um erro.
94 |
95 | Algumas regras de indentação:
96 |
97 | - Use dois pontos `:` para iniciar um bloco e pressione `[Enter]`.
98 | - Todas as linhas em um bloco devem usar a mesma indentação, seja com espaços ou `[tab]`.
99 | - Python recomenda quatro espaços como indentação para tornar o código mais legível. Não misture espaço e `[tab]` no mesmo bloco.
100 |
101 | Você pode configurar seu editor de texto para a tecla `[tab]` indentar uma quantidade **x** de espaço.
102 |
103 | ## Comentários
104 |
105 | **Python** tem a capacidade de comentários para que seja mais fácil de lermos os códigos de outros programadores, melhora muito a comunicação!
106 |
107 | Comentários começam com `#`, por exemplo:
108 |
109 | ```python
110 | # Este é um comentário
111 | print("Códigos comentados são muito mais fáceis de serem compreendidos")
112 | ```
113 |
114 | **Python** também suporta [docstrings](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html), que são comentários que podem extender até mais linhas, veja:
115 |
116 | ```python
117 | """
118 | Este é um comentário
119 | que abrange várias
120 | linhas do programa
121 | """
122 | print("Procure sempre comentar o seu código")
123 | ```
124 |
125 | ## Statements
126 |
127 | As instruções em Python geralmente terminam com uma nova linha. Python, entretanto, permite o uso do caractere de continuação de linha (`\`) para indicar que a linha deve continuar. Por exemplo:
128 |
129 | ```python
130 | total = 3 + \
131 | 5 + \
132 | 7
133 | print(total) # 15
134 | ```
135 |
136 | O ponto e vírgula (`;`) permite várias instruções em uma única linha, visto que nenhuma instrução inicia um novo bloco de código. Aqui está uma amostra que ilustra esta ideia:
137 |
138 | ```python
139 | x, y = 9, 3; z = x * y; print(f'{x} x {y} = {z}')
140 | # 9 x 3 = 27
141 | ```
142 |
143 | Para saber mais detalhes específicos e técnicos sobre boas práticas de estilo de programação em Python, recomendamos que você visite e leia [PEP 8 -- Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/)
144 |
--------------------------------------------------------------------------------
/content/xml.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'XML'
3 | description: 'Aprenda a trabalhar com arquivos XML em Python'
4 | ---
5 |
6 | **[XML](https://en.wikipedia.org/wiki/XML)** se refere a *"Extensible Markup Language"*, é uma **[markup language](https://en.wikipedia.org/wiki/Markup_language)** que define um conjunto de regras para a codificação de documentos em um formato tanto legível por humanos quanto por máquina.
7 |
8 | Com similaridades ao famoso **HTML**, sua proposta principal é guardar e transportar dados, sendo uma linguagem auto-descritiva. **XML** funciona como uma estrutura de árvore que é fácil de interpretar e suporta hierarquia.
9 |
10 | Os objetivos de design do XML enfatizam a simplicidade, generalidade e usabilidade na Internet. É um formato de dados textual com forte suporte via [Unicode](https://en.wikipedia.org/wiki/Unicode) para diferentes idiomas humanos. Embora o design de XML se concentre em documentos, a linguagem é amplamente utilizada para a representação de estruturas de dados arbitrárias, como aquelas usadas em [serviços web](https://en.wikipedia.org/wiki/Web_service).
11 |
12 | **Documentos XML** possuem seções chamadas de **elementos**, sendo definidos por uma *tag de abertura e fechamento*. Tag é um constructo de markup que começa com `<` e termina com `>`. Os caracteres entre a tag de abertura e fechamento, caso tenha algum, é o conteúdo do elemento.
13 |
14 | Elementos podem conter markup, incluindo outros elementos, que nesse caso, são chamados de filhos. O elemento de maior nível é chamado de **root**, do inglês, raiz em português, esse seria o elemento que **engloba** todos os outros. *Atributos são pares de nome-valor* que existem dentro de uma tag de abertura ou uma tag de elemento vazio. Um atributo **XML** só pode ter um único valor e cada atributo pode aparecer no máximo uma vez em cada elemento.
15 |
16 | Para entendermos melhor o **XML**, vamos utilizar o arquivo [livros.xml](https://github.com/the-akira/Python-Iluminado/blob/master/Arquivos/livros.xml) como exemplo:
17 |
18 | ```xml
19 |
20 |
21 |
22 | Orwell, George
23 | Nineteen Eighty-Four: A Novel
24 | Dystopian
25 | 1949-06-08
26 | Thematically, Nineteen Eighty-Four centres on the consequences of totalitarianism, mass surveillance, and repressive regimentation of persons and behaviours within society.
27 |
28 |
29 | Huxley, Aldous
30 | Brave New World
31 | Dystopian
32 | 1932-12-16
33 | Largely set in a futuristic World State, whose citizens are environmentally engineered into an intelligence-based social hierarchy, the novel anticipates huge scientific advancements in reproductive technology, sleep-learning, psychological manipulation and classical conditioning that are combined to make a dystopian society which is challenged by only a single individual: the story's protagonist.
34 |
35 |
36 | Huxley, Aldous
37 | The Doors of Perception
38 | Psychology
39 | 1954-11-17
40 | The Doors of Perception provoked strong reactions for its evaluation of psychedelic drugs as facilitators of mystical insight with great potential benefits for science, art, and religion.
41 |
42 |
43 | Gibson, William
44 | Neuromancer
45 | Cyberpunk
46 | 1984-07-01
47 | Set in the future, the novel follows Henry Case, a washed-up computer hacker who is hired for one last job, which brings him up against a powerful artificial intelligence.
48 |
49 |
50 | Erickson, Jon
51 | Hacking: The Art of Exploitation
52 | Computer Security
53 | 2003-09-10
54 | Hacking: The Art of Exploitation is a book by Jon "Smibbs" Erickson about computer security and network security.
55 |
56 |
57 | Chollet, François
58 | Deep Learning with Python
59 | Machine Learning
60 | 2017-11-02
61 | Deep Learning with Python introduces the field of deep learning using the Python language and the powerful Keras library. Written by Keras creator and Google AI researcher François Chollet, this book builds your understanding through intuitive explanations and practical examples.
62 |
63 |
64 | Kant, Immanuel
65 | Critique of Pure Reason
66 | Philosophy
67 | 1787-11-02
68 | The Critique of Pure Reason is a book by the German philosopher Immanuel Kant, in which the author seeks to determine the limits and scope of metaphysics.
69 |
70 |
71 | Schopenhauer, Arthur
72 | The World as Will and Representation
73 | Philosophy
74 | 1818-12-06
75 | Taking the transcendental idealism of Immanuel Kant as his starting point, Schopenhauer argues that the world we experience around us—the world of objects in space and time and related in causal ways—exists solely as 'representation' (Vorstellung) dependent on a cognizing subject, not as a world that can be considered to exist in itself (independently of how it appears to the subject’s mind).
76 |
77 |
78 | ```
79 |
80 | Como podemos ver, ele é fácil de compreender e legível, assim como os arquivos JSON, agora vamos começar a trabalhar com ele em **Python**, para isso vamos usar o módulo **[xml.etree.ElementTree](https://docs.python.org/3/library/xml.etree.elementtree.html)**, porém esteja atento que esse módulo *não é seguro contra dados maliciosos*, então esteja atento na segurança dos dados que você vai processar.
81 |
82 | O módulo **xml.etree.ElementTree** implementa uma API simples e eficiente para analisar e criar dados XML.
83 |
84 | Para trabalharmos com este módulo, é necessário apenas importá-lo, sem a necessidade de instalação. Vamos nos referir a ele apenas como **et** para ficar mais simples para trabalharmos:
85 |
86 | ```python
87 | import xml.etree.ElementTree as et
88 | ```
89 |
90 | Para carregar o nosso arquivo, vamos utilizar o método **parse()**:
91 |
92 | ```python
93 | arquivo = et.parse('livros.xml')
94 | print(arquivo)
95 | #
96 | ```
97 |
98 | Observe que nos é retornado um objeto **ElementTree**, que representa respectivamente uma árvore de elementos XML. Para obtermos a raiz (root) desta árvore, podemos usar o método **getroot()**:
99 |
100 | ```python
101 | raiz = arquivo.getroot()
102 | print(raiz) #
103 | print(raiz.tag) # 'catalog'
104 | ```
105 |
106 | Como podemos ver, temos um objeto **Element** com o nome 'catalog', que representa o nosso catálogo de livros, a raiz de nossa árvore, com o atributo **tag** podemos acessar este valor.
107 |
108 | Uma vez que temos a raiz, podemos por exemplo iterar sob os children nodes, que são as tags filhas respectivamente:
109 |
110 | ```python
111 | for filhas in raiz:
112 | print(filhas.tag, filhas.attrib)
113 |
114 | # book {'id': 'bk101'}
115 | # book {'id': 'bk102'}
116 | # book {'id': 'bk103'}
117 | # book {'id': 'bk104'}
118 | # book {'id': 'bk105'}
119 | # book {'id': 'bk106'}
120 | # book {'id': 'bk107'}
121 | # book {'id': 'bk108'}
122 | ```
123 |
124 | Neste exemplo específico, estamos obtendo o nome das tags filhas e seus respectivos atributos.
125 |
126 | As tags filhas são **encadeadas**, e para acessarmos seus valores específicos por índice, usamos esta notação:
127 |
128 | ```python
129 | print(raiz[0][0].text) # Orwell, George
130 | print(raiz[1][1].text) # Brave New World
131 | ```
132 |
133 | Agora vamos utilizar o método **findall()** que nos permite procurar por **tags** que são filhas diretas do elemento atual que estamos usando. Além disso, temos também o método **find()** que procura o primeiro filho com uma tag particular e **Element.text** que acesso o conteúdo de texto do elemento.
134 |
135 | ```python
136 | for filhas in raiz.findall('book'):
137 | autor = filhas.find('author').text
138 | titulo = filhas.find('title').text
139 | print(f'Autor: {autor} | Título: {titulo}')
140 |
141 | # Autor: Orwell, George | Título: Nineteen Eighty-Four: A Novel
142 | # Autor: Huxley, Aldous | Título: Brave New World
143 | # Autor: Huxley, Aldous | Título: The Doors of Perception
144 | # Autor: Gibson, William | Título: Neuromancer
145 | # Autor: Erickson, Jon | Título: Hacking: The Art of Exploitation
146 | # Autor: Chollet, François | Título: Deep Learning with Python
147 | # Autor: Kant, Immanuel | Título: Critique of Pure Reason
148 | # Autor: Schopenhauer, Arthur | Título: The World as Will and Representation
149 | ```
150 |
151 | Também podemos usar o método **iter()** que nos ajuda a iterar sob a árvore XML. Por exemplo:
152 |
153 | ```python
154 | descricoes = [d.text for d in raiz.iter('description')]
155 | print(descricoes[0])
156 | # Thematically, Nineteen Eighty-Four centres on the consequences of totalitarianism, mass surveillance, and repressive regimentation of persons and behaviours within society.
157 | ```
158 |
159 | ElementTree fornece uma maneira simples de construir documentos XML e gravá-los em arquivos. O método **write()** serve a esse propósito.
160 |
161 | Uma vez criado, um objeto Element pode ser manipulado alterando diretamente seus campos (como Element.text), adicionando e modificando atributos (método **set()**), bem como adicionando novos filhos (por exemplo, com **append()**).
162 |
163 | Imagine que queremos atualizar o gênero do livro **Neuromancer** para **Science Fiction**, podemos fazê-lo com o auxílio dos métodos **find()** e **findall()** e com um simples `if` testamos pela existência do gênero atual e o substituímos pelo novo, e através do método **set()** nós adicionamos um atributo `atualizado` para esta tag ``.
164 |
165 | ```python
166 | for genre in raiz.findall('book'):
167 | genero = genre.find('genre')
168 | if genero.text == 'Cyberpunk':
169 | genero.text = 'Science Fiction'
170 | genero.set('atualizado','sim')
171 | print(genero.text)
172 |
173 | arquivo.write('novo_livros.xml')
174 | ```
175 |
176 | Finalmente, com o método **write()** salvamos os novos dados em um novo arquivo.
177 |
178 | Também podemos remover elementos usando o método **remove()**. Se quisermos por exemplo remover o elemento ``, podemos usar o método **findall()** para iterar sob todos os elementos livros e buscar especificamente o elemento **publish_date** e removê-lo com o método **remove()**. Novamente podemos salvar as alterações em um novo arquivo com **write()**.
179 |
180 | ```python
181 | for book in raiz.findall('book'):
182 | publish_date = book.find('publish_date')
183 | book.remove(publish_date)
184 |
185 | arquivo.write('new_livros.xml')
186 | ```
187 |
188 | Essa foi uma introdução básica ao XML com Python, embora já não esteja tão popular como no passado por conta do poderoso JSON, é necessário que entendamos como funciona a estrutura do arquivo XML e se necessário como manipulá-lo.
189 |
--------------------------------------------------------------------------------
/content/json.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'JSON'
3 | description: 'Aprenda a trabalhar com dados JSON'
4 | ---
5 |
6 | Na computação, **[JSON](https://www.json.org/)** ou **Javascript Object Notation** é um padrão aberto de formato de arquivo que utiliza textos legíveis para humanos para transmistir objetos de dados que consistem de *pares de atributos-valores* e tipos de dados **array** (ou qualquer outro valor serializável), é um formato de dados de uso muito comum para comunicação *asíncrona de cliente-servidor*.
7 |
8 | É importante destacar, que embora JSON carregue Javascript no seu nome, ele é independente e vale para qualquer linguagem de programação.
9 |
10 | Os tipos básicos de dados do JSON são:
11 |
12 | - **Number**: Um número decimal com sinal que pode conter uma parte fracionária e pode usar a notação exponencial **E**, mas não pode incluir não-números como **NaN**. O formato não faz distinção entre integer e floating-point.
13 | - **String**: Uma sequência de zero ou mais caracteres Unicode. Strings são delimitadas com aspas duplas e oferecem suporte a uma sintaxe de escape de barra invertida.
14 | - **Boolean**: Um valor `true` ou `false`
15 | - **Array**: Uma lista ordenada de zero ou mais valores, cada um dos quais pode ser de qualquer tipo. Arrays usam notação de colchetes com elementos separados por vírgula.
16 | - **Object**: Uma coleção de pares **nome-valor** onde os nomes (também chamados de chaves) são strings. Os objetos têm o objetivo de representar arrays associativos, onde cada chave é única dentro de um objeto. Os objetos são delimitados por chaves e usam vírgulas `,` para separar cada par, enquanto dentro de cada par o caractere `:` separa a **chave** ou **nome** de seu **valor**.
17 | - **null**: Um valor vazio, utilizando a palavra `null`
18 |
19 | Para entendermos melhor o **JSON**, vamos definir um arquivo `pessoa.json` que descreverá uma pessoa:
20 |
21 | ```javascript
22 | {
23 | "primeiroName": "Miguel",
24 | "segundoName": "Arcanjo",
25 | "estaVivo": true,
26 | "idade": 27,
27 | "endereço": {
28 | "rua": "Rua Alfa 33",
29 | "cidade": "São Paulo",
30 | "estado": "SP",
31 | "codigoPostal": "1321-32423"
32 | },
33 | "numerosTelefones": [
34 | {
35 | "tipo": "casa",
36 | "numero": "212 555-1234"
37 | },
38 | {
39 | "tipo": "escritorio",
40 | "numero": "646 555-4567"
41 | },
42 | {
43 | "tipo": "celular",
44 | "numero": "123 456-7890"
45 | }
46 | ],
47 | "criancas": [],
48 | "cônjuge": null
49 | }
50 | ```
51 |
52 | Como podermos ver, **JSON** é bastante legível e acessível, fazendo com que seja excelente para estruturarmos dados, nesse caso, veja que temos um objeto **pessoa**.
53 |
54 | Dentro do objeto pessoas temos diversos atributos:
55 |
56 | - **primeiroName**: String representando o primeiro nome da pessoa
57 | - **segundoName**: String representando o sobrenome da pessoa
58 | - **estaVivo**: Boolean representando se a pessoa está viva ou não
59 | - **idade**: Number integer representando a idade da pessoa
60 | - **endereço**: Um objeto com quatro atributos (rua, cidade, estado, codigoPostal) representando o endereço da pessoa
61 | - **numerosTelefones**: Um array contendo três objetos, representando os telefones da pessoa
62 | - **criancas**: Um array representando as crianças da pessoa, neste exemplo ele está vazio
63 | - **cônjuge**: Campo representando se a pessoa é casada, neste exemplo está `null`
64 |
65 | Para utilizarmos **JSON** em **Python**, contamos com o módulo **json**, que podemos importá-lo facilmente, sem a necessida de instalação:
66 |
67 | ```python
68 | import json
69 | ```
70 |
71 | ## Parse de JSON, Convertendo JSON para Python
72 |
73 | Em Python, caso tenhamos uma string JSON, nós usamos o método **json.loads()** para fazer o **parse** e convertermos em um dicionário para que seja mais fácil de trabalharmos com os dados.
74 |
75 | Veja que além do arquivo `.json`, também podemos ter JSON armazenado como uma string:
76 |
77 | ```python
78 | import json
79 |
80 | pessoa = '{ "nome":"Rafael", "idade":29, "cidade":"São Paulo"}'
81 |
82 | pessoa_dict = json.loads(pessoa)
83 | print(type(pessoa_dict)) #
84 | print(pessoa_dict) # {'nome': 'Rafael', 'idade': 29, 'cidade': 'São Paulo'}
85 | print(pessoa_dict['idade']) # 29
86 | ```
87 |
88 | ## Convertendo Python para JSON
89 |
90 | Se quisermos, também podemos converter um objeto de Python em uma string JSON, para esta tarefa vamos usar o método **json.dumps()**.
91 |
92 | Vamos definir um dicionário Python e fazer sua conversão:
93 |
94 | ```python
95 | import json
96 |
97 | pessoa = {
98 | "nome": "Gabriel",
99 | "idade": 27,
100 | "país": "Brasil"
101 | }
102 |
103 | pessoa_json = json.dumps(pessoa) #
104 | print(pessoa_json) # {"nome": "Gabriel", "idade": 27, "pa\u00eds": "Brasil"}
105 | ```
106 |
107 | Perceba que ele não nos retornou os dados na codificação correta, para obtermos os dados em UTF-8, devemos setar o atributo **ensure_ascii** como `False`:
108 |
109 | ```python
110 | pessoa_json = json.dumps(pessoa, ensure_ascii=False)
111 | print(pessoa_json) # '{"nome": "Gabriel", "idade": 27, "país": "Brasil"}'
112 | ```
113 |
114 | É possível converter os seguintes objetos em **Python** para **JSON**, e eles receberão um valor de equivalência em JSON como mostra a seguinte tabela:
115 |
116 | | Python | JSON |
117 | |--------|--------|
118 | | dict | Object |
119 | | list | Array |
120 | | tuple | Array |
121 | | str | String |
122 | | int | Number |
123 | | float | Number |
124 | | True | true |
125 | | False | false |
126 | | None | null |
127 |
128 | ## Exemplo com todos os Tipos de Dados
129 |
130 | Para compreendermos melhor o funcionamento da biblioteca json, vamos agora trabalhar em um exemplo contendo todos os tipos possíveis de dados.
131 |
132 | ```python
133 | import json
134 |
135 | personagem = {
136 | "nome": "Talantyr",
137 | "epiteto": "O Glorioso",
138 | "nível": 45,
139 | "vivo": True,
140 | "atributos": {"força": 45, "destreza": 60, "inteligência": 70},
141 | "mascotes": ("Lobo","Coruja"),
142 | "magias": None,
143 | "itens": [
144 | {"nome": "poção de mana", "quantidade": 5},
145 | {"nome": "poção de vida", "quantidade": 7}
146 | ]
147 | }
148 |
149 | print(json.dumps(personagem, ensure_ascii=False))
150 | # {"nome": "Talantyr", "epiteto": "O Glorioso", "nível": 45, "vivo": true, "atributos": {"força": 45, "destreza": 60, "inteligência": 70}, "mascotes": ["Lobo", "Coruja"], "magias": null, "itens": [{"nome": "poção de mana", "quantidade": 5}, {"nome": "poção de vida", "quantidade": 7}]}
151 | ```
152 |
153 | Para obtermos um output mais limpo, podemos setar o atributo **indent** com um determinado número, neste caso específico, **4**:
154 |
155 | ```python
156 | print(json.dumps(personagem, ensure_ascii=False, indent=4))
157 | ```
158 |
159 | Dessa vez, temos o resultado que esperamos:
160 |
161 | ```javascript
162 | {
163 | "nome": "Talantyr",
164 | "epiteto": "O Glorioso",
165 | "nível": 45,
166 | "vivo": true,
167 | "atributos": {
168 | "força": 45,
169 | "destreza": 60,
170 | "inteligência": 70
171 | },
172 | "mascotes": [
173 | "Lobo",
174 | "Coruja"
175 | ],
176 | "magias": null,
177 | "itens": [
178 | {
179 | "nome": "poção de mana",
180 | "quantidade": 5
181 | },
182 | {
183 | "nome": "poção de vida",
184 | "quantidade": 7
185 | }
186 | ]
187 | }
188 | ```
189 |
190 | Caso queiramos os atributos do resultado ordenados, podemos usar o parâmetro **sort_keys** como `True`:
191 |
192 | ```python
193 | print(json.dumps(p, indent=4, sort_keys=True))
194 | ```
195 |
196 | Dessa vez, temos o seguinte resultado:
197 |
198 | ```javascript
199 | {
200 | "atributos": {
201 | "destreza": 60,
202 | "força": 45,
203 | "inteligência": 70
204 | },
205 | "epiteto": "O Glorioso",
206 | "itens": [
207 | {
208 | "nome": "poção de mana",
209 | "quantidade": 5
210 | },
211 | {
212 | "nome": "poção de vida",
213 | "quantidade": 7
214 | }
215 | ],
216 | "magias": null,
217 | "mascotes": [
218 | "Lobo",
219 | "Coruja"
220 | ],
221 | "nome": "Talantyr",
222 | "nível": 45,
223 | "vivo": true
224 | }
225 | ```
226 |
227 | Se quisermos, podemos facilmente converter o dicionário personagem em JSON (como já vimos anteriormente) e em seguida, salvar os dados em um arquivo de nome `personagem.json`:
228 |
229 | ```python
230 | dados_json = json.dumps(personagem, ensure_ascii=False, indent=4)
231 |
232 | with open('personagem.json','w') as json_file:
233 | json_file.write(dados_json)
234 | ```
235 |
236 | Como podemos observar, os dados agora persistem no arquivo [personagem.json](https://github.com/the-akira/Python-Iluminado/blob/master/Arquivos/personagem.json)
237 |
238 | ## Utilizando uma API
239 |
240 | Vamos consumir uma simples [API](https://en.wikipedia.org/wiki/Representational_state_transfer) de testes para entendermos melhor a interação com outras aplicações que expõem seus serviços online.
241 |
242 | ```python
243 | import json
244 | import requests
245 |
246 | r = requests.get('https://jsonplaceholder.typicode.com/posts')
247 | posts = r.json()
248 |
249 | for post in posts:
250 | print(post) # Imprime todos os posts
251 | print(post['id']) # Imprime todos os ids
252 | print(post['title']) # Imprime todos os títulos
253 | print(post['body']) # Imprime todos os textos
254 | ```
255 |
256 | Como podemos observar, conseguimos obter os dados com sucesso e agora podemos trabalhar com eles da forma que desejarmos.
257 |
258 | Experimente esta ideia trabalhando com outras API's, por exemplo a do [GitHub](https://api.github.com/).
259 |
260 | ## JSONPickle
261 |
262 | A biblioteca **[jsonpickle](https://jsonpickle.github.io/)** nos permite **serializar** e **deserializar** objetos complexos em Python para JSON e também de JSON.
263 |
264 | Para podermos usar suas funcionalidades, precisamos instalar ela com um simples comando:
265 |
266 | ```
267 | pip install jsonpickle
268 | ```
269 |
270 | Vejamos exemplos dela para ilustrar o seu uso.
271 |
272 | Vamos começar criando um objeto `Gato`:
273 |
274 | ```python
275 | class Gato:
276 | def __init__(self, nome, raca):
277 | self.nome = nome
278 | self.raca = raca
279 | ```
280 |
281 | Agora vamos criar um novo `Gato`
282 |
283 | ```python
284 | gato = Gato('Osíris','Sphynx')
285 | ```
286 |
287 | Transformando o objeto `Gato` em uma string JSON e salvando em um arquivo:
288 |
289 | ```python
290 | import jsonpickle
291 |
292 | jsonpickle.set_preferred_backend('json')
293 | jsonpickle.set_encoder_options('json', ensure_ascii=False)
294 |
295 | with open('gato.json', 'w') as file:
296 | frozen = jsonpickle.encode(gato)
297 | file.write(frozen)
298 | ```
299 |
300 | Nosso objeto agora persiste no arquivo [gato.json](https://github.com/the-akira/Python-Iluminado/blob/master/Arquivos/gato.json)
301 |
302 | Lendo o arquivo JSON e decodificando para recriar o objeto `Gato`:
303 |
304 | ```python
305 | with open('gato.json', 'r') as file:
306 | contents = file.read()
307 | unfrozen = jsonpickle.decode(contents)
308 | print(unfrozen) # <__main__.Gato object at 0x7efdfeeca5c0>
309 | print(unfrozen.raca) # Sphynx
310 | print(unfrozen.nome) # Osíris
311 | ```
312 |
313 | Essa breve introdução nos mostrou a importância do **JSON** atualmente e a capacidade que o Python tem de manipulá-lo com uma certa facilidade, inclusive.
314 |
315 | Se você deseja obter mais detalhes sobre a biblioteca padrão json em Python, visite **[docs.python](https://docs.python.org/3/library/json.html)**. Bons estudos!
316 |
--------------------------------------------------------------------------------
/content/decoradores.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Decoradores'
3 | description: 'Aprenda sobre Decoradores'
4 | ---
5 |
6 | **Decoradores** são um elemento significante do Python, também são conhecidos como **[meta-programação](https://en.wikipedia.org/wiki/Metaprogramming)**, para simplificarmos sua ideia, podemos dizer que eles são funções que modificam a funcionalidade de uma outra função, eles nos ajudam a deixar o código menor e mais **Pythônico** (legível ao modo Python). O conceito de decoradores pode ser inicialmente um pouco difícil de capturarmos, mas vamos por partes.
7 |
8 | Antes de compreendermos os decoradores, é interessante que entendamos como as funções funcionam. Lembre que uma função retorna um valor baseado nos argumentos fornecidos a ela. Vejamos um simples exemplo:
9 |
10 | ```python
11 | def saudar(nome='Gabriel'):
12 | return f'Saudações, {nome}!'
13 | ```
14 |
15 | Podemos agora chamar essa função sem um argumento (pois já existe um argumento padrão nela), ou com um argumento:
16 |
17 | ```python
18 | saudar() # 'Saudações, Gabriel!'
19 | saudar('Rafael') # 'Saudações, Rafael!'
20 | ```
21 |
22 | Em geral, as funções em Python também podem ter efeitos colaterais, em vez de apenas transformar um *input* em um *output*. A função **print()** é um exemplo básico disso: ela retorna `None` enquanto tem o efeito colateral de enviar algo para o console. Porém, para entender os decoradores, basta pensar nas funções como algo que transforma determinados argumentos em um valor.
23 |
24 | Também podemos atribuir uma função a uma variável, para isso, não usamos parenteses, dessa maneira estamos guardando apenas a referência ao objeto função.
25 |
26 | ```python
27 | saudacao = saudar
28 | print(saudacao) #
29 | saudacao('Miguel') # 'Saudações, Miguel!'
30 | ```
31 |
32 | Podemos por exemplo deletar a referência em memória da antiga função:
33 |
34 | ```python
35 | del saudar
36 | saudar() # NameError: name 'saudar' is not defined
37 | ```
38 |
39 | Veja que se tentarmos invocá-la írá ocorrer um `NameError`, mas veja que ainda podemos chamar a outra referência que temos:
40 |
41 | ```python
42 | saudacao() # 'Saudações, Gabriel!'
43 | ```
44 |
45 | Veja que mesmo deletando a função antiga, ainda conseguimos executar a função **saudacao()**!
46 |
47 | ## Funções dentro de Funções
48 |
49 | Em Python, funções são [first-class objects](https://stackoverflow.com/questions/245192/what-are-first-class-objects#:~:text=A%20first%20class%20object%20is,being%20storable%20in%20variables). Isso significa que as funções podem ser transmitidas e usadas como argumentos, assim como qualquer outro objeto (string, int, float, listas e assim por diante).
50 |
51 | Vamos começar definindo uma simples função:
52 |
53 | ```python
54 | def func(string):
55 | def wrapper():
56 | print("Iniciada")
57 | print(string)
58 | print("Finalizada")
59 | return wrapper()
60 | ```
61 |
62 | Observe que temos uma função de nome **func()** que recebe uma string como argumento e dentro dela temos uma função de nome **wrapper()** que não recebe nenhum argumento e imprime `"Iniciada"`, a **string** passada para a função **func()** e `"Finalizada"` e finalmente retorna a função **wrapper()** (ela mesma) invocando-a. Podemos usá-la da seguinte forma:
63 |
64 | ```python
65 | f = func("Hello World")
66 | # Iniciada
67 | # Hello World
68 | # Finalizada
69 | ```
70 |
71 | Vamos agora modificá-la para que a função **wrapper()** não retorne a ela mesmo invocando-a, mas dessa vez apenas o objeto função.
72 |
73 | ```python
74 | def func(string):
75 | def wrapper():
76 | print("Iniciada")
77 | print(string)
78 | print("Finalizada")
79 | return wrapper
80 | ```
81 |
82 | Dessa vez para usá-la temos de usar o seguinte procedimento:
83 |
84 | ```python
85 | f = func("Hello World")
86 | print(f) # .wrapper at 0x7f7ab6fca0e0>
87 | f()
88 | # Iniciada
89 | # Hello World
90 | # Finalizada
91 | ```
92 |
93 | Também existe a opção de chamá-la da seguinte forma:
94 |
95 | ```python
96 | func("Hello World")()
97 | # Iniciada
98 | # Hello World
99 | # Finalizada
100 | ```
101 |
102 | Até então tudo bem, nada que venha a nos surpreender. Mas e se desejarmos passar uma outra função como argumento para **func()**? Vamos definir duas novas funções para testarmos:
103 |
104 | ```python
105 | def func(f):
106 | def wrapper():
107 | print("Iniciada")
108 | f()
109 | print("Finalizada")
110 | return wrapper
111 |
112 | def f1():
113 | print("Função f1() chamada!")
114 |
115 | def f2():
116 | print("Função f2() chamada")
117 | ```
118 |
119 | Observe que modificamos a função **wrapper()** e agora ela está invocando a função **f()** (esta que passaremos como argumento). Vamos agora chamar a função **func()** passando as funções **f1()** e **f2()** como argumento:
120 |
121 | ```python
122 | f1 = func(f1)
123 | f2 = func(f2)
124 | print(f1) # .wrapper at 0x7f7ab702ab90>
125 | print(f2) # .wrapper at 0x7f7ab702a950>
126 | f1()
127 | # Iniciada
128 | # Função f1() chamada!
129 | # Finalizada
130 | f2()
131 | # Iniciada
132 | # Função f2() chamada
133 | # Finalizada
134 | ```
135 |
136 | Basicamente este é o conceito de decoradores, estamos usando a função **func()** para alterar o comportamento das funções **f1()** e **f2()**, porém existe uma maneira mais interessante de definí-los, em outras palavras, mais Pythônica.
137 |
138 | ## Decorando Funções
139 |
140 | Vamos decorar as funções **f1()** e **f2()** usando a sintaxe `@`:
141 |
142 | ```python
143 | @func
144 | def f1():
145 | print("Função f1() chamada!")
146 |
147 | @func
148 | def f2():
149 | print("Função f2() chamada")
150 | ```
151 |
152 | Dessa vez podemos chamá-las diretamente e teremos o mesmo efeito anterior:
153 |
154 | ```python
155 | f1()
156 | # Iniciada
157 | # Função f1() chamada!
158 | # Finalizada
159 | f2()
160 | # Iniciada
161 | # Função f2() chamada
162 | # Finalizada
163 | ```
164 |
165 | Faremos agora outra modificação, dessa vez as funções **wrapper()** e **f1()** passam a receber um argumento e a função passada como argumento para **func()** passa a ser invocada com esse argumento:
166 |
167 | ```python
168 | def func(f):
169 | def wrapper(x):
170 | print("Iniciada")
171 | f(x)
172 | print("Finalizada")
173 | return wrapper
174 |
175 | @func
176 | def f1(x):
177 | print(f"O valor de x é = {x}")
178 |
179 | @func
180 | def f2():
181 | print("Função f2() chamada")
182 | ```
183 |
184 | Vejamos agora o que ocorre se invocarmos as funções **f1()** e **f2()**:
185 |
186 | ```python
187 | f1(7)
188 | # Iniciada
189 | # O valor de x é = 7
190 | # Finalizada
191 | f2() # TypeError: wrapper() missing 1 required positional argument: 'x'
192 | ```
193 |
194 | **f1()** é chamada e nos imprime o valor como esperado, porém **f2()** "quebra", não somo capazes de chamá-la, pois a função **wrapper()** espera um argumento. Para solucionar este problema podemos usar o conceito de `*args` e `**kwargs`, vamos então masi uma vez modificar nossas funções:
195 |
196 | ```python
197 | def func(f):
198 | def wrapper(*args, **kwargs):
199 | print("Iniciada")
200 | f(*args, **kwargs)
201 | print("Finalizada")
202 | return wrapper
203 |
204 | @func
205 | def f1(x):
206 | print(f"O valor de x é = {x}")
207 |
208 | @func
209 | def f2():
210 | print("Função f2() chamada")
211 |
212 | f1(7)
213 | # Iniciada
214 | # O valor de x é = 7
215 | # Finalizada
216 | f2()
217 | # Iniciada
218 | # Função f2() chamada
219 | # Finalizada
220 | ```
221 |
222 | Para finalizarmos, vamos modificar nossas funções **wrapper()** e **f1()** para retornar um valor:
223 |
224 | ```python
225 | def func(f):
226 | def wrapper(*args, **kwargs):
227 | print("Iniciada")
228 | valor_retorno = f(*args, **kwargs)
229 | print("Finalizada")
230 | return valor_retorno
231 | return wrapper
232 |
233 | @func
234 | def f1(x, y):
235 | print(f"O valor de x é = {x}")
236 | print(f"O valor de y é = {y}")
237 | return y + x
238 |
239 | f1 = f1(5,33)
240 | # Iniciada
241 | # O valor de x é = 5
242 | # O valor de y é = 33
243 | # Finalizada
244 | print(f1) # 38
245 | ```
246 |
247 | ## Outros Exemplos
248 |
249 | Funções e métodos são chamados **callable** se for possível chamá-los. De fato, qualquer objeto que implemente o método especial `__call__()` é um **callable**, então um decorador seria um callable que retorna um callable.
250 |
251 | Então como já tinhamos dito na nossa introdução, um decorador recebe um função, adiciona alguma funcionalidade a ela e a retorna:
252 |
253 | ```python
254 | def embelezar(func):
255 | def interno():
256 | print("Fui decorado")
257 | func()
258 | return interno
259 |
260 | def normal():
261 | print("Eu sou normal")
262 |
263 | normal() # Eu sou normal
264 | bonito = embelezar(normal)
265 | bonito()
266 | # Fui decorado
267 | # Eu sou normal
268 | ```
269 |
270 | Veja que a função **normal()** foi decorada e demos o nome à função retornada, que se chamou bonito. Uma forma mais eficaz de usarmos os decoradores é usando o símbolo `@` junto do nome da função decoradora e colocar ele em cima da definição da função a ser decorada. Por exemplo:
271 |
272 | ```python
273 | @embelezar
274 | def normal():
275 | print("Eu sou normal também")
276 |
277 | normal()
278 | # Fui decorado
279 | # Eu sou normal também
280 | ```
281 |
282 | ### Decorando Funções com Parâmetros
283 |
284 | O último **decorador** que escrevemos foi bastante simples, só funcionava com funções sem parâmatros, apenas para ilustrarmos o conceito, mas e se tivermos funções que operam com parâmetros?
285 |
286 | ```python
287 | def divisao(x, y):
288 | return x / y
289 | ```
290 |
291 | A função recebe dois parâmetros **x** e **y**, sabemos que se passarmos **0** para **y** ocorrerá um erro.
292 |
293 | ```python
294 | print(divisao(10,2)) # 5.0
295 | print(divisao(3,0)) # ZeroDivisionError: division by zero
296 | ```
297 |
298 | Agora vamos fazer um decorador para resolvermos esse problema.
299 |
300 | ```python
301 | def divisao_inteligente(func):
302 | def interior(x,y):
303 | print("Será feita uma divisão de {0} por {1}".format(x,y))
304 | if y == 0:
305 | print("Impossível dividir")
306 | return
307 | return func(x,y)
308 | return interior
309 |
310 | @divisao_inteligente
311 | def divisao(x,y):
312 | return x / y
313 |
314 | divisao(3,3)
315 | # Será feita uma divisão de 3 por 3
316 | # 1.0
317 | divisao(3,0)
318 | # Será feita uma divisão de 3 por 0
319 | # Impossível dividir
320 | ```
321 |
322 | ### Medindo Desempenho
323 |
324 | Podemos criar um decorar que é capaz de medir quanto tempo uma função leva para rodar:
325 |
326 | ```python
327 | import time
328 |
329 | def timer(func):
330 | def wrapper(*args, **kwargs):
331 | inicio = time.time()
332 | valor_retorno = func()
333 | total = time.time() - inicio
334 | print(f"Tempo: {total}")
335 | return valor_retorno
336 | return wrapper
337 | ```
338 |
339 | Vamos definir duas funções para medí-las:
340 |
341 | ```python
342 | @timer
343 | def t1():
344 | for _ in range(10_000_000):
345 | pass
346 |
347 | @timer
348 | def t2():
349 | time.sleep(2.3)
350 | ```
351 |
352 | Finalmente, vamos obter o tempo de cada uma:
353 |
354 | ```python
355 | t1() # Tempo: 0.36320018768310547
356 | t2() # Tempo: 2.302194118499756
357 | ```
358 |
359 | Com esse estudo podemos considerar que decoradores são de certa forma um pouco complexos, mas que nos trazem novas possibilidades de trabalharmos em cima das funções, modificando seu comportamento. Eles são muito comuns também em **frameworks web**, como **[Flask](https://flask.palletsprojects.com/)** e **[Bottle](https://bottlepy.org/docs/dev/)** por exemplo.
360 |
--------------------------------------------------------------------------------
/content/ambientes-virtuais.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Gerenciadores de Pacotes e Ambientes Virtuais'
3 | description: 'Aprenda sobre Gerenciadores de Pacotes e Ambientes Virtuais'
4 | ---
5 |
6 | **PIP** é o gerenciador de pacotes do Python, também conhecidos como **bibliotecas**.
7 |
8 | É importante notar que o termo "pacote" neste contexto está sendo usado como sinônimo de distribuição (ou seja, um pacote de software a ser instalado), não para se referir ao tipo de pacote que você importa em seu código-fonte Python (ou seja, um contêiner de módulos). É comum na comunidade Python referir-se a uma distribuição usando o termo "pacote". O uso do termo "distribuição" geralmente não é preferido, porque pode ser facilmente confundido com uma distribuição Linux ou outra distribuição de software maior como o próprio Python.
9 |
10 | A partir da versão 3.4 do Python o PIP já vem incluído por padrão com a instalação do Python, então existem grandes chances de você já tê-lo em sua máquina.
11 |
12 | Para confirmar se ele está instalado, vamos digitar o seguinte comando na nossa **interface de linha de comando**:
13 |
14 | ```
15 | pip --version
16 | ```
17 |
18 | Caso ele não esteja presente em sua máquina, você pode encontrá-lo em: **https://pypi.org/project/pip/** ou **[get-pip.py](https://bootstrap.pypa.io/get-pip.py)**:
19 |
20 | - Faça o download do arquivo `get-pip.py`
21 | - Execute o comando `python get-pip.py`. Isso irá instalar ou atualizar o pip.
22 |
23 | Outra opção de instalação é executar o comando:
24 |
25 | ```
26 | python -m ensurepip --default-pip
27 | ```
28 |
29 | Para confirmar se o pip está atualizado, você pode executar o seguinte comando:
30 |
31 | ```
32 | python -m pip install --upgrade pip
33 | ```
34 |
35 | Para navegar através da lista de mais de `190,943` projetos, `2,069,359` arquivos e `354,989` usuários, visite: **https://pypi.org**
36 |
37 | ## Pacotes
38 |
39 | Um pacote seria um conjunto de arquivos para um módulo, como já vimos antes, módulos são como bibliotecas de código que podemos incluir em nossos projetos para usarmos suas funcionalidades e facilitar nossa vida como programadores.
40 |
41 | Normalmente, não armazenamos todos os nossos arquivos em nosso computador no mesmo local. Usamos uma hierarquia de diretórios bem organizada para facilitar o acesso e gerência.
42 |
43 | Conforme nosso programa cresce em tamanho com muitos módulos, colocamos módulos semelhantes em um pacote e módulos diferentes em pacotes diferentes. Isso torna um projeto (programa) fácil de gerenciar.
44 |
45 | Da mesma forma, como um diretório pode conter sub-diretórios e arquivos, um pacote Python pode ter sub-pacotes e módulos.
46 |
47 | Um diretório deve conter um arquivo denominado `__init__.py` para que o Python o considere como um pacote. Este arquivo pode ser deixado vazio, mas geralmente colocamos o código de inicialização para esse pacote neste arquivo.
48 |
49 | A seguinte ilustração nos apresenta a ideia de como funciona a estrutura de um projeto, usamos como exemplo um pacote de nome **Game** que possui diversos módulos.
50 |
51 | 
52 |
53 | ### Instalando Pacotes
54 |
55 | Novamente, vamos abrir nossa **interface de linha de comando** e vamos até o diretório que está nosso script. Digitaremos o seguinte comando para instalar a biblioteca [requests](https://requests.readthedocs.io/en/master/):
56 |
57 | ```python
58 | pip install requests
59 | ```
60 |
61 | Será iniciado um processo de *download e instalação*, aguarde um pouco e estará pronto, agora poderemos usar a nova biblioteca.
62 |
63 | ### Utilizando o Pacote
64 |
65 | Uma vez que já temos requests instalada, para usarmos é só importá-la, assim como fazemos com os módulos padrão do Python:
66 |
67 | ```python
68 | import requests
69 |
70 | print(dir(requests))
71 | # ['ConnectionError', 'FileModeWarning', 'HTTPError', 'NullHandler', 'PreparedRequest', 'Request', 'RequestException', 'Response', 'Session', 'Timeout', 'TooManyRedirects', 'URLRequired', '__author__', '__build__', '__builtins__', '__cached__', '__copyright__', '__doc__', '__file__', '__license__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__title__', '__version__', 'adapters', 'api', 'auth', 'certs', 'codes', 'compat', 'cookies', 'delete', 'exceptions', 'get', 'head', 'hooks', 'logging', 'models', 'options', 'packages', 'patch', 'post', 'put', 'request', 'session', 'sessions', 'status_codes', 'structures', 'utils', 'warnings']
72 |
73 | r = requests.get("http://google.com")
74 | print(r.status_code) # 200, significa que a requisição ocorreu com sucesso
75 | print(r.text) # Retorna o conteúdo HTML da página
76 | print(r.encoding) # ISO-8859-1, codificação usada na página
77 | ```
78 |
79 | Como podem ver, com um rápido download e instalação, temos acesso a uma poderosa biblioteca chamada **requests**, que nos permite fazer requisições **[HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview)** e uma série de outras funcionalidades web.
80 |
81 | ### Removendo um Pacote
82 |
83 | Para desinstalarmos um pacote de nossa máquina podemos usar o comando `uninstall`
84 |
85 | ```
86 | pip uninstall requests
87 | ```
88 |
89 | É necessário confirmarmos a desinstalação com a tecla `y`.
90 |
91 | ### Listando os Pacotes
92 |
93 | Podemos usar o comando `list` para listarmos os pacotes que temos instalado em nossa máquina:
94 |
95 | ```
96 | pip list
97 | ```
98 |
99 | ### Atualizando um Pacote Existente
100 |
101 | O comando `install --upgrade` nos permite atualizar um pacote para sua versão mais recente:
102 |
103 | ```
104 | pip install --upgrade requests
105 | ```
106 |
107 | ### Obtendo Informações
108 |
109 | Através do comando `show` podemos obter informações sobre um determinado pacote:
110 |
111 | ```
112 | pip show requests
113 | ```
114 |
115 | Podemos também fazer pesquisas por **palavras-chave**:
116 |
117 | ```
118 | pip search http
119 | ```
120 |
121 | # Ambientes Virtuais
122 |
123 | O principal propósito dos **Ambientes Virtuais** é criar um ambiente isolado para projetos Python. Isso significa que cada projeto pode ter suas próprias dependências, independente da dependência de outros projetos. Eles são essenciais para evitarmos conflitos de versões de bibliotecas entre os nossos projetos.
124 |
125 | Python, como a maioria das outras linguagens de programação modernas, tem sua própria maneira única de baixar, armazenar e resolver pacotes. Embora isso tenha suas vantagens, algumas decisões interessantes foram tomadas sobre o armazenamento e a resolução de pacotes, o que levou a alguns problemas - especialmente em relação à como e onde os pacotes são armazenados.
126 |
127 | Existem alguns locais diferentes onde esses pacotes podem ser instalados em seu sistema. Por exemplo, a maioria dos pacotes de sistema são armazenados em um diretório filho, no qual o caminho fica armazenado em [sys.prefix](https://docs.python.org/3/library/sys.html#sys.prefix).
128 |
129 | Sendo assim, podemos usar a biblioteca **sys** para sabermos onde `sys.prefix` está apontando:
130 |
131 | ```python
132 | import sys
133 | print(sys.prefix) # /home/akira/anaconda3
134 | ```
135 |
136 | Veja que no meu caso, estou usando anaconda e posso usar este caminho para saber quais pacotes eu tenho instalado com o seguinte comando Linux:
137 |
138 | ```
139 | ls -la /home/akira/anaconda3/lib/python3.7/
140 | ```
141 |
142 | Mas afinal, por que essas informações são relevantes?
143 |
144 | É importante saber isso porque, por padrão, todos os projetos em seu sistema usarão esses mesmos diretórios para armazenar e recuperar pacotes de sites (bibliotecas de terceiros). Inicialmente, isso pode não parecer problemático, e não é realmente, para pacotes de sistema (pacotes que fazem parte da biblioteca Python padrão), mas importa para pacotes de terceiros.
145 |
146 | Considere o seguinte cenário em que você tem dois projetos: **ProjetoA** e **ProjetoB**, ambos os quais dependem da mesma biblioteca, **TimeLib**. O problema se torna aparente quando começamos a exigir versões diferentes do TimeLib. Talvez o ProjectA precise da v1.0.0, enquanto o ProjectB requer a v2.0.0 mais recente, por exemplo.
147 |
148 | Isso irá gerar conflitos e por este motivo os ambientes virtuais são tão importantes!
149 |
150 | Para saber mais detalhes sobre os **Ambientes Virtuais** você pode visitar: **[venv](https://docs.python.org/3/library/venv.html)**
151 |
152 | ## Usando Ambientes Virtuais
153 |
154 | Antes de tudo, devemos instalar a ferramenta `virtualenv` que nos permite trabalhar com ambientes virtuais.
155 |
156 | ```
157 | pip install virtualenv
158 | ```
159 |
160 | Lembrando que se você instalou a versão 3 do Python, é provável que você já o módulo `venv` da biblioteca padrão em seu computador. Agora que você já tem a ferramenta para criar **ambientes virtuais**, vamos criar um novo **diretório** em nossa máquina e navegar até ele através de nossa **interface de linha de comando** e digitar o seguinte comando
161 |
162 | ```
163 | # Para Python 2
164 | virtualenv env
165 |
166 | # Para Python 3
167 | python3 -m venv env
168 | ```
169 |
170 | O comando acima irá criar um diretório chamado `env` (nome arbitrário escolhido por nós) que contém uma estrutura similar a essa:
171 |
172 | ```
173 | ├── bin
174 | │ ├── activate
175 | │ ├── activate.csh
176 | │ ├── activate.fish
177 | │ ├── easy_install
178 | │ ├── easy_install-3.5
179 | │ ├── pip
180 | │ ├── pip3
181 | │ ├── pip3.5
182 | │ ├── python -> python3.5
183 | │ ├── python3 -> python3.5
184 | │ └── python3.5 -> /Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5
185 | ├── include
186 | ├── lib
187 | │ └── python3.5
188 | │ └── site-packages
189 | └── pyvenv.cfg
190 | ```
191 |
192 | Cada *folder* no diretório `env` contém:
193 |
194 | - **bin**: arquivos que interagem com o ambiente virtual
195 | - **include**: Cabeçalhos **C** que compilam os pacotes Python
196 | - **lib**: Uma cópia da versão Python juntamente com o *folder* `site-packages` onde cada dependência está localizada
197 |
198 | ## Ativando um Ambiente Virtual
199 |
200 | Dentro do *folder* **bin** que vimos anteriormente existem **scripts de ativação**, esses scripts são usados para setar nossa **[Shell](https://en.wikipedia.org/wiki/Shell_(computing))** para usar o executável Python do ambiente e os `site-packages`.
201 |
202 | De forma a usarmos os pacotes e recursos de um **ambiente virtual** é necessário que ativemos ele:
203 |
204 | ```
205 | source env/bin/activate
206 | ```
207 |
208 | Ou até mesmo utilizando somente `.`
209 |
210 | ```
211 | . env/bin/activate
212 | ```
213 |
214 | Perceba que ao ativarmos o ambiente virtual, nosso **prompt** de comandos irá se alterar para nos indicar que o ambiente está ligado. Caso você queira desativar o **ambiente virtual** basta digitar:
215 |
216 | ```python
217 | deactivate
218 | ```
219 |
220 | Agora que vimos como **ativar** e **desativar** nosso ambiente virtual, vamos reativá-lo e testá-lo instalando a biblioteca [bcrypt](https://pypi.org/project/bcrypt):
221 |
222 | ```python
223 | pip install bcrypt
224 | ```
225 |
226 | Abra agora o **Python Interactivo** ou um **Script** e vamos testar se a biblioteca está instalada corretamenta:
227 |
228 | ```python
229 | import bcrypt
230 |
231 | bcrypt.hashpw('senha'.encode('utf-8'), bcrypt.gensalt(12))
232 | # b'$2b$12$ZT52zrACwPVFy1ST8UbsKuRQ/LZmhMvmMB7EqchU1VUQTLTi4X7Mu'
233 | ```
234 |
235 | ## Gerando o Arquivo requirements.txt
236 |
237 | O comando `pip freeze` nos permite listar os pacotes que estão instalados em nossa **máquina** ou, caso estejamos em um **ambiente virtual**, os pacotes que nele estão presentes.
238 |
239 | É muito comum existir em projetos o arquivo `requirements.txt` que mostra os pacotes e suas versões necessárias para que o projeto possa funcionar corretamente, também é possível instalar pacotes através do arquivo `requirements.txt`
240 |
241 | Assumindo que estamos em nosso **ambiente virtual** e temos a biblioteca **bcrypt** instalada, vamos executar:
242 |
243 | ```python
244 | pip freeze > requirements.txt
245 | ```
246 |
247 | Ao verificar o contéudo do arquivo **requirements.txt**, encontramos o seguinte:
248 |
249 | ```
250 | bcrypt==3.1.7
251 | cffi==1.12.3
252 | pycparser==2.19
253 | six==1.12.0
254 | ```
255 |
256 | Caso queiramos instalar todos os pacotes contidos nele podemos usar o comando:
257 |
258 | ```python
259 | pip install -r requirements.txt
260 | ```
261 |
262 | ## Outras Alternativas
263 |
264 | Pip é uma ferramenta essencial para todos os Pythonistas e é usada por muitos aplicativos e projetos para gerenciamento de pacotes, ainda sim, existem outras alternativas muito boas que podemos usar em nossos projetos.
265 |
266 | ### Conda
267 |
268 | Conda é um gerenciador de pacotes, dependências e ambientes para muitas linguagens, incluindo Python. Na verdade, sua origem vem do [Anaconda](https://www.anaconda.com/), que começou como um pacote de ciência de dados para Python.
269 |
270 | O Conda é amplamente utilizado para aplicativos de ciência de dados e *Machine Learning*, e usa seu próprio índice para hospedar pacotes compatíveis.
271 |
272 | Conda não apenas permite que você gerencie dependências de pacote, mas também gerencia ambientes virtuais para seus aplicativos, instala distribuições Python compatíveis e empacota seu aplicativo para implantação na produção.
273 |
274 | Além do **pip** e do **ambiente virtual** tradicional que utilizamos anteriormente, também existem outras opções de gerenciadores de pacotes para Python.
275 |
276 | Você pode obter mais detalhes sobre Conda em: https://docs.conda.io/en/latest/
277 |
278 | ### Pipenv
279 |
280 | Pipenv é uma ferramenta que visa trazer o melhor de todos os mundos de pacotes (bundler, composer, npm, cargo, yarn, etc.) para o mundo Python. O Windows é um cidadão de primeira classe no Pipenv.
281 |
282 | Ele cria e gerencia automaticamente um virtualenv para seus projetos, bem como adiciona / remove pacotes de seu Pipfile conforme você instala / desinstala pacotes. Ele também gera o sempre importante `Pipfile.lock`, que é usado para produzir compilações determinísticas.
283 |
284 | Você pode obter mais detalhes sobre ele em: https://pipenv.pypa.io/en/latest/
285 |
--------------------------------------------------------------------------------
/content/introducao.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Introdução'
3 | description: 'Capítulo Introdutório'
4 | ---
5 |
6 | 
7 |
8 | Python é uma linguagem de programação **[interpretada](https://pt.wikipedia.org/wiki/Linguagem_interpretada)**, **[de alto nível](https://pt.wikipedia.org/wiki/Linguagem_de_programação_de_alto_nível)**, que pode ser aplicada em diversas soluções. Famosa por sua sintaxe amigável, ela vem ganhando uma expressiva popularidade nos últimos anos. Foi criada por Guido Van Rossum no
9 | período de 1985-1990, seu código fonte está disponível sob o **GNU General Public License (GPL)**. Python conta com uma **[tipagem dinâmica](https://pt.wikipedia.org/wiki/Sistema_de_tipos)** e um sistema de gerenciamento de memória automático, sendo capaz de suportar múltiplos **[paradigmas de programação](https://pt.wikipedia.org/wiki/Paradigma_de_programação)**.
10 |
11 | Python é uma linguagem poderosa e de fácil aprendizado. Possui **[estruturas de dados](https://pt.wikipedia.org/wiki/Estrutura_de_dados)** eficientes e de alto nível e uma simples e efetiva abordagem em relação à **[programação orientada a objetos](https://pt.wikipedia.org/wiki/Programação_orientada_a_objetos)**. A sintaxe elegante de Python e sua **tipagem dinâmica**, juntamente com sua natureza interpretada, faz do Python uma linguagem ideal para *scripting* e desenvolvimento rápido de aplicações em muitas áreas e para diversas plataformas.
12 |
13 | O **interpretador** Python e a extensiva **[standard library](https://docs.python.org/3/library/)** estão disponíveis gratuitamente na forma *source* ou *binary* para todas as maiores plataformas através do **[site oficial Python](https://www.python.org/)**.
14 |
15 | ## As principais aplicações de Python são:
16 |
17 | - Desenvolvimento web **[(lado do servidor)](https://pt.wikipedia.org/wiki/Server-side)**
18 | - Desenvolvimento de softwares em geral
19 | - Matemática e Computação Científica
20 | - Inteligência Artificial, **[Machine Learning](https://en.wikipedia.org/wiki/Machine_learning)**, **[Deep Learning](https://en.wikipedia.org/wiki/Deep_learning)**
21 | - **[Scripting](https://pt.wikipedia.org/wiki/Linguagem_de_script)** e automação de tarefas repetitivas
22 | - Testes de software
23 |
24 | ## Por que aprender Python?
25 |
26 | - Python é capaz de rodar em múltiplas plataformas (**Windows**, **Linux**, **MacOS**, **Raspberry Pi**, etc)
27 | - Python suporta **programação interativa** (Interação direta com o interpretador)
28 | - Sua sintaxe é simples de compreender
29 | - Suporta múltiplos **[paradigmas de programação](https://pt.wikipedia.org/wiki/Paradigma_de_programação)**
30 | - Python pode ser usada para prototipação rápida
31 | - Python está apta a se conectar com sistemas de **[banco de dados](https://pt.wikipedia.org/wiki/Banco_de_dados)**, pode também ler e modificar arquivos
32 | - Pode ser utilizada para lidar com grandes quantidades de dados e executar cálculos matemáticos complexos
33 | - Python conta com uma comunidade gigantesca e muito material de aprendizado!
34 |
35 | ## Importante
36 |
37 | - A versão mais recente de Python é o Python 3, no qual iremos utilizar nesse guia, porém a versão Python 2 ainda é muito popular, embora não esteja mais recebendo suporte da **Python Software Foundation**
38 | - Python pode ser integrada com **C**, **C++**, **CORBA**, **Java**. Caso haja a necessidade de trabalhar com códigos de alta perfomance
39 | - Atualmente muitas das grandes corporações utilizam Python, podemos citar elas: **Google**, **Facebook**, **Microsoft**, **NASA**, **CERN**.
40 |
41 | # Computação
42 |
43 | 
44 |
45 | Antes de iniciarmos nossos estudos sobre a linguagem Python, é importante que tenhamos uma breve Introdução à Computação.
46 |
47 | A Computação é qualquer tipo de cálculo que inclui etapas aritméticas e não-aritméticas e que segue um modelo bem definido (por exemplo, um [algoritmo](https://en.wikipedia.org/wiki/Algorithm)).
48 |
49 | Dispositivos mecânicos ou eletrônicos (ou, historicamente, pessoas) que realizam cálculos são conhecidos como computadores. Uma disciplina especialmente conhecida do estudo da computação é a [ciência da computação](https://en.wikipedia.org/wiki/Computer_science).
50 |
51 | A Computação pode ser vista como um fenômeno puramente físico que ocorre dentro de um [sistema físico](https://en.wikipedia.org/wiki/Physical_system) fechado chamado computador. Exemplos de tais sistemas físicos incluem computadores digitais, computadores mecânicos, computadores quânticos, computadores de DNA, computadores moleculares ou até mesmo computadores analógicos. Esse ponto de vista foi adotado pela [física da computação](https://en.wikipedia.org/wiki/Physics_of_computation), um ramo da física teórica, bem como pelo campo da [computação natural](https://en.wikipedia.org/wiki/Natural_computing).
52 |
53 | Um ponto de vista ainda mais radical, o [pancomputacionalismo](https://en.wikipedia.org/wiki/Pancomputationalism), é o postulado da [física digital](https://en.wikipedia.org/wiki/Digital_physics) que argumenta que a evolução do universo é em si uma computação.
54 |
55 | ## Computação na Prática
56 |
57 | Programação de computador é o processo de escrever instruções que são executadas por computadores. As instruções, também conhecidas como código, são escritas em uma linguagem de programação que o computador pode entender e usar para realizar uma tarefa ou resolver um problema.
58 |
59 | Para que possamos escrever programas de qualidade e eficientes, é importante que conheçamos conceitos como:
60 |
61 | - Representação de conhecimento através de **Estruturas de Dados**
62 | - **Iteração** e **Recursão** como metáforas computacionais
63 | - **Abstração** de procedimentos e tipos de dados
64 | - **Organizar** e **Modularizar** sistemas utilizando objetos [classes](https://docs.python.org/3/tutorial/classes.html) e métodos
65 | - Diferentes classes de **algoritmos** ([searching](https://en.wikipedia.org/wiki/Search_algorithm), [sorting](https://en.wikipedia.org/wiki/Sorting_algorithm))
66 | - **Complexidade** de algoritmos
67 |
68 | ## O que um Computador faz?
69 |
70 | Fundamentalmente ele é capaz de realizar cálculos (bilhões de cálculos por segundo) e também é capaz de lembrar resultados (centenas de gigabytes de storage).
71 |
72 | Quais tipos de cálculos ele pode executar? Um computador pode executar cálculos que são **pré-construídos** na linguagem e também aqueles que você define como programador. É importante lembrarmos que **Computadores** apenas sabem o que dizemos a eles, então é importante que forneçamos as instruções corretas para que possamos obter os resultados desejados.
73 |
74 | ## Tipos de Conhecimento
75 |
76 | Em [epistemologia](https://en.wikipedia.org/wiki/Epistemology), conhecimento descritivo, também conhecido como **Conhecimento Declarativo** é uma afirmação de um fato, em outras palavras, é o conhecimento que pode ser expresso em uma frase declarativa ou uma proposição indicativa (por exemplo: "Está chovendo lá fora").
77 |
78 | Conhecimento processual, também conhecido como **Conhecimento Imperativo** é uma **receita** ou "tutorial", é o conhecimento exercido no desempenho de alguma tarefa.
79 |
80 | Podemos considerar um algoritmo, por exemplo:
81 |
82 | - Ler um número
83 | - Verificar se ele é maior que **0**
84 | - Se o número for maior que **0**, retornar que ele é **positivo**
85 | - Verificar se ele é menor que **0**
86 | - Se o número for menor que **0**, retornar que ele é **negativo**
87 | - Se nenhum dos casos acima for atendido, então ele é **0**.
88 | - Fim do algoritmo
89 |
90 | O fluxograma a seguir nos apresenta esta ideia visualmente:
91 |
92 | 
93 |
94 | ## Calculando a Raiz Quadrada
95 |
96 | Na matemática, a raiz quadrada de um número **x** é um número **y** tal que `y² = x`. Em outras palavras, um número **y** cujo quadrado (o resultado da multiplicação do número por ele mesmo, ou `y*y`) é x.
97 |
98 | Vamos então definir que:
99 |
100 | - A raiz quadrada de um número **x** é **y** de forma que `y*y = x`
101 |
102 | - A receita para deduzir a raiz quadrada de um número **x** é:
103 |
104 | 1. Começar com uma suposição **g**
105 | 2. Se `g*g` é próximo o suficiente de **x**, pare e diga que **g** é a resposta
106 | 3. Caso contrário faça uma nova suposição calculando a média de **g** e **x/g**
107 | 4. Utilizando a nova suposição, repita o processo até se aproximar
108 |
109 | Neste exemplo, queremos obter a raiz quadrada do número **16**, que é **4**, veja que através do nosso algoritmo somos capazes de alcançar um número muito próximo de **4**.
110 |
111 | | `g` | `g*g` | `x/g` |`(g+x/g)/2`|
112 | |--------|---------|-------|-----------|
113 | | 3 | 9 | 16/3 | 4.17 |
114 | | 4.17 | 17.36 | 3.837 | 4.0035 |
115 | | **4.0035** | 16.0277 | 3.997 | 4.000002 |
116 |
117 | ## O que é uma Receita?
118 |
119 | Uma receita é um conjunto de instruções que descreve como preparar ou fazer algo, em outras palavras:
120 |
121 | - Uma sequência de simples passos
122 | - Processo de **Controle de Fluxo** que específica quando cada passo é executado
123 | - Um meio de determinar quando parar
124 |
125 | 1+5+7 = UM **ALGORITMO**!
126 |
127 | ## Computadores são Máquinas
128 |
129 | Um computador é uma máquina que pode ser instruída a realizar sequências de operações aritméticas ou lógicas automaticamente por meio de programação de computador. Os computadores modernos têm a capacidade de seguir conjuntos generalizados de operações, chamados programas.
130 |
131 | Existem diversos tipos de computadores, por exemplo:
132 |
133 | - Computador de **Programa Fixo**: Calculadora
134 | - Computador de **Programa Armazenado**: A máquina armazena e executa instruções
135 |
136 | ## Arquitetura Básica do Computador
137 |
138 | 
139 |
140 | ## Computador de Programa Armazenado
141 |
142 | Um computador de programa armazenado é aquele que armazena instruções do programa em uma memória acessível eletronicamente ou opticamente. Isso contrasta com os sistemas que armazenavam as instruções do programa com plugboards ou mecanismos semelhantes.
143 |
144 | A Sequência de Instruções são então armazenadas dentro do computador. Construídos através de um conjunto pré-definido de instruções primitivas:
145 |
146 | 1. Aritmética e Lógica
147 | 2. Testes simples
148 | 3. Movendo dados
149 |
150 | Um Programa Especial (Interpretador) **executa cada instrução em ordem** e pode ser usado em testes para alterar o fluxo de controle.
151 |
152 | ## Primitivos Básicos
153 |
154 | Na computação, primitivos de linguagem são os elementos mais simples disponíveis em uma linguagem de programação. Um primitivo é a menor 'unidade de processamento' disponível para um programador de uma determinada máquina, ou pode ser um elemento atômico de uma expressão em uma linguagem.
155 |
156 | Um primitivo é um tipo de dados fundamental que não pode ser dividido em um tipo de dados mais simples. Por exemplo, um **inteiro** é um tipo de dados primitivo, enquanto que um **array**, que pode armazenar vários tipos de dados, não é.
157 |
158 | - Turing mostrou que podemos **computar tudo** utilizando apenas 6 primitivos
159 | - Linguagens de programação modernas possuem conjuntos de primitivos mais convenientes
160 | - É possível abstrair métodos para criar **novos primitivos**
161 | - Qualquer cálculo computável em uma linguagem é computável em qualquer outra linguagem de programação
162 |
163 | ## Criando Receitas
164 |
165 | Uma linguagem de programação fornece um conjunto de **operações** primitivas. **Expressões** são complexas combinações legais de primitivos em uma linguagem de programação. Expressões e Computações possuem **valores** e **sentido** em uma linguagem de programação
166 |
167 | ## Aspectos das Linguagens
168 |
169 | As linguagens possuem **Constructos Primitivos**, em português, por exemplo, temos as **palavras**, nas linguagens de programação temos os **números**, **strings** e **operadores simples**.
170 |
171 | Elas também possuem uma **Sintaxe**, por exemplo, em português podemos construir a seguinte frase "gato caxorro garoto", que é inválida sintaticamente, também podemos construir "mãe abraça o garoto", que é válida sintaticamente. Nas linguagens de programação existem as mesmas situações, por exemplo `"oi"5` é uma definição inválida em termos de sintaxe, porém `3*5` é válido, pois define a multiplicação de dois números de maneira correta, veja que aqui estamos usando um exemplo geral e não estamos falando de uma linguagem específica.
172 |
173 | Além disso, as linguagens também possuem a **Semântica Estática**, no qual strings sintaticamente válidas possuem sentido, no português, por exemplo, podemos definir "Eu árvore fome", embora seja uma expressão valida sintaticamente, ela tem erro de semântica, pois não há sentido no que se quer dizer. Nas linguagens de programação temos o mesmo problema, se definirmos por exemplo `3+"oi"` teremos um erro semântico, pois esta soma não faz sentido.
174 |
175 | A **Semântica** é então o sentido associado com uma string de símbolos sintaticamente correta com nenhum erro de semântica.
176 |
177 | ## Quando Ocorrem Erros
178 |
179 | Erros são os problemas ou falhas no programa que fazem com que nosso programa se comporte de forma inesperada, existem diversos tipos de erros, podemos citar por exemplo:
180 |
181 | - Erros de Sintáxe: Comuns e fáceis de perceber
182 | - Erros de Semântica Estática: Algumas linguagens checam por eles antes de rodar o programa, eles podem causar comportamento imprevisível
183 | - Nenhum erro de Semântica, porém um sentido diferente do que o programador desejava expressar ocorre: Programa crasha, para de rodar, programa roda para sempre, programa dá uma resposta, porém diferente do esperado
184 |
185 | ## Programas em Python
186 |
187 | Um programa é uma sequência de definições e comandos, estas definições devem ser bem avaliadas. Também podemos considerar ele como comandos executados pelo Interpretador Python em uma shell, comandos (afirmações) instruem o interpretador a fazerem algo e podem ser digitados diretamente em uma shell ou guardados em um arquivo que é então lido na shell e avaliado.
188 |
189 | ## Objetos
190 |
191 | Python é uma linguagem de programação orientada a objetos. Quase tudo em Python é um objeto, com suas propriedades e métodos.
192 |
193 | 
194 |
195 | Devemos estar cientes da importância dos Objetos, pois programas manipulam **objetos de dados**. Objetos possuem um **tipo** que define os tipos de ações que os programas podem fazer com eles, por exemplo:
196 |
197 | - Gabriel é um humano, sendo assim ele pode caminhar, falar, etc.
198 | - Zeus é um cachorro, sendo assim ele pode latir, rosnar, etc.
199 |
200 | Objetos são normalmente divididos em duas categorias:
201 |
202 | - Escalares (não podem ser subdivididos)
203 | - Não-Escalares (possui uma estrutura interna que pode ser acessada)
204 |
205 | Agora que temos informações fundamentais básicas sobre princípios da computação e da linguagem **Python**, podemos iniciar a configuração de nosso Ambiente de Programação.
206 |
--------------------------------------------------------------------------------
/content/expressoes-regulares.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Expressões Regulares'
3 | description: 'Aprenda sobre Expressões Regulares'
4 | ---
5 |
6 | **Expressões regulares** são um mecanismo muito poderoso para manipulação de **strings**, também conhecido como **regex** ou **regexp**, é um campo de estudo muito abrangente na **ciência da computação teórica** e **linguagens formais**.
7 |
8 | Pode-se dizer que é uma sequência de caracteres que define um padrão de busca, normalmente este padrão é usado por algoritmos de busca de strings, onde é feito uma busca por determinado padrão, seja para encontrá-lo ou até mesmo encontrá-lo e alterá-lo, também é muito usado para *validação de input de dados*.
9 |
10 | O conceito surgiu na década de 1950, quando o matemático americano [Stephen Cole Kleene](https://en.wikipedia.org/wiki/Stephen_Cole_Kleene) formalizou a descrição de uma [linguagem regular](https://en.wikipedia.org/wiki/Regular_language). O conceito entrou em uso comum com utilitários de processamento de texto do Unix. Diferentes sintaxes para escrever expressões regulares existem desde a década de 1980, sendo uma o padrão [POSIX](https://en.wikipedia.org/wiki/POSIX) e outra, amplamente utilizada, a sintaxe [Perl](https://en.wikipedia.org/wiki/Perl).
11 |
12 | Expressões regulares são usadas em [search engines](https://en.wikipedia.org/wiki/Search_engine), *search and replace dialogs* de processadores de texto e editores de texto, em utilitários de processamento de texto como [sed](https://en.wikipedia.org/wiki/Sed) e [AWK](https://en.wikipedia.org/wiki/AWK) e em análise lexical. Muitas linguagens de programação fornecem recursos de regex integrados ou por meio de bibliotecas, como é o caso da linguagem Python que nos oferece a biblioteca [re](https://docs.python.org/3/library/re.html).
13 |
14 | ## Introdução
15 |
16 | Uma expressão regular, geralmente chamada de padrão, especifica um conjunto de strings necessárias para um propósito específico. Uma maneira simples de especificar um conjunto finito de strings é listar seus elementos ou membros. No entanto, muitas vezes existem maneiras mais concisas, por exemplo, o conjunto contendo as três cadeias de caracteres "Handel", "Händel" e "Haendel" pode ser especificado pelo padrão `H(ä|ae?)Ndel`, dizemos que esse padrão corresponde a cada uma das três strings. Na maioria dos formalismos, se existe pelo menos uma expressão regular que corresponde a um determinado conjunto, então existe um número infinito de outras expressões regulares que também correspondem a ela - a especificação não é única.
17 |
18 | **Âncoras**: `^` e `$`
19 |
20 | | Exemplo | Descrição | URL |
21 | |----------|------------------------------------------------|------------------------------------|
22 | | ^Py | Encontra qualquer string que comece com Py | **https://regex101.com/r/cO8lqs/4303** |
23 | | on$ | Encontra uma string que termina com on | **https://regex101.com/r/cO8lqs/4304** |
24 | | ^Python$ | Encontra a string Python | **https://regex101.com/r/cO8lqs/4305** |
25 | | Python | Encontra qualquer string que tenha Python em si | **https://regex101.com/r/cO8lqs/23892** |
26 |
27 | **Quantificadores**: `*`, `+`, `?` e `{}`
28 |
29 | | Exemplo | Descrição |
30 | |------------|-------------------------------------------------------------------------------------|
31 | | abc* | Encontra uma string que tenha ab seguido por zero ou mais c |
32 | | abc+ | Encontra uma string que tenha ab seguido por um ou mais c |
33 | | abc? | Encontra uma string que tenha ab seguido por zero, ou um c |
34 | | abc{2} | Encontra uma string que tenha ab seguido por dois c |
35 | | abc{2,} | Encontra uma string que tenha ab seguido por dois ou mais c |
36 | | abc{2,5} | Encontra uma string que tenha ab seguido por 2 até no máximo 5 c |
37 | | a(bc)* | Encontra uma string que tenha a seguido por zero ou mais cópias da sequência bc |
38 | | a(bc){2,5} | Encontra uma string que tenha a seguido por 2 até no máximo 5 cópias da sequência bc |
39 |
40 | **Operador OU**: `|` e `[]`
41 |
42 | | Exemplo | Descrição |
43 | |---------|-----------------------------------------------------------------------------------|
44 | | a(b\|c) | Encontra uma string que tenha a seguido por b ou c |
45 | | a[bc] | Igual o anterior, ambas as notações podem ser usadas e produzem o mesmo resultado |
46 |
47 | **Classes de caracteres**: `\d`, `\w`, `\s` e `.`
48 |
49 | | Exemplo | Descrição |
50 | |---------|-------------------------------------------------------------------------|
51 | | \d | Encontra um único caracter que seja um dígito |
52 | | \w | Encontra um caracter de palavra (caracter alfanumérico e underline) |
53 | | \s | Encontra caracteres de espaço em branco (incluindo tabs e quebra de linha) |
54 | | . | Encontra qualquer caracter |
55 |
56 | **Negação de classe de caracteres**: `\D`, `\W`, `\S`
57 |
58 | | Exemplo | Descrição |
59 | |---------|-----------------------------------------------------------|
60 | | \D | Faz a operação inversa de \d e traz todos os não-dígitos |
61 | | \W | Faz a operação inversa de \w e traz todas as não-palavras |
62 | | \S | Faz a operação inversa de \s e traz todos os não-espaços |
63 |
64 | Outro ponto importante, é caso queiramos dar **escape**, por exemplo validar um `.`, para isso usamos o `\.`
65 |
66 | O mesmo vale caso seja necessário validarmos `$`, utilizamos `\$`
67 |
68 | Experimente mais opções de expressões em **[Regex101](https://regex101.com/r/cO8lqs/1)**
69 |
70 | ## Expressões Regulares em Python
71 |
72 | Python já possui incluído o módulo **re** que utilizaremos para nossas **expressões regulares**, este módulo fornece operações de correspondência de expressões regulares semelhantes às encontradas em Perl.
73 |
74 | Para usá-lo precisamos importá-lo, sem a necessidade de instalação, vamos também inspecionar o módulo para termos uma visão do que ele nos disponibiliza em termos de atributos e métodos.
75 |
76 | ```python
77 | import re
78 |
79 | print(dir(re))
80 | # ['A', 'ASCII', 'DEBUG', 'DOTALL', 'I', 'IGNORECASE', 'L', 'LOCALE', 'M', 'MULTILINE', 'S', 'Scanner', 'T', 'TEMPLATE', 'U', 'UNICODE', 'VERBOSE', 'X', '_MAXCACHE', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', '_alphanum_bytes', '_alphanum_str', '_cache', '_cache_repl', '_compile', '_compile_repl', '_expand', '_locale', '_pattern_type', '_pickle', '_subx', 'compile', 'copyreg', 'error', 'escape', 'findall', 'finditer', 'fullmatch', 'match', 'purge', 'search', 'split', 'sre_compile', 'sre_parse', 'sub', 'subn', 'sys', 'template']
81 | ```
82 |
83 | Veja que temos bastantes opções para trabalharmos, inicialmente vamos ver os métodos mais relevantes através de diversos exemplos, mas primeiramente é importante entendermos o conceito de *raw string*, pois são elas que vamos utilizar em nossas expressões regulares.
84 |
85 | Uma *raw string* do Python é uma string normal, prefixada com **r** ou **R**. Isso trata caracteres como barra invertida (`\`) como um caractere literal. Isso também significa que esse caractere não será tratado como um caractere de escape, por exemplo:
86 |
87 | ```python
88 | print('Hello\nWorld')
89 | # Hello
90 | # World
91 | ```
92 |
93 | Veja que o *output* é tratado como esperado, o escape caracter `\n` é interpretado como uma quebra de linha, já no caso de uma *raw string*, ele será tratado como um caractere literal:
94 |
95 | ```python
96 | print(r'Hello\nWorld') # Hello\nWorld
97 | ```
98 |
99 | Agora que sabemos como as *raw strings* funcionam, vamos ver os métodos de expressões regulares.
100 |
101 | ### findall()
102 |
103 | O método **findall()** retorna todas as porções correspondidas como uma lista de strings. Ele conta com os seguintes argumentos:
104 |
105 | - padrão
106 | - string
107 | - flags
108 |
109 | O primeiro argumento é o padrão que desejamos testar e extrair em relação à string de *input*, que é o segundo argumento. O último argumento flags é opcional. Vamos então aos exemplos para uma melhor compreensão:
110 |
111 | ```python
112 | resultados = re.findall(r'ab*c', 'abc ac adc abbbc abbb')
113 | print(resultados) # ['abc', 'ac', 'abbbc']
114 | ```
115 |
116 | No exemplo acima usamos o quantificador `*`, que indica 0 ou mais **b**'s.
117 |
118 | ```python
119 | resultados = re.findall(r'ab+c', 'abc ac adc abbbc abbb')
120 | print(resultados) # ['abc', 'abbbc']
121 | ```
122 |
123 | No exemplo acima usamos o quantificador `+`, que indica 1 ou mais **b**'s.
124 |
125 | Vejamos como podemos definir uma expressão regular para encontrar caracteres de palavras:
126 |
127 | ```python
128 | import re
129 |
130 | x = "Expressões regulares são legais"
131 | r = re.findall(r"\w+", x)
132 | print(r) # ['Expressões', 'regulares', 'são', 'legais']
133 | ```
134 |
135 | Como podemos ver, todos os caracteres da sentença foram correspondidos e recebemos uma lista deles.
136 |
137 | ### split()
138 |
139 | O método **split()** divida a string pelas ocorrências do padrão.
140 |
141 | ```python
142 | import re
143 |
144 | e = "Eu sou uma expressao com diversas palavras"
145 | r = re.split(r'\s', e)
146 | print(r) # ['Eu', 'sou', 'uma', 'expressao', 'com', 'diversas', 'palavras']
147 | ```
148 |
149 | Como podemos ver, a função **split()** separou a expressão em uma lista de palavras, usando o separador `\s` que representa o espaço em branco.
150 |
151 | Vamos agora usar um dígito como separador:
152 |
153 | ```python
154 | string = 'um:1 dois:2 quinze:15 trinta:30'
155 | padrao = r'\d+'
156 | resultado = re.split(padrao, string)
157 | print(resultado) # ['um:', ' dois:', ' quinze:', ' trinta:', '']
158 | ```
159 |
160 | ### search()
161 |
162 | Normalmente, usamos o operador **in** para testar se uma string faz parte de outra string ou não. Para expressões regulares, usamos a função **search()** cuja lista de argumentos é mostrada abaixo:
163 |
164 | - padrão
165 | - string
166 | - flags
167 |
168 | O primeiro argumento é o padrão de expressão regular que você deseja testar contra a string de *input*, que é o segundo argumento, flags é opcional, ajuda a alterar o comportamento padrão dos padrões de expressões regulares.
169 |
170 | Como uma boa prática, é interessante usar *raw strings* para construir o padrão de expressão regular. Vejamos então alguns exemplos:
171 |
172 | ```python
173 | import re
174 |
175 | sentenca = "esta é uma string"
176 |
177 | print('esta' in sentenca) # True
178 | print('este' in sentenca) # False
179 |
180 | print(bool(re.search(r'esta',sentenca))) # True
181 | print(bool(re.search(r'este',sentenca))) # False
182 | print(type(re.search(r'esta',sentenca))) #
183 | print(type(re.search(r'este',sentenca))) #
184 | ```
185 |
186 | O valor de retorno da função **search()** é um objeto `re.Match` quando há uma correspondência, caso contrário o resultado é `NoneType`.
187 |
188 | Vejamos agora um exemplo usando o argumento flags:
189 |
190 | ```python
191 | print(bool(re.search(r'Esta',sentenca))) # False
192 | print(bool(re.search(r'Esta',sentenca, flags=re.I))) # True
193 | ```
194 |
195 | A flag `re.I` significa **IGNORECASE** é uma flag para permitir correspondência sem distinção entre maiúsculas e minúsculas.
196 |
197 | Vejamos agora um exemplo com expressões geradoras:
198 |
199 | ```python
200 | palavras = ['cachorro','macarrão','macaco']
201 |
202 | [p for p in palavras if re.search(r'rr',p)] # ['cachorro', 'macarrão']
203 | all(re.search(r'ca',p) for p in palavras) # True
204 | any(re.search(r'xa',p) for p in palavras) # False
205 | ```
206 |
207 | Vejamos agora como podemos utilizar um quantificador em nossa padrão:
208 |
209 | ```python
210 | import re
211 |
212 | padrao = "a*b"
213 | r = re.search(padrao, "aaaaaaabcedefg")
214 | print(r) # <_sre.SRE_Match object; span=(0, 8), match='aaaaaaab'>
215 | print(r.group()) # aaaaaaab
216 | ```
217 |
218 | Como podemos ver, primeiro nos foi retornado um **objeto match**, posteriormente acessamos a string encontrada através do método **group()** que nos traz o resultado, também podemos aplicar métodos como **start()**, **end()** e **span()**.
219 |
220 | ### sub()
221 |
222 | Para busca e substituição normais, podemos usar o método **str.replace()**. Para expressões regulares, usamos a função **sub()**, cuja lista de argumentos é mostrada abaixo:
223 |
224 | - padrão
225 | - substituição
226 | - string
227 | - count
228 | - flags
229 |
230 | O primeiro argumento é o padrão de expressão regular a ser correspondido em relação à string de *input*, que é o terceiro argumento. O segundo argumento específica a string que irá substituir as porções correspondidas pelo padrão da expressão regular. Os últimos dois argumentos são opcionais. Para entendermos melhor este conceito, vamos ao exemplo:
231 |
232 | ```python
233 | frase = 'eu gosto de pizza'
234 |
235 | print(re.sub(r'z','Z',frase)) # eu gosto de piZZa
236 | print(re.sub(r'z','Z',frase,count=1)) # eu gosto de piZza
237 | ```
238 |
239 | Observe que o argumento **count** limita o número de substituições.
240 |
241 | ### Compilando Expressões Regulares
242 |
243 | Expressões Regulares podem ser compiladas usando a função **compile()**, que nos retorna um objeto `re.Pattern`.
244 |
245 | As funções do módulo **re** de nível superior estão todas disponíveis como métodos para tais objetos. Compilando uma expressão regular é útil se ela tiver que ser usada em vários lugares ou chamada em vários vezes dentro de um loop (benefício de velocidade).
246 |
247 | Vamos começar compilando uma expressão regular:
248 |
249 | ```python
250 | animal = re.compile(r'gato')
251 | print(type(animal)) #
252 | ```
253 |
254 | Usaremos agora o o método **search()** no padrão definido por nós para buscar pelo padrão em uma determinada string:
255 |
256 | ```python
257 | bool(animal.search('o gato é bonito')) # True
258 | bool(animal.search('o rato é roedor')) # False
259 | ```
260 |
261 | Também podemos usar o método **sub** neste padrão, de forma a executar substituções:
262 |
263 | ```python
264 | animal.sub('rato','o gato fugiu do cachorro')
265 | # 'o rato fugiu do cachorro'
266 | ```
267 |
268 | ### match()
269 |
270 | O método **match()** funciona da seguinte forma: Se zero ou mais caracteres no início da string corresponderem a expressão regular informada, retorna um objeto de `re.Match` correspondente. Retorna `None` se a string não corresponder ao padrão.
271 |
272 | Neste exemplo vamos usar um padrão simples para darmos **match** em um email:
273 |
274 | ```python
275 | import re
276 |
277 | padrao = r"\w+@(\w+\.)+(com|org|net)"
278 | r = re.match(padrao,"teste@teste.org")
279 | print(r) #
280 | print(r.group()) # teste@teste.org
281 | ```
282 |
283 | Vimos que nesse caso, foi possível dar match no e-mail `teste@teste.org`, nos mostrando assim a relevância e importância das expressões regulares dentro da computação, um assunto relevante e de compreensão necessária, pois está presente em praticamente todas as linguagens de programação e sua aplicabilidade é muito vasta.
284 |
--------------------------------------------------------------------------------
/content/modulos.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Módulos'
3 | description: 'Aprenda a trabalhar com módulos'
4 | ---
5 |
6 | **Módulo** é um arquivo que contém definições e comandos/instruções **Python**.
7 |
8 | Um módulo pode conter tanto instruções executáveis quanto definições de funções e classes. Essas instruções servem para inicializar o módulo. Eles são executados somente na primeira vez que o módulo é encontrado em uma instrução de importação.
9 |
10 | Podemos dizer que os **módulos** são **bibliotecas** que podem nos ajudar com funções definidas para uso imediato, em outras palavras, para usarmos um módulo devemos compreender como utilizar suas **funções**, sem a necessidade de mergulharmos em **detalhes específicos** de implementação.
11 |
12 | ### Intuição dos Módulos
13 |
14 | Também podemos imaginar um módulo como um conjunto de ferramentas disponíveis para usarmos para solucionar determinados problemas.
15 |
16 | A figura a seguir ilustra esta ideia, onde temos um módulo chamado de **ferramentas**:
17 |
18 | 
19 |
20 | Imagine agora que desejamos importar todas as ferramentas do módulo **ferramentas**, para isso, podemos usar o seguinte comando:
21 |
22 | ```python
23 | import ferramentas
24 | ```
25 |
26 | Agora pense em uma situação em que desejamos apenas importar uma ferramenta específica. Podemos expressar essa ideia da seguinte forma:
27 |
28 | ```python
29 | from ferramentas import martelo
30 | ```
31 |
32 | Também podemos importar mais de uma ferramenta, separando-as por vírgula:
33 |
34 | ```python
35 | from ferramentas import tesoura, alicate
36 | ```
37 |
38 | Uma outra maneira de obtermos todas as ferramentas é usando o `*`, neste caso, expressamos da seguinte forma:
39 |
40 | ```python
41 | from ferramentas import *
42 | ```
43 |
44 | Dessa forma temos todas as ferramentas em mãos e não precisamos usar o prefixo ferramentas quando desejarmos usá-las.
45 |
46 | ### Definindo Módulos
47 |
48 | Vejamos agora como estes conceitos funcionam na prática, para isso vamos definir duas simples funções:
49 |
50 | ```python
51 | def add(x, y):
52 | """Recebe dois números x e y e retorna sua soma"""
53 | return x + y
54 |
55 | def multiply(x, y):
56 | """Recebe dois números x e y e retorna sua multiplicação"""
57 | return x * y
58 | ```
59 |
60 | Salvamos ambas as funções em um arquivo de nome `modulo.py`, agora vamos criar um **novo arquivo** no mesmo diretório e **importaremos** nosso módulo para utilizá-lo:
61 |
62 | ```python
63 | import modulo
64 |
65 | print(modulo.add(4,5)) # 9
66 | print(modulo.multiply(3,3)) # 9
67 | ```
68 |
69 | Veja que utilizamos o comando **import** para buscarmos o nosso módulo e posteriormente **invocamos** as funções dele prefixando elas com a palavra **modulo**.
70 |
71 | ### Importando Módulos
72 |
73 | Imagine agora que temos um módulo chamado **matematica**. Os principais formatos para **importarmos** nossos módulos são:
74 |
75 | ```python
76 | import matematica
77 | ```
78 |
79 | - Tudo que está no módulo **matematica** é importado
80 | - Para se referir aos métodos de matematica, adicionamos o prefixo "matematica" em frente ao seu nome
81 |
82 | ```python
83 | matematica.nomeclasse.metodo()
84 | matematica.funcao()
85 | ```
86 |
87 | Importando usando o asterisco `*`:
88 |
89 | ```python
90 | from matematica import *
91 | ```
92 |
93 | - Tudo no módulo matematica é importado
94 | - Para se referir a qualquer método no módulo, basta usar seu nome, sem precisarmos prefixar
95 | - Lembre de ter atenção ao usar esse tipo de import, pois ele pode sobrescrever a definição de uma variável ou função já existente
96 |
97 | ```python
98 | nomeclasse.metodo()
99 | funcao()
100 | ```
101 |
102 | Importando uma classe ou função específica:
103 |
104 | ```python
105 | from matematica import nomeclasse
106 | ```
107 |
108 | - Apenas o item **nomeclasse** será importado
109 | - Após importar **nomeclasse** você pode usar ele sem o prefixo do módulo, ele é colocado no namespace atual
110 | - Tome cuidado ao usar, pois pode sobrescrever a definição do nome, caso ele já esteja no namespace
111 |
112 | ```python
113 | nomeclasse.metodo()
114 | funcao()
115 | ```
116 |
117 | Além de funções, os módulos também podem conter variáveis e estruturas de dados (listas, tuplas, dicionários, objetos). Vamos então criar mais um módulo para testarmos, nomearemos o nosso arquivo como `estudantes.py`.
118 |
119 | ```python
120 | estudantes = [
121 | {'nome':'Uriel','idade':27,'aprovado':True},
122 | {'nome':'Emanuel','idade':25,'aprovado':True},
123 | {'nome':'Malthael','idade':29,'aprovado':False}
124 | ]
125 |
126 | def imprimir_aprovados():
127 | for estudante in estudantes:
128 | if estudante['aprovado']:
129 | print(f'{estudante["nome"]} está aprovado')
130 | ```
131 |
132 | Iremos agora importar o módulo **estudantes** e podemos acessar a lista de dicionários **estudantes**, perceba que fornecemos o mesmo nome para ambos, mas isso é uma escolha livre que temos. Também temos acesso a função para imprimir os estudantes que estão aprovados.
133 |
134 | ```python
135 | from estudantes import *
136 |
137 | estudante = estudantes[2]['nome']
138 | print(estudante) # Malthael
139 | ```
140 |
141 | Vamos agora invocar a função **imprimir()** para vermos quais estudantes estão aprovados:
142 |
143 | ```python
144 | imprimir()
145 | # Uriel está aprovado
146 | # Emanuel está aprovado
147 | ```
148 |
149 | Observe que usamos o `*` para importar o módulo por completo, por este motivo não foi necessário prefixarmos a função imprimir da seguinte forma `estudantes.imprimir()`.
150 |
151 | ### Nomeando um Módulo
152 |
153 | Podemos dar um apelido para um módulo, tornando-o mais fácil de nos referirmos a ele, para isso usamos a palavra-chave **as**:
154 |
155 | ```python
156 | import estudantes as e
157 |
158 | print(e.estudantes[0]['idade']) # 27
159 | e.imprimir()
160 | # Uriel está aprovado
161 | # Emanuel está aprovado
162 | ```
163 |
164 | ### Módulos Construídos do Python
165 |
166 | Existem diversos módulos que já são construídos no Python e nós podemos importá-los quando quisermos sem a necessidade de instalação.
167 |
168 | #### Módulo platform
169 |
170 | O módulo [platform](https://docs.python.org/3/library/platform.html) nos permite o acesso aos dados de identificação da plataforma subjacente.
171 |
172 | ```python
173 | import platform
174 |
175 | s = platform.system()
176 | print(s) # Linux
177 | ```
178 |
179 | #### A função **dir()**
180 |
181 | Existe uma função muito importante chamada **dir()** que lista todos os nomes das funções (e nome de atributos e variáveis) no módulo.
182 |
183 | Vamos testá-la com o módulo de [math](https://docs.python.org/3/library/math.html):
184 |
185 | ```python
186 | import math
187 |
188 | conteudo = dir(math)
189 | print(conteudo) # ['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']
190 | ```
191 |
192 | Observe que nos é retornado uma grande quantidade de opções, entre atributos e funções, vejamos como podemos usar algumas delas.
193 |
194 | Calculando a raiz quadrada de um número:
195 |
196 | ```python
197 | print(math.sqrt(4)) # 2.0
198 | ```
199 |
200 | Calculando o logaritmo na base 2 de um número:
201 |
202 | ```python
203 | print(math.log2(8)) # 3.0
204 | ```
205 |
206 | Calculando o logaritmo na base 10 de um número:
207 |
208 | ```python
209 | math.log10(100) # 2.0
210 | ```
211 |
212 | Calculando o máximo divisor comum entre dois números:
213 |
214 | ```python
215 | math.gcd(50,85) # 5
216 | ```
217 |
218 | Obtendo os valores de **pi** e **e**:
219 |
220 | ```python
221 | print(math.e) # 2.718281828459045
222 | print(math.pi) # 3.141592653589793
223 | ```
224 |
225 | #### Módulo collections
226 |
227 | Este módulo implementa tipos de dados de contêiner especializados, fornecendo alternativas aos contêineres integrados de uso geral do Python, **dict**, **list**, **set** e **tuple**.
228 |
229 | Imagine que temos por exemplo uma lista com diversos itens repetidos:
230 |
231 | ```python
232 | x = [1,1,1,2,2,3,3,5,9,9]
233 | ```
234 |
235 | Desejamos contar o número de ocorrências de cada elemento desta lista, podemos usar o **Counter** do módulo [collections](https://docs.python.org/3/library/collections.html):
236 |
237 | ```python
238 | from collections import Counter
239 |
240 | Counter(x) # Counter({1: 3, 2: 2, 3: 2, 9: 2, 5: 1})
241 | ```
242 |
243 | Um Counter é uma subclasse de **dict** para a contagem de objetos hashable. É uma coleção onde os elementos são armazenados como chaves de dicionário e suas contagens são armazenadas como valores de dicionário. As contagens podem ser qualquer valor inteiro, incluindo zero ou contagens negativas.
244 |
245 | Observe que o número 1 ocorre 3 vezes, o 2 ocorre 2 e assim por diante.
246 |
247 | Se quisermos saber os dois números com mais entradas, podemos utilizar o método **most_common()** passando como argumento o número 2:
248 |
249 | ```python
250 | Counter(x).most_common(2) # [(1, 3), (2, 2)]
251 | ```
252 |
253 | Nos será retornado uma lista de tuplas de pares de valores, neste caso indicando que o número 1 ocorre 3 vezes e o 2 apenas 2 vezes.
254 |
255 | #### Módulo statistics
256 |
257 | O módulo [statistics](https://docs.python.org/3/library/statistics.html) fornece funções para calcular estatísticas matemáticas de dados numéricos (com valor real).
258 |
259 | Com ele podemos fazer cálculos como **média**, **mediana**, **moda**, **variância** e **desvio padrão**, essenciais na estatísticas.
260 |
261 | Vamos então importar essas funções específicas e definir uma lista de números reais para exemplificar:
262 |
263 | ```python
264 | from statistics import mean, median, mode, variance, stdev
265 |
266 | y = [-1.0, 2.5, 3.25, 5.75, 12.0, 37.5, 22.8, 99.13, -5.8, 2.5]
267 | ```
268 |
269 | Calculando a média:
270 |
271 | ```python
272 | media = mean(y)
273 | print(media) # 17.863
274 | ```
275 |
276 | Calculando a mediana:
277 |
278 | ```python
279 | mediana = median(y)
280 | print(mediana) # 4.5
281 | ```
282 |
283 | Calculando a moda:
284 |
285 | ```python
286 | moda = mode(y)
287 | print(moda) # 2.5
288 | ```
289 |
290 | Calculando a variância:
291 |
292 | ```python
293 | variancia = variance(y)
294 | print(variancia) # 977.4160233333333
295 | ```
296 |
297 | Calculando o desvio padrão:
298 |
299 | ```python
300 | desvio_padrao = stdev(y)
301 | print(desvio_padrao) # 31.263653390692095
302 |
303 | from math import sqrt
304 |
305 | desviopadrao = sqrt(variancia)
306 | print(desviopadrao) # 31.263653390692095
307 | ```
308 |
309 | Observe que o desvio padrão é apenas a raiz quadrada da variância.
310 |
311 | #### Módulo itertools
312 |
313 | O módulo [itertools](https://docs.python.org/3/library/itertools.html) do Python é uma coleção de ferramentas para lidar com iteradores. Simplificando, iteradores são tipos de dados que podem ser usados em um **for loop**. O iterador mais comum em Python é a lista.
314 |
315 | Para compreendermos melhor o funcionamento deste módulo, vamos considerar alguns exemplos, mas antes vamos importá-lo, abreviando-o com o nome **it**.
316 |
317 | ```python
318 | import itertools as it
319 | ```
320 |
321 | A função **accumulate()** recebe um iterável como argumento e opcionalmente uma função. Ele retorna os resultados acumulados. Os próprios resultados estão contidos em um iterável.
322 |
323 | ```python
324 | dados = [1,3,4,7,9,25,45]
325 | resultados = it.accumulate(dados)
326 |
327 | for resultado in resultados:
328 | print(f'{resultado} ',end='') # 1 4 8 15 24 49 94
329 | ```
330 |
331 | Veja que por padrão ele nos traz a soma acumula dos números na sequência, se quisermos por exemplo a multiplicação acumulada, podemos usar a função de multiplicação do módulo **operator** para nos auxiliar nesta tarefa, porém para isso, precisamos importá-lo. Vejamos um exemplo:
332 |
333 | ```python
334 | import operator
335 |
336 | multiplicacoes = it.accumulate(dados,operator.mul)
337 |
338 | for multi in multiplicacoes:
339 | print(f'{multi} ',end='') # 1 3 12 84 756 18900 850500
340 | ```
341 |
342 | Dessa forma nos será trazida a multiplicação acumulada.
343 |
344 | Outra função muito interessante do módulo itertools é a **combinations()**, esta função recebe um iterável e um inteiro **R** e criará todas as combinações **exclusivas** que possuem **R** membros.
345 |
346 | ```python
347 | formas = ['círculo','triângulo','quadrado','hexágono']
348 |
349 | R = 2
350 |
351 | combinacoes = it.combinations(formas,R)
352 |
353 | for combinacao in combinacoes:
354 | print(combinacao)
355 |
356 | # ('círculo', 'triângulo')
357 | # ('círculo', 'quadrado')
358 | # ('círculo', 'hexágono')
359 | # ('triângulo', 'quadrado')
360 | # ('triângulo', 'hexágono')
361 | # ('quadrado', 'hexágono')
362 | ```
363 |
364 | Uma outra função muito interessante de itertools de "força bruta" é **permutations()**, que aceita um único iterável e produz todas as permutações (rearranjos) possíveis de seus elementos:
365 |
366 | ```python
367 | alpha = ['x','y','z']
368 |
369 | permutacoes = it.permutations(alpha)
370 |
371 | for permutacao in permutacoes:
372 | print(permutacao)
373 |
374 | # ('x', 'y', 'z')
375 | # ('x', 'z', 'y')
376 | # ('y', 'x', 'z')
377 | # ('y', 'z', 'x')
378 | # ('z', 'x', 'y')
379 | # ('z', 'y', 'x')
380 | ```
381 |
382 | As permutações são todas as maneiras diferentes que podemos agrupar um certo número de itens, onde a ordem importa.
383 |
384 | Qualquer iterável de três elementos terá seis permutações, e o número de permutações de iteráveis mais longos cresce extremamente rápido. Na verdade, um iterável de comprimento `n` possui `n!` permutações, onde:
385 |
386 | 
387 |
388 | Para compreendermos melhor, vejamos uma tabela desses números, de `n = 1` até `n = 10`:
389 |
390 | | n | n! |
391 | |---|---|
392 | | 2 | 2 |
393 | | 3 | 6 |
394 | | 4 | 24 |
395 | | 5 | 120 |
396 | | 6 | 720 |
397 | | 7 | 5040 |
398 | | 8 | 40.320 |
399 | | 9 | 362.880 |
400 | | 10 | 3.628.800 |
401 |
402 | O fenômeno de apenas algumas entradas produzindo um grande número de resultados é chamado de [explosão combinatória](https://en.wikipedia.org/wiki/Combinatorial_explosion).
403 |
404 | A função **cycle()** nos permite criar um ciclo com um determinado iterador:
405 |
406 | ```python
407 | i = 0
408 |
409 | for item in it.cycle([0,1]):
410 | i += 1
411 | if i == 15:
412 | break
413 | print(f'{item} ',end='')
414 |
415 | # 0 1 0 1 0 1 0 1 0 1 0 1 0 1
416 | ```
417 |
418 | É importante definirmos um ponto de parada para o nosso ciclo, caso contrário ficaremos preso em um loop infinito.
419 |
420 | A função **product()** cria o produto cartesiano de uma série de iteráveis.
421 |
422 | ```python
423 | numeros = [1,2,3]
424 | letras = ['a','b','c']
425 |
426 | produto = it.product(numeros,letras)
427 |
428 | for p in produto:
429 | print(p)
430 |
431 | # (1, 'a')
432 | # (1, 'b')
433 | # (1, 'c')
434 | # (2, 'a')
435 | # (2, 'b')
436 | # (2, 'c')
437 | # (3, 'a')
438 | # (3, 'b')
439 | # (3, 'c')
440 | ```
441 |
442 | Como podemos ver os módulos nos permitem organizar o nosso código de maneira limpa e adequada e faz com que possamos trabalhar com bibliotecas do próprio **Python** e até mesmo outras feitas por terceiras pessoas, o que enriquece bastante o leque de possibilidades da linguagem **Python**, nos trazendo muitas funcionalidades adicionais.
443 |
--------------------------------------------------------------------------------