├── .gitignore ├── .vscode └── settings.json ├── 00_intro └── hello.py ├── 01_numericos └── tabuada.py ├── 02_textos ├── email_tmpl.txt ├── emails.txt └── interpolacao.py ├── 03_the_dicts └── cadastro_de_produto.py ├── 03_tuplas_listas ├── escola_v1_com_listas.py ├── escola_v2_com_sets.py └── escola_v3_com_dict.py ├── 04_input ├── infixcalc.log └── infixcalc.py ├── 05_filesystem ├── notes.py └── notes.txt ├── 06_errors └── errors.py ├── 07_algoritmo └── algoritmo.py ├── 07_logs └── logs.py ├── 08_repeticoes ├── post.txt ├── repete_com_for.py └── repete_com_while.py ├── 09_exercicios ├── alerta.py ├── numeros_pares.py ├── quartos.txt ├── repete_vogal.py ├── reserva.py └── reservas.txt ├── 09_smtp └── smtp.py ├── 10_funcao ├── anatomia_funcoes.py ├── composicao.py ├── coringas.py ├── funcoes.py ├── heron.py ├── lambdas.py ├── questions.py ├── valores_default.py └── valores_default_mutaveis.py ├── 11_escopos ├── contador.py ├── escopo.py ├── forcando_global.py └── non_local.py ├── 12_debug └── tembug.py ├── 13_poo ├── band.py ├── exercicio1.py ├── exercicio1_resolvido.py ├── exercicio1_resolvido_dataclass_rich.py ├── exercicio1_resolvido_dataclasses.py ├── funcional.py ├── instruments.py ├── match_turtle.py ├── oo.py ├── oo_v1.py ├── oo_v2_abstracao.py ├── oo_v3_heranca.py ├── oo_v4_abc.py ├── oo_v5_polimorfismo.py ├── oo_v6_encapsulamento.py ├── oo_v7_properties.py ├── oo_v8_protocolos.py ├── procedural.py └── requirements.txt ├── 14_modelagem ├── models.py ├── models_pydantic.py ├── requirements.txt ├── sqla_example.py ├── sqlite_example.py └── sqlmodel_example.py ├── 15_gui ├── kivy_example.py ├── requirements.txt ├── simplegui_example.py ├── tk_clock.py └── tk_example.py ├── 16_game ├── beers │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ └── 5.png ├── game.py ├── player │ └── player.png ├── requirements.txt └── sound │ ├── olha_so.mp3 │ ├── sensacional.mp3 │ ├── vai.mp3 │ └── zika.mp3 ├── 17_tui ├── br-utf8.txt ├── colorize.py ├── grid.py ├── palavras.txt ├── processa_palavras.py ├── pylavras.py ├── requirements.txt └── trivia.py ├── 18_web ├── app.py ├── data.json ├── requirements.txt └── templates │ ├── index.html │ └── pessoas.html ├── 19_api ├── api.py ├── data.json └── requirements.txt └── docs ├── README.md ├── d1 ├── d1p01_intro.md ├── d1p02_programacao_linguagens.md ├── d1p03_plataforma_python.md ├── d1p04_instalacao_ambiente_terminais_editor.md ├── d1p05_repositorio_git_primeiro_script.md ├── d1p06_variaveis_de_ambiente.md ├── d1p07_tipos_de_instrucoes.md ├── d1p08_blocos_de_codigo.md └── d1p09_ambiente_virtual_ipython.md ├── d2 ├── d2p01_protocolos_e_tipos_de_dados_primarios.md ├── d2p02_float_bool_none.md ├── d2p03_textos.md ├── d2p04_formatacao_de_textos.md ├── d2p05_tipos_compostos-tuplas.md ├── d2p06_0_listas.md ├── d2p06_1_exercicio_listas_tuplas.md ├── d2p07_sets.md ├── d2p08_dicionario.md └── imgs │ ├── ascii.png │ ├── cartesiano.png │ ├── memoria.excalidraw │ ├── memoria.png │ ├── pasta_docs.jpg │ └── sets.jpg ├── d3 ├── computer.excalidraw ├── d3p01_stdout_stdin.md ├── d3p02_infix.md ├── d3p03_filesystem.md ├── d3p04_exercicio_notas.md ├── d3p05_exceptions.md ├── d3p06_logging.md ├── d3p07_allgoritmos.md ├── d3p08_condicionais_inline.md ├── d3p09_repeticoes.md ├── d3p10_exericios.md └── imgs │ ├── io.png │ └── precedencia.png ├── d4 ├── _email.py ├── d4p01_funcoes_uteis-builtin.md ├── d4p02_funcoes_stdlib_enviar_emails.md ├── d4p03_primeira_funcao_e_formula_math.md ├── d4p04_anatomia_de_funcoes.md ├── d4p05_escopos_argumentos_mutaveis_e_coringas.md ├── d4p06_lambdas.md ├── d4p07_recursao_e_retry.md ├── d4p08_debugging.md └── imgs │ ├── escopos.jpg │ ├── fun1.png │ ├── fun2.png │ ├── fun3.png │ ├── fun4.png │ ├── fun5.png │ ├── fun6.png │ ├── fun7.png │ ├── fun8.png │ ├── heron.png │ ├── pudb.png │ └── vscodepdb.png ├── d5 ├── README.md ├── project.md ├── rich_click.png ├── system_design.excalidraw └── system_design.png ├── d6 ├── d6p01_paradigmas.md ├── d6p02_intro_a_oo.md ├── d6p03_init_method.md ├── d6p04_pilares_oo.md ├── d6p05_propriedades.md ├── d6p06_protocolos.md └── d6p07_type_annotations.md ├── d7 ├── d7p01_pydantic.md ├── d7p02_exemplo_orm.md ├── d7p03_sql.md ├── d7p04_ORM.md ├── d7p05_SQLModel.md ├── d7p06_migrando_para_orm.md ├── d7p07_migrations_e_api.md ├── d7p08_final.md └── imgs │ ├── db_designer.png │ ├── sql_lang.png │ ├── vs_open_database.png │ ├── vs_sqlite_explorer.png │ └── vs_sqlite_select.png └── d8 └── README.MD /.gitignore: -------------------------------------------------------------------------------- 1 | .venv 2 | __pycache__ 3 | .DS_Store 4 | .vscode -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.linting.flake8Enabled": true, 3 | "python.linting.enabled": true, 4 | "python.formatting.provider": "black", 5 | "python.linting.flake8Path": "pflake8", 6 | "activitusbar.alignment": "Right", 7 | "workbench.sideBar.location": "right", 8 | "editor.rulers": [ 9 | 80 10 | ], 11 | "editor.minimap.enabled": false 12 | } 13 | -------------------------------------------------------------------------------- /00_intro/hello.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """Hello World Multi Linguas. 3 | 4 | Dependendo da lingua configurada no ambiente o programa exibe a mensagem 5 | correspondente. 6 | 7 | Como usar: 8 | 9 | Tenha a variável LANG devidamente configurada ex: 10 | 11 | export LANG=pt_BR 12 | 13 | Ou informe atraves do CLI argument `--lang` 14 | 15 | Ou o usuário terá que digitar. 16 | 17 | Execução: 18 | 19 | python3 hello.py 20 | ou 21 | ./hello.py 22 | """ 23 | __version__ = "0.1.3" 24 | __author__ = "Bruno Rocha" 25 | __license__ = "Unlicense" 26 | 27 | import logging 28 | import os 29 | import sys 30 | 31 | log_level = os.getenv("LOG_LEVEL", "WARNING").upper() 32 | log = logging.Logger("bruno", log_level) 33 | ch = logging.StreamHandler() 34 | ch.setLevel(log_level) 35 | fmt = logging.Formatter( 36 | "%(asctime)s %(name)s %(levelname)s " "l:%(lineno)d f:%(filename)s: %(message)s" 37 | ) 38 | ch.setFormatter(fmt) 39 | log.addHandler(ch) 40 | 41 | arguments = {"lang": None, "count": 1} 42 | 43 | for arg in sys.argv[1:]: 44 | try: 45 | key, value = arg.split("=") 46 | except ValueError as e: 47 | log.error( 48 | "You need to use `=`, you passed %s, try --key=value: %s", 49 | arg, 50 | str(e), 51 | ) 52 | sys.exit(1) 53 | 54 | key = key.lstrip("-").strip() 55 | value = value.strip() 56 | 57 | # Validação 58 | if key not in arguments: 59 | print(f"Invalid Option `{key}`") 60 | sys.exit() 61 | 62 | arguments[key] = value 63 | 64 | current_language = arguments["lang"] 65 | 66 | if current_language is None: 67 | if "LANG" in os.environ: 68 | current_language = os.getenv("LANG") 69 | else: 70 | current_language = input("Choose a language:") 71 | 72 | current_language = current_language[:5] 73 | 74 | msg = { 75 | "en_US": "Hello, World!", 76 | "pt_BR": "Olá, Mundo!", 77 | "it_IT": "Ciao, Mondo!", 78 | "es_ES": "Hola, Mundo!", 79 | "fr_FR": "Bonjour, Monde!", 80 | } 81 | 82 | 83 | """ 84 | # try com valor default 85 | message = msg.get(current_language, msg["en_US"]) 86 | """ 87 | 88 | # EAFP 89 | try: 90 | message = msg[current_language] 91 | except KeyError as e: 92 | print(f"[ERROR] {str(e)}") 93 | print(f"Language is invalid, choose from: {list(msg.keys())}") 94 | sys.exit(1) 95 | 96 | print(message * int(arguments["count"])) 97 | -------------------------------------------------------------------------------- /01_numericos/tabuada.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Imprime a tabuada do 1 ao 10. 3 | 4 | ---Tabuada do 1--- 5 | 6 | 1 x 1 = 1 7 | 2 x 1 = 2 8 | 3 x 1 = 3 9 | ... 10 | ################## 11 | ---Tabuada do 2--- 12 | 13 | 2 x 1 = 2 14 | 2 x 2 = 4 15 | ... 16 | ################## 17 | """ 18 | __version__ = "0.1.1" 19 | __author__ = "Bruno" 20 | 21 | # numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - Iterable (percorriveis) 22 | numeros = list(range(1, 11)) 23 | 24 | # para cada numero em numeros 25 | for n1 in numeros: 26 | print("{:-^18}".format(f"Tabuada do {n1}")) 27 | print() 28 | for n2 in numeros: 29 | resultado = n1 * n2 30 | print("{:^18}".format(f"{n1} x {n2} = {resultado}")) 31 | print() 32 | print("#" * 18) 33 | -------------------------------------------------------------------------------- /02_textos/email_tmpl.txt: -------------------------------------------------------------------------------- 1 | Olá, %(nome)s 2 | 3 | Tem interesse em comprar %(produto)s? 4 | 5 | Este produto é ótimo para resolver %(texto)s 6 | 7 | Clique agora em %(link)s 8 | 9 | Apenas %(quantidade)d disponiveis! 10 | 11 | Preço promocional %(preco).2f 12 | -------------------------------------------------------------------------------- /02_textos/emails.txt: -------------------------------------------------------------------------------- 1 | Bruno,rochacbruno@gmail.com 2 | Maria,maria@gmail.com 3 | Joao,jjj@hotmail.com 4 | antonio,antoninho@ig.com.br 5 | -------------------------------------------------------------------------------- /02_textos/interpolacao.py: -------------------------------------------------------------------------------- 1 | #!/user/bin/env python 2 | """Imprime a mensagem de um e-mail 3 | 4 | NAO MANDE SPAM!!! 5 | """ 6 | __version__ = "0.1.1" 7 | 8 | import sys 9 | import os 10 | import smtplib 11 | from email.mime.text import MIMEText 12 | 13 | arguments = sys.argv[1:] 14 | if not arguments: 15 | print("informa o nome do arquivo de emails") 16 | sys.exit(1) 17 | 18 | filename = arguments[0] 19 | templatename = arguments[1] 20 | 21 | path = os.curdir 22 | filepath = os.path.join(path, filename) # emails.txt 23 | templatepath = os.path.join(path, templatename) # email_tmpl.txt 24 | 25 | 26 | with smtplib.SMTP(host="localhost", port=8025) as server: 27 | 28 | for line in open(filepath): 29 | name, email = line.split(",") 30 | text = open(templatepath).read() % { 31 | "nome": name, 32 | "produto": "caneta", 33 | "texto": "Escrever muito bem", 34 | "link": "http//canetaslegais.com", 35 | "quantidade": 1, 36 | "preco": 50.5, 37 | } 38 | 39 | from_ = "bruno@rocha.com" 40 | to = ", ".join([email]) 41 | 42 | message = MIMEText(text) 43 | message["Subject"] = "Compre mais" 44 | message["From"] = from_ 45 | message["To"] = to 46 | 47 | server.sendmail(from_, to, message.as_string()) 48 | -------------------------------------------------------------------------------- /03_the_dicts/cadastro_de_produto.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """Cadastro de produto""" 3 | __version__ = "0.1.0" 4 | 5 | from pprint import pprint 6 | 7 | produto = { 8 | "nome": "Caneta", 9 | "cores": ["azul", "branco"], 10 | "preco": 3.23, 11 | "dimensao": { 12 | "altura": 12.1, 13 | "largura": 0.8, 14 | }, 15 | "em_estoque": True, 16 | "codigo": 45678, 17 | "codebar": None, 18 | } 19 | 20 | cliente = {"nome": "Bruno"} 21 | 22 | compra = {"cliente": cliente, "produto": produto, "quantidade": 3} 23 | 24 | # pprint(compra) 25 | 26 | total_compra = compra["quantidade"] * compra["produto"]["preco"] 27 | 28 | print( 29 | f"O cliente {compra['cliente']['nome']}" 30 | f" comprou {compra['quantidade']} unidades de {compra['produto']['nome']}" 31 | f" e pagou o total de {total_compra}" 32 | ) 33 | -------------------------------------------------------------------------------- /03_tuplas_listas/escola_v1_com_listas.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """Exibe relatório de crianças por atividade. 3 | 4 | Imprimir a lista de crianças agrupadas por sala 5 | que frequentas cada uma das atividades. 6 | """ 7 | __version__ = "0.1.0" 8 | 9 | # Dados 10 | sala1 = ["Erik", "Maia", "Gustavo", "Manuel", "Sofia", "Joana"] 11 | sala2 = ["Joao", "Antonio", "Carlos", "Maria", "Isolda"] 12 | 13 | aula_ingles = ["Erik", "Maia", "Joana", "Carlos", "Antonio"] 14 | aula_musica = ["Erik", "Carlos", "Maria"] 15 | aula_danca = ["Gustavo", "Sofia", "Joana", "Antonio"] 16 | 17 | atividades = [ 18 | ("Inglês", aula_ingles), 19 | ("Música", aula_musica), 20 | ("Dança", aula_danca), 21 | ] 22 | 23 | # Listar alunos em cada atividade por sala 24 | 25 | for nome_atividade, atividade in atividades: 26 | 27 | print(f"Alunos da atividade {nome_atividade}\n") 28 | print("-" * 40) 29 | 30 | atividade_sala1 = [] 31 | atividade_sala2 = [] 32 | 33 | for aluno in atividade: 34 | if aluno in sala1: 35 | atividade_sala1.append(aluno) 36 | elif aluno in sala2: 37 | atividade_sala2.append(aluno) 38 | 39 | print("Sala1 ", atividade_sala1) 40 | print("Sala2 ", atividade_sala2) 41 | 42 | print() 43 | print("#" * 40) 44 | -------------------------------------------------------------------------------- /03_tuplas_listas/escola_v2_com_sets.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """Exibe relatório de crianças por atividade. 3 | 4 | Imprimir a lista de crianças agrupadas por sala 5 | que frequentas cada uma das atividades. 6 | """ 7 | __version__ = "0.1.1" 8 | 9 | # Dados 10 | sala1 = ["Erik", "Maia", "Gustavo", "Manuel", "Sofia", "Joana"] 11 | sala2 = ["Joao", "Antonio", "Carlos", "Maria", "Isolda"] 12 | 13 | aula_ingles = ["Erik", "Maia", "Joana", "Carlos", "Antonio"] 14 | aula_musica = ["Erik", "Carlos", "Maria"] 15 | aula_danca = ["Gustavo", "Sofia", "Joana", "Antonio"] 16 | 17 | atividades = [ 18 | ("Inglês", aula_ingles), 19 | ("Música", aula_musica), 20 | ("Dança", aula_danca), 21 | ] 22 | 23 | # Listar alunos em cada atividade por sala 24 | 25 | for nome_atividade, atividade in atividades: 26 | 27 | print(f"Alunos da atividade {nome_atividade}\n") 28 | print("-" * 40) 29 | 30 | # sala1 que tem interseção com a atividade 31 | atividade_sala1 = set(sala1) & set(atividade) 32 | atividade_sala2 = set(sala2).intersection(atividade) 33 | 34 | print("Sala1 ", atividade_sala1) 35 | print("Sala2 ", atividade_sala2) 36 | 37 | print() 38 | print("#" * 40) 39 | -------------------------------------------------------------------------------- /03_tuplas_listas/escola_v3_com_dict.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """Exibe relatório de crianças por atividade. 3 | 4 | Imprimir a lista de crianças agrupadas por sala 5 | que frequentas cada uma das atividades. 6 | """ 7 | __version__ = "0.1.1" 8 | 9 | 10 | ############################################## 11 | # ATENçÃO: MODIFIQUE ESSE CÓDIGO! # 12 | # Tente utilizar dicionários # 13 | ############################################## 14 | 15 | 16 | # Dados 17 | sala1 = ["Erik", "Maia", "Gustavo", "Manuel", "Sofia", "Joana"] 18 | sala2 = ["Joao", "Antonio", "Carlos", "Maria", "Isolda"] 19 | 20 | aula_ingles = ["Erik", "Maia", "Joana", "Carlos", "Antonio"] 21 | aula_musica = ["Erik", "Carlos", "Maria"] 22 | aula_danca = ["Gustavo", "Sofia", "Joana", "Antonio"] 23 | 24 | atividades = [ 25 | ("Inglês", aula_ingles), 26 | ("Música", aula_musica), 27 | ("Dança", aula_danca), 28 | ] 29 | 30 | # Listar alunos em cada atividade por sala 31 | 32 | for nome_atividade, atividade in atividades: 33 | 34 | print(f"Alunos da atividade {nome_atividade}\n") 35 | print("-" * 40) 36 | 37 | # sala1 que tem interseção com a atividade 38 | atividade_sala1 = set(sala1) & set(atividade) 39 | atividade_sala2 = set(sala2).intersection(atividade) 40 | 41 | print("Sala1 ", atividade_sala1) 42 | print("Sala2 ", atividade_sala2) 43 | 44 | print() 45 | print("#" * 40) 46 | -------------------------------------------------------------------------------- /04_input/infixcalc.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/04_input/infixcalc.log -------------------------------------------------------------------------------- /04_input/infixcalc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """Calculadora infix. 3 | 4 | Funcionamento: 5 | 6 | [operação] [n1] [n2] 7 | 8 | Operações: 9 | sum -> + 10 | sub -> - 11 | mul -> * 12 | div -> / 13 | 14 | Uso: 15 | $ infixcalc.py sum 5 2 16 | 7 17 | 18 | $ infixcalc.py mul 10 5 19 | 50 20 | 21 | $ infixcalc.py 22 | operação: sum 23 | n1: 5 24 | n2: 4 25 | 9 26 | 27 | Os resultados serão salvos em `infixcalc.log` 28 | """ 29 | __version__ = "0.1.0" 30 | 31 | import os 32 | import sys 33 | 34 | from datetime import datetime 35 | 36 | arguments = sys.argv[1:] 37 | 38 | 39 | valid_operations = { 40 | "sum": lambda a, b: a + b, 41 | "sub": lambda a, b: a - b, 42 | "mul": lambda a, b: a * b, 43 | "div": lambda a, b: a / b, 44 | } 45 | 46 | path = os.curdir 47 | filepath = os.path.join(path, "infixcalc.log") 48 | timestamp = datetime.now().isoformat() 49 | user = os.getenv("USER", "anonymous") 50 | 51 | 52 | while True: 53 | 54 | # Validacao 55 | if not arguments: 56 | operation = input("operação:") 57 | n1 = input("n1:") 58 | n2 = input("n2:") 59 | arguments = [operation, n1, n2] 60 | elif len(arguments) != 3: 61 | print("Número de argumentos inválidos") 62 | print("ex: `sum 5 5`") 63 | sys.exit(1) 64 | 65 | operation, *nums = arguments 66 | 67 | if operation not in valid_operations: 68 | print("Operação inválida") 69 | print(valid_operations) 70 | sys.exit(1) 71 | 72 | validated_nums = [] 73 | for num in nums: 74 | if not num.replace(".", "").isdigit(): 75 | print(f"Numero inválido {num}") 76 | sys.exit(1) 77 | if "." in num: 78 | num = float(num) 79 | else: 80 | num = int(num) 81 | validated_nums.append(num) 82 | 83 | try: 84 | n1, n2 = validated_nums 85 | except ValueError as e: 86 | print(str(e)) 87 | sys.exit(1) 88 | 89 | result = valid_operations[operation](n1, n2) 90 | print(f"O resultado é {result}") 91 | 92 | try: 93 | with open(filepath, "a") as log: 94 | log.write(f"{timestamp} - {user} - {operation},{n1},{n2} = {result}\n") 95 | except PermissionError as e: 96 | print(str(e)) 97 | sys.exit(1) 98 | 99 | arguments = None 100 | 101 | if input("Pressione enter para continar ou qualquer tecla para sair"): 102 | break 103 | -------------------------------------------------------------------------------- /05_filesystem/notes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """Bloco de notas 3 | 4 | $ notes.py new "Minha Nota" 5 | tag: tech 6 | text: 7 | Anotacao geral sobre carreira de tecnologia 8 | 9 | $ notes.py 1 tech 10 | ... 11 | ... 12 | """ 13 | __version__ = "0.1.0" 14 | 15 | import os 16 | import sys 17 | 18 | cmds = ("read", "new") 19 | path = os.curdir 20 | filepath = os.path.join(path, "notes.txt") 21 | 22 | arguments = sys.argv[1:] 23 | if not arguments: 24 | print("Invalid usage") 25 | print(f"you must specify subcommand {cmds}") 26 | sys.exit(1) 27 | 28 | if arguments[0] not in cmds: 29 | print(f"Invalid command {arguments[0]}") 30 | 31 | 32 | while True: 33 | 34 | if arguments[0] == "read": 35 | try: 36 | arg_tag = arguments[1].lower() 37 | except IndexError: 38 | arg_tag = input("Qual a tag?").strip().lower() 39 | 40 | # leitura das notas 41 | for line in open(filepath): 42 | title, tag, text = line.split("\t") 43 | if tag.lower() == arg_tag: 44 | print(f"title: {title}") 45 | print(f"text: {text}") 46 | print("-" * 30) 47 | print() 48 | 49 | if arguments[0] == "new": 50 | try: 51 | title = arguments[1] 52 | except IndexError: 53 | title = input("qual é o titulo:").strip().title() 54 | 55 | text = [ 56 | f"{title}", 57 | input("tag:").strip(), 58 | input("text:\n").strip(), 59 | ] 60 | # \t - tsv 61 | with open(filepath, "a") as file_: 62 | file_.write("\t".join(text) + "\n") 63 | 64 | cont = input(f"Quer continuar {arguments[0]} notas? [N/y]").strip().lower() 65 | if cont != "y": 66 | break 67 | -------------------------------------------------------------------------------- /05_filesystem/notes.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/05_filesystem/notes.txt -------------------------------------------------------------------------------- /06_errors/errors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import time 3 | import logging 4 | 5 | log = logging.Logger("errors") 6 | 7 | 8 | # EAFP - Easy to Ask Forgiveness than permission 9 | # (É mais fácil pedir perdão do que permissão) 10 | 11 | 12 | def try_to_open_a_file(filepath, retry=1) -> list: 13 | """Tries to open a file, if error, retries n times.""" 14 | if retry > 999: 15 | raise ValueError("Retry cannot be above 999") 16 | 17 | try: 18 | return open(filepath).readlines() # FileNotFoundError 19 | except FileNotFoundError as e: 20 | log.error("ERRO: %s", e) 21 | time.sleep(2) 22 | if retry > 1: 23 | # recursão 24 | return try_to_open_a_file(filepath, retry=retry - 1) 25 | else: 26 | print("Sucesso!!!") 27 | finally: 28 | print("Execute isso sempre!") 29 | 30 | return [] 31 | 32 | 33 | for line in try_to_open_a_file("names.txt", retry=5): 34 | print(line) 35 | -------------------------------------------------------------------------------- /07_algoritmo/algoritmo.py: -------------------------------------------------------------------------------- 1 | # PSEUDO CODIGO 2 | import ir, pegar, pedir, tem, comer, ficar 3 | 4 | # Premissas 5 | today = "Segunda" 6 | hora = 15 7 | natal = False 8 | chovendo = True 9 | frio = True 10 | nevando = True 11 | semana = ["Segunda", "Terça", "Quarta", "Quinta", "Sexta"] 12 | feriados = ["Quarta"] 13 | horario_padaria = {"semana": 19, "fds": 12} 14 | 15 | # Algoritmo 16 | if today in feriados and not natal: 17 | padaria_aberta = False 18 | elif today not in semana and hora < horario_padaria["fds"]: 19 | padaria_aberta = True 20 | elif today in semana and hora < horario_padaria["semana"]: 21 | padaria_aberta = True 22 | else: 23 | padaria_aberta = False 24 | 25 | if padaria_aberta: 26 | if chovendo and (frio or nevando): 27 | pegar("guarda-chuva") 28 | pegar("blusa") 29 | pegar("botas") 30 | elif chovendo and not frio: 31 | pegar("guarda-chuvas") 32 | pegar("agua") 33 | elif chovendo: 34 | pegar("guarda-chuva") 35 | 36 | ir("padaria") 37 | 38 | if tem("pao int") and tem("baguete"): 39 | pedir(6, "pao int") 40 | pedir(6, "baguete") 41 | elif tem("pao int") or tem("baguete"): 42 | pedir(12, "qualquer um dos 2") 43 | else: 44 | pedir(6, "qualquer pao") 45 | else: 46 | ficar("casa") 47 | comer("bolacha") 48 | -------------------------------------------------------------------------------- /07_logs/logs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import logging 5 | from logging import handlers 6 | 7 | # BOILERPLATE (que deve ser encapulado em uma função posteriormente) 8 | log_level = os.getenv("LOG_LEVEL", "WARNING").upper() 9 | log = logging.Logger("bruno", log_level) 10 | # ch = logging.StreamHandler() # Console/terminal/stderr 11 | # ch.setLevel(log_level) 12 | fh = handlers.RotatingFileHandler( 13 | "meulog.log", 14 | maxBytes=300, # 10**6 15 | backupCount=10, 16 | ) 17 | fh.setLevel(log_level) 18 | fmt = logging.Formatter( 19 | "%(asctime)s %(name)s %(levelname)s " "l:%(lineno)d f:%(filename)s: %(message)s" 20 | ) 21 | # ch.setFormatter(fmt) 22 | fh.setFormatter(fmt) 23 | # log.addHandler(ch) 24 | log.addHandler(fh) 25 | 26 | 27 | """ 28 | log.debug("Mensagem pro dev, qe, sysadmin") 29 | log.info("Mensagem geral para usuarios") 30 | log.warning("Aviso que nao causa erro") 31 | log.error("Erro que afeta uma unica execucao") 32 | log.critical("Erro geral ex: banco de dados sumiu") 33 | """ 34 | 35 | try: 36 | 1 / 0 37 | except ZeroDivisionError as e: 38 | log.error("Deu erro %s", str(e)) 39 | -------------------------------------------------------------------------------- /08_repeticoes/post.txt: -------------------------------------------------------------------------------- 1 | title:Meu post 2 | tags:tech,geral 3 | date:2022-02-10 4 | published:1 5 | --- 6 | Este é o meu post 7 | Aqui tem texto e conteudo 8 | etc. etc. etc. 9 | -------------------------------------------------------------------------------- /08_repeticoes/repete_com_for.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | original = [1, 2, 3] 4 | 5 | # For loops / Laço for 6 | dobrada = [] 7 | for n in original: 8 | dobrada.append(n * 2) 9 | print(dobrada) 10 | 11 | # Funcional 12 | # List Comprehension 13 | dobrada = [n * 2 for n in original] 14 | print(dobrada) 15 | 16 | # Dict comprehension 17 | dados = { 18 | line.split(":")[0]: line.split(":")[1].strip() 19 | for line in open("post.txt") 20 | if ":" in line 21 | } 22 | dados = {} 23 | for line in open("post.txt"): 24 | if ":" in line: 25 | key, valor = line.split(":") 26 | dados[key] = valor.strip() 27 | 28 | print(dados) 29 | -------------------------------------------------------------------------------- /08_repeticoes/repete_com_while.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # While - Enquanto 4 | 5 | n = 0 6 | while n < 101: 7 | if n % 2 != 0: 8 | n += 1 9 | continue 10 | print(n) 11 | n += 1 12 | -------------------------------------------------------------------------------- /09_exercicios/alerta.py: -------------------------------------------------------------------------------- 1 | """ 2 | Alarme de temperatura 3 | 4 | Faça um script que pergunta ao usuário qual a temperatura atual e o indice de 5 | umidade do ar sendo que caso será exibida uma mensagem de alerta dependendo das 6 | condições: 7 | 8 | temp maior 45: "ALERTA!!! 🥵 Perigo calor extremo" 9 | temp maior que 30 e temp vezes 3 for maior ou igual a umidade: 10 | "ALERTA!!! 🥵♒ Perigo de calor úmido" 11 | temp entre 10 e 30: "😀 Normal" 12 | temp entre 0 e 10: "🥶 Frio" 13 | temp <0: "ALERTA!!! ⛄ Frio Extremo." 14 | 15 | ex: 16 | python3 alerta.py 17 | temperatura: 30 18 | umidade: 90 19 | ... 20 | "ALERTA!!! 🥵♒ Perigo de calor úmido" 21 | """ 22 | import logging 23 | 24 | log = logging.Logger("alerta") 25 | 26 | 27 | def is_completely_filled(dict_of_inputs): 28 | """Returns a boolean telling if a dict is completely filled.""" 29 | info_size = len(dict_of_inputs) 30 | filled_size = len([value for value in dict_of_inputs.values() if value is not None]) 31 | return info_size == filled_size 32 | 33 | 34 | def read_inputs_for_dict(dict_of_info): 35 | """Reads information for a dict from user input.""" 36 | for key in dict_of_info.keys(): # ["temperatura", "umidade"] 37 | if dict_of_info[key] is not None: 38 | continue 39 | try: 40 | dict_of_info[key] = int(input(f"{key}:").strip()) 41 | except ValueError: 42 | log.error("%s inválida, digite números", key) 43 | break # para o for 44 | 45 | 46 | # PROGRAMA PRINCIPAL 47 | 48 | info = {"temperatura": None, "umidade": None} 49 | 50 | while not is_completely_filled(info): 51 | read_inputs_for_dict(info) 52 | 53 | temp, umidade = info.values() # unpacking [30, 90] 54 | 55 | if temp > 45: 56 | print("ALERTA!!! 🥵 Perigo calor extremo") 57 | elif temp > 30 and temp * 3 >= umidade: 58 | print("ALERTA!!! 🥵♒ Perigo de calor úmido") 59 | elif temp >= 10 and temp <= 30: 60 | # elif 10 <= temp <= 30: 61 | # elif temp in range(1, 31): 62 | print("😀 Normal") 63 | elif temp >= 0 and temp <= 10: 64 | print("🥶 Frio") 65 | elif temp < 0: 66 | print("ALERTA!!! ⛄ Frio Extremo.") 67 | -------------------------------------------------------------------------------- /09_exercicios/numeros_pares.py: -------------------------------------------------------------------------------- 1 | """ 2 | Faça um programa que imprime os números pares de 1 a 200 3 | 4 | ex 5 | `python3 numeros_pares.py` 6 | 2 7 | 4 8 | 6 9 | 8 10 | ... 11 | """ 12 | 13 | for num in range(1, 201): 14 | if num % 2 != 0: 15 | continue 16 | print(num) 17 | -------------------------------------------------------------------------------- /09_exercicios/quartos.txt: -------------------------------------------------------------------------------- 1 | 1,Suite Master,500 2 | 2,Quarto Familia,200 3 | 3,Quarto Single,100 4 | 4,Quarto Simples,50.6 5 | -------------------------------------------------------------------------------- /09_exercicios/repete_vogal.py: -------------------------------------------------------------------------------- 1 | """ 2 | Repete vogais 3 | 4 | Faça um programa que pede ao usuário que digite uma ou mais palavras e imprime 5 | cada uma das palavras com suas vogais duplicadas. 6 | 7 | ex: 8 | python repete_vogal.py 9 | 'Digite uma palavra (ou enter para sair):' Python 10 | 'Digite uma palavra (ou enter para sair):' Bruno 11 | 'Digite uma palavra (ou enter para sair):' 12 | Pythoon 13 | Bruunoo 14 | """ 15 | 16 | VOGAIS = "aeiouãõâôêéáíó" # constante 17 | 18 | words = [] # acumullator/acumulador 19 | while True: 20 | word = input("Digite uma palavra (ou enter para sair):").strip() 21 | if not word: # condição de parada 22 | break 23 | 24 | final_word = "" # acumullator/acumulador 25 | for letter in word: 26 | if letter.lower() in VOGAIS: 27 | final_word += letter * 2 28 | else: 29 | final_word += letter 30 | # final_word += letter * 2 if letter.lower() in VOGAIS else letter 31 | words.append(final_word) 32 | 33 | 34 | print(*words, sep="\n") 35 | -------------------------------------------------------------------------------- /09_exercicios/reserva.py: -------------------------------------------------------------------------------- 1 | """ 2 | Faça um programa de terminal que exibe ao usuário uma listas dos quartos 3 | disponiveis para alugar e o preço de cada quarto, esta informação está 4 | disponível em um arquivo de texto separado por virgulas. 5 | 6 | `quartos.txt` 7 | # codigo, nome, preço 8 | 1,Suite Master,500 9 | 2,Quarto Familia,200 10 | 3,Quarto Single,100 11 | 4,Quarto Simples,50 12 | 13 | O programa pergunta ao usuário o nome, qual o número do quarto a ser reservado 14 | e a quantidade de dias e no final exibe o valor estimado a ser pago. 15 | 16 | O programa deve salvar esta escolha em outro arquivo contendo as reservas 17 | 18 | `reservas.txt` 19 | # cliente, quarto, dias 20 | Bruno,3,12 21 | 22 | Se outro usuário tentar reservar o mesmo quarto o programa deve exibir uma 23 | mensagem informando que já está reservado. 24 | """ 25 | import sys 26 | import logging 27 | 28 | RESERVAS_FILE = "reservas.txt" 29 | QUARTOS_FILE = "quartos.txt" 30 | 31 | # Acesso ao banco de dados 32 | 33 | # TODO: Usar pacote csv 34 | 35 | ocupados = {} # acumulador 36 | try: 37 | for line in open(RESERVAS_FILE): 38 | nome_cliente, num_quarto, dias = line.strip().split(",") 39 | ocupados[int(num_quarto)] = { 40 | "nome_cliente": nome_cliente, 41 | "dias": int(dias), 42 | } 43 | except FileNotFoundError: 44 | logging.error("arquivo %s não existe", RESERVAS_FILE) 45 | sys.exit(1) 46 | 47 | 48 | # TODO: Usar função para ler os arquivos 49 | 50 | quartos = {} # acumulador 51 | try: 52 | for line in open(QUARTOS_FILE): 53 | num_quarto, nome_quarto, preco = line.strip().split(",") 54 | quartos[int(num_quarto)] = { 55 | "nome_quarto": nome_quarto, 56 | "preco": float(preco), # TODO: Usar Decimal 57 | "disponivel": False if int(num_quarto) in ocupados else True, 58 | } 59 | except FileNotFoundError: 60 | logging.error("arquivo %s não existe", QUARTOS_FILE) 61 | sys.exit(1) 62 | 63 | # Programa principal 64 | print("Reservas no Hotel Pythonico da Linux Tips") 65 | print("-" * 52) 66 | if len(ocupados) == len(quartos): 67 | print("Hotel está lotado, volte depois.") 68 | sys.exit(0) 69 | 70 | nome_cliente = input("Qual é o seu nome:").strip() 71 | print() 72 | 73 | # TODO: Usar rich.Table 74 | print("Lista de quartos") 75 | print() 76 | head = ["Número", "Nome do Quarto", "Preço", "Disponível"] 77 | print(f"{head[0]:<6} - {head[1]:<14} - R$ {head[2]:<9} - {head[3]:<10}") 78 | for num_quarto, dados_quarto in quartos.items(): 79 | nome_quarto = dados_quarto["nome_quarto"] 80 | preco = dados_quarto["preco"] 81 | disponivel = "⛔" if not dados_quarto["disponivel"] else "👍" 82 | print( 83 | f"{num_quarto:<6} - {nome_quarto:<14} - " f"R$ {preco:<9.2f} - {disponivel:<10}" 84 | ) 85 | 86 | print("-" * 52) 87 | # reserva 88 | 89 | try: 90 | num_quarto = int(input("Qual o quarto desejado:").strip()) 91 | if not quartos[num_quarto]["disponivel"]: 92 | print(f"O quarto {num_quarto} está ocupado, escolha outro.") 93 | sys.exit(0) 94 | except KeyError: 95 | print(f"O Quarto {num_quarto} não existe.") 96 | sys.exit(0) 97 | except ValueError: 98 | print("Número inválido, digite apenas digitos.") 99 | sys.exit(0) 100 | 101 | try: 102 | dias = int(input("Quantos dias:").strip()) 103 | except ValueError: 104 | print("Número inválido, digite apenas digitos.") 105 | sys.exit(0) 106 | 107 | nome_quarto = quartos[num_quarto]["nome_quarto"] 108 | preco_diaria = quartos[num_quarto]["preco"] 109 | total = dias * preco_diaria 110 | 111 | print( 112 | f"Olá {nome_cliente}, você escolheu o quarto {nome_quarto} " 113 | f"o valor total estimado será R$ {total:.2f}" 114 | ) 115 | 116 | if input("Confirma? (digite y)").strip().lower() in ("y", "yes", "sim", "s"): 117 | with open(RESERVAS_FILE, "a") as reserva_file: 118 | reserva_file.write(f"{nome_cliente},{num_quarto},{dias}\n") 119 | -------------------------------------------------------------------------------- /09_exercicios/reservas.txt: -------------------------------------------------------------------------------- 1 | Bruno,2,6 2 | -------------------------------------------------------------------------------- /09_smtp/smtp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """Exemplos de envio de e-mail""" 3 | import smtplib 4 | 5 | SERVER = "localhost" 6 | PORT = 8025 7 | 8 | FROM = "bruno@rocha.com" 9 | TO = ["destino1@server.com", "destino2@server.com"] 10 | SUBJECT = "Meu e-mail via Python" 11 | TEXT = """\ 12 | Este é o meu e-mail enviado pelo Python 13 | Olá mundo 14 | """ 15 | 16 | # SMTP 17 | message = f"""\ 18 | From: {FROM} 19 | To: {", ".join(TO)} 20 | Subject: {SUBJECT} 21 | 22 | {TEXT} 23 | """ 24 | 25 | 26 | with smtplib.SMTP(host=SERVER, port=PORT) as server: 27 | server.sendmail(FROM, TO, message.encode("utf-8")) 28 | -------------------------------------------------------------------------------- /10_funcao/anatomia_funcoes.py: -------------------------------------------------------------------------------- 1 | """\ 2 | Este modulo serve apenas de anotação. 3 | """ 4 | 5 | # definição ou atribuição 6 | # assinatura + type hints 7 | # documentacao / docstring 8 | # codigo 9 | # valor de retorno 10 | 11 | # - parametros 12 | # posicional - passados em ordem 13 | 14 | 15 | def nome_da_funcao(a, b, c): 16 | """Esta função faz algo com a, b e c. 17 | 18 | Use esta função quando quiser a + b + c 19 | quando o parametro a tiver o valor 10 20 | vai acontecer x. 21 | 22 | >>> nome_da_funcao(1, 2, 3) 23 | 6 24 | """ 25 | resultado = a + b + c 26 | return resultado 27 | 28 | 29 | # passagem de argumentos posicionais 30 | valor = nome_da_funcao(1, 2, 3) 31 | 32 | # passagem de argumentos nomeados 33 | valor = nome_da_funcao(a=1, b=2, c=3) 34 | valor = nome_da_funcao(c=1, b=2, a=3) 35 | valor = nome_da_funcao(b=1, a=2, c=3) 36 | 37 | # passagem de argumentos mista 38 | # argumentos posicionais antes dos nomeados 39 | valor = nome_da_funcao(1, 2, c=3) 40 | valor = nome_da_funcao(1, c=2, b=3) 41 | 42 | # funcao com muitos argumentos 43 | valor = nome_da_funcao( 44 | 1, 45 | c=2, 46 | b=3, 47 | ) 48 | 49 | print(valor) 50 | 51 | 52 | ########################### 53 | 54 | 55 | def outra_funcao(a, b, c): 56 | """Explica o que ela faz""" 57 | # tupla como valor de retorno 58 | return a * 2, b * 2, c * 2 59 | 60 | 61 | valor1, valor2, valor3 = outra_funcao(1, 2, 3) 62 | print(valor1) 63 | print(valor2) 64 | print(valor3) 65 | 66 | valor1, *resto = outra_funcao(1, 2, 3) 67 | print(valor1) 68 | print(resto) 69 | 70 | 71 | ################################ 72 | 73 | 74 | # Passagem de argumentos com desempacotamento 75 | 76 | 77 | def soma(n1, n2): 78 | """Faz a soma de 2 numeros.""" 79 | return n1 + n2 80 | 81 | 82 | # normal 83 | print(soma(10, 20)) 84 | 85 | # argumentos em sequencia / posicional 86 | args = (20, 30) # tuple, list, str 87 | # print(soma(args[0], args[1])) 88 | print(soma(*args)) 89 | 90 | 91 | # argumentos dicionario / nomeados 92 | args = {"n2": 90, "n1": 100} # dict, hashmap 93 | # print(soma(n1=args["n1"], n2=args["n2"])) 94 | print(soma(**args)) 95 | 96 | lista_de_valores_para_somar = [ 97 | {"n2": 90, "n1": 100}, 98 | {"n2": 90, "n1": 200}, 99 | {"n2": 9, "n1": 650}, 100 | (5, 10), 101 | [8, 13], 102 | ] 103 | 104 | for item in lista_de_valores_para_somar: 105 | if isinstance(item, dict): 106 | print(soma(**item)) 107 | else: 108 | print(soma(*item)) 109 | 110 | 111 | ############################### -------------------------------------------------------------------------------- /10_funcao/composicao.py: -------------------------------------------------------------------------------- 1 | """Imprime apenas os nomes iniciados com a letra B""" 2 | 3 | names = [ 4 | "Bruno", 5 | "Joao", 6 | "Bernardo", 7 | "Barbara", 8 | "Brian", 9 | ] 10 | 11 | 12 | # estilo funcional 13 | print("Estilo funcional") 14 | print(*list(filter(lambda text: text[0].lower() == "b", names)), sep="\n") 15 | 16 | print() 17 | 18 | # estilo imperativo 19 | print("Estilo procedural") 20 | 21 | 22 | def starts_with_b(text): 23 | """Return bool if text starts with b""" 24 | return text[0].lower() == "b" 25 | 26 | 27 | filtro = filter(starts_with_b, names) 28 | filtro = list(filtro) 29 | for name in filtro: 30 | print(name) 31 | -------------------------------------------------------------------------------- /10_funcao/coringas.py: -------------------------------------------------------------------------------- 1 | # SOLID - Single REsponsibility 2 | def funcao(*args, timeout=10, **options): 3 | for item in args: 4 | print(item) 5 | print(options) 6 | 7 | print(f"timeout {timeout}") 8 | 9 | 10 | funcao( 11 | "Bruno", 12 | 1, 13 | True, 14 | timeout=90, 15 | nome="Joao", 16 | cidade="Viana", 17 | data="hoje", 18 | banana=1, 19 | panela=3, 20 | teclado=True, 21 | ) 22 | -------------------------------------------------------------------------------- /10_funcao/funcoes.py: -------------------------------------------------------------------------------- 1 | """Exemplos de funções""" 2 | 3 | """ 4 | f(x) = 5 * (x / 2) 5 | """ 6 | 7 | 8 | # Solid - Single Responsibility 9 | 10 | 11 | def f(x): # assinatura 12 | result = 5 * (x / 2) 13 | ... 14 | return result 15 | 16 | 17 | def double(x): 18 | return x * 2 19 | 20 | 21 | valor = double(f(10)) 22 | 23 | print(valor) 24 | print(valor == 50) 25 | 26 | 27 | def print_in_upper(text): 28 | """Procedure with no explicit return""" 29 | print(text.upper()) 30 | # implicit return None 31 | 32 | 33 | print_in_upper("bruno") 34 | 35 | #### 36 | 37 | 38 | def heron(a, b, c): 39 | """Calcula a area de um triangulo""" 40 | perimeter = a + b + c 41 | s = perimeter / 2 42 | area = s * (s - a) * (s - b) * (s - c) 43 | return area**0.5 # math.sqrt(area) 44 | 45 | 46 | triangulos = [ 47 | (3, 4, 5), 48 | (5, 12, 13), 49 | (8, 15, 17), 50 | (12, 35, 37), 51 | (3, 4, 5), 52 | (5, 12, 13), 53 | (8, 15, 17), 54 | (12, 35, 37), 55 | ] 56 | 57 | for t in triangulos: 58 | area = heron(*t) 59 | print(f"A area do triangulo é: {area}") 60 | 61 | 62 | #### 63 | 64 | 65 | def nome_da_funcao(): 66 | print("Hello funcao") 67 | return 1 68 | 69 | 70 | result = nome_da_funcao() 71 | print(result) 72 | -------------------------------------------------------------------------------- /10_funcao/heron.py: -------------------------------------------------------------------------------- 1 | def heron(a, b, c): 2 | perimeter = a + b + c 3 | s = perimeter / 2 4 | area = (s * (s - a) * (s - b) * (s - c)) ** 0.5 5 | return area 6 | 7 | 8 | a = int(input("Digite o valor de a: ").strip()) 9 | b = int(input("Digite o valor de b: ").strip()) 10 | c = int(input("Digite o valor de c: ").strip()) 11 | 12 | print("A área do triângulo é: ", heron(a, b, c)) 13 | 14 | triangulos = [ 15 | (3, 4, 5), 16 | (5, 12, 13), 17 | (8, 15, 17), 18 | (12, 35, 37), 19 | (3, 4, 5), 20 | (5, 12, 13), 21 | (8, 15, 17), 22 | (12, 35, 37), 23 | ] 24 | for t in triangulos: 25 | print("A área do triângulo é: ", heron(*t)) 26 | -------------------------------------------------------------------------------- /10_funcao/lambdas.py: -------------------------------------------------------------------------------- 1 | def transforma_em_maiusculo(texto): 2 | return texto.upper() 3 | 4 | 5 | def transforma_em_minusculo(texto): 6 | return texto.lower() 7 | 8 | 9 | def divide_por_2(numero): 10 | return numero // 2 11 | 12 | 13 | # e nossa função principal 14 | 15 | 16 | def faz_algo(valor, funcao): 17 | print(f"Aplicando {funcao} em {valor}") 18 | return funcao(valor) 19 | 20 | 21 | names = ["Bruno", "Joao", "Bernado", "Cintia", "Marcia", "Juca"] 22 | 23 | print(sorted(names, key=lambda name: name.count("i"))) 24 | 25 | print(list(filter(lambda name: name[0].lower() == "b", names))) 26 | 27 | print(list(map(lambda name: "Hello " + name, names))) 28 | 29 | 30 | # Calculadora 31 | 32 | operacao = input("operacao [sum, mul, div, sub]:").strip() 33 | n1 = input("n1:").strip() 34 | n2 = input("n2:").strip() 35 | 36 | 37 | def soma(a, b): 38 | return a + b 39 | 40 | 41 | operacoes = { 42 | "sum": soma, 43 | "sub": lambda a, b: a - b, 44 | "mul": lambda a, b: a * b, 45 | "div": lambda a, b: a / b, 46 | } 47 | 48 | resultado = operacoes[operacao](int(n1), int(n2)) 49 | print(f"O resultado é: {resultado}") 50 | -------------------------------------------------------------------------------- /10_funcao/questions.py: -------------------------------------------------------------------------------- 1 | def welcome(): 2 | print("Welcome to the test.") 3 | input("When you are ready press enter.") 4 | 5 | 6 | def ask_questions(ask_color=False): 7 | name = input("name:") 8 | print(f"It is nice to meet you {name}") 9 | 10 | if ask_color: 11 | color = input("Quat is your favorite color?") 12 | print(f"{color} is a great color!") 13 | 14 | input("Describe yourself") 15 | print("admirable!") 16 | 17 | 18 | def goodbye(): 19 | print("Goodbye.") 20 | 21 | 22 | welcome() 23 | ask_questions(ask_color=True) 24 | goodbye() 25 | -------------------------------------------------------------------------------- /10_funcao/valores_default.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | 4 | def imprime_nome(nome, sobrenome="Sabugosa"): 5 | # escopo local {nome: .., sobrenome: ..} 6 | print(f"Seu nome é {nome} {sobrenome}") 7 | 8 | 9 | imprime_nome("Bruno", "Rocha") 10 | imprime_nome("Linus") 11 | 12 | 13 | def conecta(host, timeout=10): 14 | print(f"conectando com {host}") 15 | for i in range(1, timeout + 1): 16 | time.sleep(1) 17 | print("." * i) 18 | print("erro ao conectar") 19 | 20 | 21 | conecta("localhost") 22 | -------------------------------------------------------------------------------- /10_funcao/valores_default_mutaveis.py: -------------------------------------------------------------------------------- 1 | # set, dict, list 2 | 3 | 4 | def adiciona_a_lista(valor, lista=None): 5 | if lista is None: 6 | lista = [] 7 | lista.append(valor) 8 | return lista 9 | 10 | 11 | adiciona_a_lista(4) 12 | adiciona_a_lista(4) 13 | adiciona_a_lista(4) 14 | adiciona_a_lista(4) 15 | adiciona_a_lista(5) 16 | print(adiciona_a_lista(6)) 17 | -------------------------------------------------------------------------------- /11_escopos/contador.py: -------------------------------------------------------------------------------- 1 | contador = 0 2 | 3 | 4 | def incrementa_contador(): 5 | # ... comeca o escopo local 6 | # assignment `=` `+=` `-=` 7 | global contador 8 | contador += 1 9 | 10 | 11 | incrementa_contador() 12 | incrementa_contador() 13 | incrementa_contador() 14 | incrementa_contador() 15 | 16 | print(contador) 17 | -------------------------------------------------------------------------------- /11_escopos/escopo.py: -------------------------------------------------------------------------------- 1 | # aqui começa o escopo global 2 | nome = "Global" 3 | 4 | 5 | def funcao(): 6 | # aqui começa o escopo local da funcao 7 | nome = "Local" 8 | 9 | # Aqui é o escopo `enclosing` para a função interna 10 | def funcao_interna(): # inner function 11 | # aqui começa o escopo local da funcao interna 12 | nome = "Interna" 13 | 14 | print("Escopo local da funcao interna:", locals()) 15 | # print("*" * 30) 16 | 17 | print(nome) 18 | return nome 19 | # aqui termina o escopo local da funcao interna 20 | 21 | print("Escopo local da funcao:", locals()) 22 | print("=" * 30) 23 | 24 | funcao_interna() 25 | print(nome) 26 | 27 | return nome 28 | # aqui termina o escopo local da funcao 29 | 30 | 31 | print("Escopo global do programa", globals()) 32 | # print("-" * 30) 33 | 34 | funcao() 35 | print(nome) 36 | # aqui termina o escopo global 37 | -------------------------------------------------------------------------------- /11_escopos/forcando_global.py: -------------------------------------------------------------------------------- 1 | nome = "Global" 2 | 3 | 4 | def funcao(): 5 | nome = "Local" 6 | print("Nome Local:", nome) 7 | nome = globals()["nome"] 8 | print("Nome Global:", nome) 9 | 10 | 11 | funcao() 12 | -------------------------------------------------------------------------------- /11_escopos/non_local.py: -------------------------------------------------------------------------------- 1 | contador = 0 2 | 3 | 4 | def funcao(): 5 | global contador 6 | contador += 1 7 | 8 | subcontador = 0 9 | 10 | def funcao_interna(): 11 | global contador 12 | contador += 1 13 | 14 | nonlocal subcontador 15 | subcontador += 1 16 | 17 | funcao_interna() 18 | 19 | 20 | funcao() 21 | funcao() 22 | 23 | print(contador) 24 | -------------------------------------------------------------------------------- /12_debug/tembug.py: -------------------------------------------------------------------------------- 1 | def repete_vogal(word): 2 | """Retorna a palavra com as vogais repetidas.""" 3 | final_word = "" 4 | for letter in word: 5 | if letter.lower() in "aeiouãõâôêéáíó": 6 | breakpoint() 7 | final_word = letter * 2 # HINT 8 | else: 9 | final_word = letter # hint 10 | return final_word 11 | 12 | 13 | print(repete_vogal("banana")) 14 | -------------------------------------------------------------------------------- /13_poo/band.py: -------------------------------------------------------------------------------- 1 | from instruments import Guitar, Flute, InstrumentKind, EletricGuitar, Distortion 2 | 3 | 4 | gianini = Guitar("Giannini m2", kind=InstrumentKind.string, colors=["green"]) 5 | print(gianini) 6 | print(gianini.play()) 7 | print("colors", gianini.colors) 8 | print() 9 | 10 | yamaha = Flute("Yamaha Magic Flute", colors=["silver"]) 11 | print(yamaha) 12 | print(yamaha.play()) 13 | print("colors", yamaha.colors) 14 | print() 15 | 16 | lespaul = EletricGuitar("lespaul m1", colors=["brown", "yellow"]) 17 | print(lespaul) 18 | print(lespaul.play(distortion=Distortion.normal)) 19 | print(lespaul.play(distortion=Distortion.whisper)) 20 | print(lespaul.play(distortion=Distortion.wave)) 21 | print("colors", lespaul.colors) 22 | print() 23 | -------------------------------------------------------------------------------- /13_poo/exercicio1.py: -------------------------------------------------------------------------------- 1 | """ 2 | Este programa pergunta ao usuário quais items ele deseja comprar 3 | e calcula o valor total da compra. 4 | 5 | 1. Clique em Run e execute o programa para ver como ele funciona. 6 | 2. Para cada um dos comentários marcados abaixo efetue as alterações 7 | usando orientação a objetos. 8 | """ 9 | from decimal import Decimal 10 | 11 | produtos = { 12 | "1": { 13 | "nome": "Maça", 14 | "valor": Decimal(4.5) 15 | # para valores monetários devemos usar Decimal ao invés de float 16 | }, 17 | "2": {"nome": "Melancia", "valor": Decimal(6.3)}, 18 | } 19 | 20 | ############################################################################### 21 | # 1. 22 | # `produtos` acima é um objeto do tipo `dict` que contém produtos que 23 | # também estão no formato `dict`. 24 | # Desafio: Crie uma classe `Produto` para armazenar `nome` e `valor` 25 | # Faça com que o dicionário `Produtos` armazene instancias de `Produto` 26 | # No lugar de sub dicionários. 27 | ############################################################################### 28 | 29 | print("Olá cliente, boas vindas à quitanda!") 30 | print("Estes são os produtos disponíveis:") 31 | for codigo, produto in produtos.items(): 32 | print(f"{codigo} -> {produto['nome']} - R$ {produto['valor']:.2f}") 33 | 34 | ############################################################################### 35 | # 2. 36 | # Altere as linhas acima para imprimir as informações usando o objeto Produto 37 | ############################################################################### 38 | 39 | compra = {"cliente": input("Qual o seu nome?"), "items": []} 40 | 41 | 42 | def calcula_total(compra): 43 | """Calcula o total da compra""" 44 | total = 0 45 | for cod_produto, quantidade in compra["items"]: 46 | produto = produtos[cod_produto] 47 | total += produto["valor"] * quantidade 48 | return Decimal(total) 49 | 50 | 51 | ############################################################################### 52 | # 3. 53 | # Crie uma classe `Compra` que contenha os atributos `cliente` e `items` e 54 | # utilize uma instância desta classe para substituir o dicionário `compra` 55 | # e transforme a função `calcula_total` em um método ou propriedade da classe 56 | ############################################################################### 57 | 58 | while True: 59 | cod_produto = input("Código do produto: [enter para sair]").strip() 60 | if not cod_produto: 61 | break 62 | if cod_produto not in produtos: 63 | print("Codigo inválido tente novamente.") 64 | continue 65 | quantidade = int(input("Quantas Unidades?:").strip()) 66 | compra["items"].append([cod_produto, quantidade]) 67 | 68 | print(f"Olá, {compra['cliente']}") 69 | print(f"No seu carrinho de compras tem {len(compra['items'])} item.") 70 | print(f"O total da compra é {calcula_total(compra):.2f}") 71 | 72 | ############################################################################### 73 | # 4. 74 | # Certifique-se de que o programa continua funcionando após as alterações. 75 | ############################################################################### 76 | -------------------------------------------------------------------------------- /13_poo/exercicio1_resolvido.py: -------------------------------------------------------------------------------- 1 | """ 2 | Este programa pergunta ao usuário quais items ele deseja comprar 3 | e calcula o valor total da compra. 4 | 5 | 1. Clique em Run e execute o programa para ver como ele funciona. 6 | 2. Para cada um dos comentários marcados abaixo efetue as alterações 7 | usando orientação a objetos. 8 | """ 9 | from decimal import Decimal 10 | 11 | 12 | class Produto: 13 | def __init__(self, nome, valor): 14 | self.nome = nome 15 | self.valor = Decimal(valor) 16 | 17 | 18 | produtos = {"1": Produto("Maça", 4.5), "2": Produto("Melancia", 6.3)} 19 | 20 | print("Olá cliente, boas vindas à quitanda!") 21 | print("Estes são os produtos disponíveis:") 22 | 23 | # ("1", Produto(...)) 24 | for codigo, produto in produtos.items(): 25 | print(f"{codigo} -> {produto.nome} - R$ {produto.valor:.2f}") 26 | 27 | 28 | 29 | class Item: 30 | def __init__(self, produto, quantidade): 31 | self.produto = produto 32 | self.quantidade = quantidade 33 | 34 | 35 | class Compra: 36 | def __init__(self, cliente, items=None): 37 | self.cliente = cliente 38 | # if items is None: 39 | # self.items = [] 40 | self.items = items or [] 41 | 42 | @property 43 | def total(self): 44 | """Calcula o total da compra""" 45 | total = sum( 46 | [item.produto.valor * item.quantidade for item in self.items] 47 | ) 48 | return Decimal(total) 49 | 50 | def add_item(self, cod_produto, quantidade): 51 | self.items.append(Item(produtos[cod_produto], quantidade)) 52 | 53 | 54 | nome_cliente = input("Qual o seu nome?") 55 | compra = Compra(nome_cliente) 56 | 57 | while True: 58 | cod_produto = input("Código do produto: [enter para sair]").strip() 59 | if not cod_produto: 60 | break 61 | if cod_produto not in produtos: 62 | print("Codigo inválido tente novamente.") 63 | continue 64 | quantidade = int(input("Quantas Unidades?:").strip()) 65 | compra.add_item(cod_produto, quantidade) 66 | 67 | print(f"Olá, {compra.cliente}") 68 | print(f"No seu carrinho de compras tem {len(compra.items)} item.") 69 | print(f"O total da compra é {compra.total:.2f}") 70 | -------------------------------------------------------------------------------- /13_poo/exercicio1_resolvido_dataclass_rich.py: -------------------------------------------------------------------------------- 1 | """ 2 | Este programa pergunta ao usuário quais items ele deseja comprar 3 | e calcula o valor total da compra. 4 | 5 | 1. Clique em Run e execute o programa para ver como ele funciona. 6 | 2. Para cada um dos comentários marcados abaixo efetue as alterações 7 | usando orientação a objetos. 8 | """ 9 | from decimal import Decimal 10 | from dataclasses import dataclass, field 11 | from rich.table import Table 12 | from rich.console import Console 13 | 14 | 15 | console = Console() 16 | 17 | 18 | @dataclass 19 | class Produto: 20 | nome: str 21 | _valor: Decimal 22 | 23 | @property 24 | def valor(self) -> Decimal: 25 | return self._valor 26 | 27 | @valor.setter 28 | def valor(self, value: Decimal | int): 29 | self._valor = Decimal(value) 30 | 31 | 32 | produtos = { 33 | "1": Produto("Maça", Decimal(4.5)), 34 | "2": Produto("Melancia", Decimal(6.3)), 35 | } 36 | 37 | 38 | print("Olá cliente, boas vindas à quitanda!") 39 | table = Table(title="Produtos disponíveis") 40 | table.add_column("Código") 41 | table.add_column("Produto") 42 | table.add_column("Valor") 43 | for codigo, produto in produtos.items(): 44 | table.add_row(str(codigo), produto.nome, f"{produto.valor:.2f}") 45 | console.print(table) 46 | 47 | 48 | @dataclass 49 | class Item: 50 | produto: Produto 51 | quantidade: int 52 | 53 | 54 | @dataclass 55 | class Cliente: 56 | nome: str 57 | 58 | def __str__(self) -> str: 59 | return self.nome 60 | 61 | 62 | @dataclass 63 | class Compra: 64 | cliente: Cliente 65 | items: list[Item] = field(default_factory=list) 66 | 67 | @property 68 | def total(self) -> Decimal: 69 | """Calcula o total da compra""" 70 | total = sum( 71 | [item.produto.valor * item.quantidade for item in self.items] 72 | ) 73 | return Decimal(total) 74 | 75 | def __len__(self): 76 | return len(self.items) 77 | 78 | def __iadd__(self, other): 79 | cod_produto, quantidade = other 80 | self.items.append(Item(produtos[cod_produto], quantidade)) 81 | return self 82 | 83 | def __str__(self) -> str: 84 | return f"No carrinho tem {len(self)} item e custa R${self.total:.2f}" 85 | 86 | def show(self): 87 | table = Table(title=f"Carrinho de compras de {self.cliente}") 88 | table.add_column("nome") 89 | table.add_column("valor") 90 | table.add_column("quantidade") 91 | for item in self.items: 92 | table.add_row( 93 | item.produto.nome, 94 | f"{item.produto.valor:.2f}", 95 | str(item.quantidade) 96 | ) 97 | table.add_row() 98 | table.add_row("[bold magenta]Total[/]", "", f"{self.total:.2f}") 99 | console.print(table) 100 | 101 | 102 | nome_cliente = input("Qual o seu nome?") 103 | cliente = Cliente(nome_cliente) 104 | compra = Compra(cliente) 105 | 106 | 107 | while True: 108 | cod_produto = input("Código do produto: [enter para sair]").strip() 109 | if not cod_produto: 110 | break 111 | if cod_produto not in produtos: 112 | print("Codigo inválido tente novamente.") 113 | continue 114 | quantidade = int(input("Quantas Unidades?:").strip()) 115 | compra += (cod_produto, quantidade) 116 | 117 | 118 | compra.show() 119 | -------------------------------------------------------------------------------- /13_poo/exercicio1_resolvido_dataclasses.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal 2 | from dataclasses import dataclass, field 3 | from typing import List, Iterator, Tuple 4 | 5 | 6 | @dataclass 7 | class Produto: 8 | nome: str 9 | _valor: Decimal 10 | 11 | @property 12 | def valor(self) -> Decimal: 13 | return self._valor 14 | 15 | @valor.setter 16 | def valor(self, value: Decimal | int | float): 17 | self._valor = Decimal(value) 18 | 19 | 20 | @dataclass 21 | class Estoque: 22 | _items: List[Produto] = field(default_factory=list) 23 | 24 | def add_produto(self, produto: Produto): 25 | self._items.append(produto) 26 | 27 | def listar(self) -> List[Produto]: 28 | return self._items 29 | 30 | def __iter__(self) -> Iterator[Tuple[str, Produto]]: 31 | return iter( 32 | [ 33 | (str(cod_produto), produto) 34 | for cod_produto, produto in enumerate(self._items, 1) 35 | ] 36 | ) 37 | 38 | def pegar_produto_pelo_codigo(self, cod) -> Produto: 39 | return self._items[int(cod) - 1] 40 | 41 | def __getitem__(self, item) -> Produto: 42 | return self.pegar_produto_pelo_codigo(item) 43 | 44 | 45 | 46 | estoque = Estoque() 47 | estoque.add_produto(Produto("Maça", Decimal(4.5))) 48 | estoque.add_produto(Produto("Melancia", Decimal(6.3))) 49 | 50 | print("Olá cliente, boas vindas à quitanda!") 51 | print("Estes são os produtos disponíveis:") 52 | for codigo, produto in estoque: 53 | print(f"{codigo} -> {produto.nome} - R$ {produto.valor:.2f}") 54 | 55 | 56 | @dataclass 57 | class Item: 58 | produto: Produto 59 | quantidade: int 60 | 61 | 62 | @dataclass 63 | class Cliente: 64 | nome: str 65 | 66 | def __str__(self): 67 | return self.nome 68 | 69 | 70 | @dataclass 71 | class Compra: 72 | cliente: Cliente 73 | items: List[Item] = field(default_factory=list) 74 | 75 | @property 76 | def total(self) -> Decimal: 77 | """Calcula o total da compra""" 78 | total = sum( 79 | [item.produto.valor * item.quantidade for item in self.items] 80 | ) 81 | return Decimal(total) 82 | 83 | def add_item(self, produto: Produto, quantidade: int): 84 | self.items.append(Item(produto, quantidade)) 85 | 86 | 87 | nome_cliente = input("Qual o seu nome?") 88 | cliente = Cliente(nome_cliente) 89 | compra = Compra(cliente) 90 | 91 | 92 | while True: 93 | cod_produto = input("Código do produto: [enter para sair]").strip() 94 | if not cod_produto: 95 | break 96 | 97 | produto = estoque.pegar_produto_pelo_codigo(cod_produto) 98 | # produto = estoque[cod_produto] 99 | 100 | quantidade = int(input("Quantas Unidades?:").strip()) 101 | compra.add_item(produto, quantidade) 102 | 103 | print(f"Olá, {compra.cliente}") 104 | print(f"No seu carrinho de compras tem {len(compra.items)} item.") 105 | print(f"O total da compra é {compra.total:.2f}") 106 | -------------------------------------------------------------------------------- /13_poo/funcional.py: -------------------------------------------------------------------------------- 1 | people = [ 2 | {"name": "Jim Halpert", "balance": 500, "role": "Salesman"}, 3 | {"name": "Dwight Schrute", "balance": 100, "role": "Manager"}, 4 | ] 5 | 6 | 7 | def add_points(person, value): 8 | data = person.copy() 9 | if data["role"] == "manager": 10 | value *= 2 11 | data["balance"] += value 12 | return data 13 | 14 | 15 | result = map(lambda person: add_points(person, 100), people) 16 | print("Resultado funcional:", list(result)) 17 | 18 | print("Dados originais sem side effects:", people) 19 | -------------------------------------------------------------------------------- /13_poo/instruments.py: -------------------------------------------------------------------------------- 1 | # Abstração e Herança com dataclasse? 2 | # Tem enum no Python? 3 | # dataclasses com valor default dão erro. 4 | # para que serve o super()? 5 | 6 | from abc import ABC, abstractmethod 7 | from dataclasses import dataclass, field 8 | from enum import Enum 9 | from typing import List 10 | 11 | 12 | # Enumeração / Enumerador 13 | class InstrumentKind(str, Enum): 14 | string = "string" 15 | wind = "wind" 16 | keys = "keys" 17 | drums = "drums" 18 | 19 | 20 | class Distortion(str, Enum): 21 | wave = "wave" 22 | whisper = "whisper" 23 | normal = "normal" 24 | 25 | 26 | class ABCInstrument(ABC): 27 | 28 | @abstractmethod 29 | def play(self): 30 | ... 31 | 32 | 33 | @dataclass 34 | class DataInstrumentMixin: 35 | name: str 36 | sound: str 37 | kind: InstrumentKind 38 | colors: List[str] = field(default_factory=list) 39 | 40 | def __str__(self): 41 | return f"" 42 | 43 | class Instrument(DataInstrumentMixin, ABCInstrument): 44 | ... 45 | 46 | 47 | @dataclass 48 | class Guitar(Instrument): 49 | n_strings: int = 6 50 | sound: str = "Ding Ding Ding" 51 | kind: InstrumentKind = InstrumentKind.string 52 | colors: List[str] = field(default_factory=lambda: ["red", "black"]) 53 | 54 | def play(self): 55 | return self.sound 56 | 57 | 58 | @dataclass 59 | class EletricGuitar(Guitar): 60 | sound: str = "Wah Wah Wah" 61 | 62 | def play(self, distortion: Distortion = Distortion.wave): 63 | return_from_base_class = super().play() 64 | if distortion is Distortion.wave: 65 | return "~~~".join(return_from_base_class.split()) 66 | elif distortion is Distortion.whisper: 67 | return "...".join(return_from_base_class.split()) 68 | return return_from_base_class 69 | 70 | 71 | 72 | @dataclass 73 | class Flute(Instrument): 74 | sound: str = "Flu Flu Flu" 75 | kind: InstrumentKind = InstrumentKind.wind 76 | colors: List[str] = field(default_factory=lambda: ["beige", "white"]) 77 | 78 | def play(self): 79 | return self.sound 80 | -------------------------------------------------------------------------------- /13_poo/match_turtle.py: -------------------------------------------------------------------------------- 1 | # Python 3.10 2 | # Pattern Match Estrutural 3 | print( 4 | """\ 5 | Jogo da Tartaruga 6 | 7 | comandos: 8 | move x y 9 | move steps 10 | turn angle (default 90) 11 | draw shape size (line|circle) 12 | write text 13 | stop | exit 14 | """ 15 | ) 16 | 17 | from turtle import Turtle 18 | 19 | turtle = Turtle() 20 | turtle.shape("turtle") 21 | turtle.speed(3) 22 | turtle.color("blue", "yellow") 23 | turtle.penup() 24 | 25 | while True: 26 | command: list[str] = input("🐢>").strip().split() 27 | 28 | match command: 29 | 30 | case ["move", *points]: 31 | match points: 32 | case [x, y]: 33 | turtle.goto(float(x), float(y)) 34 | case [steps]: 35 | turtle.forward(float(steps)) 36 | 37 | case ["turn", *options]: 38 | match options: 39 | case [angle]: 40 | turtle.right(float(angle)) 41 | case _: 42 | turtle.right(90) 43 | 44 | case ["draw", shape, size]: 45 | turtle.pendown() 46 | match shape: 47 | case "circle": 48 | turtle.circle(float(size)) 49 | case "line": 50 | turtle.forward(float(size)) 51 | turtle.penup() 52 | 53 | case ["write", *text]: 54 | turtle.write(" ".join(text), None, "center", "16pt 20") 55 | 56 | case ["exit" | "stop" | "quit"]: 57 | break 58 | 59 | case _: 60 | print("Invalid command") 61 | -------------------------------------------------------------------------------- /13_poo/oo.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass 5 | class Pessoa: 6 | pk: str 7 | name: str 8 | points: int = 100 9 | 10 | 11 | def funcao(dados: Pessoa): 12 | ... 13 | 14 | 15 | dados = Pessoa(pk="joe@doe.com", name="Joe", points=10) 16 | 17 | print(dados.name) 18 | 19 | funcao(dados) 20 | -------------------------------------------------------------------------------- /13_poo/oo_v1.py: -------------------------------------------------------------------------------- 1 | # Definição da classe 2 | class Person: 3 | """Represents a Person""" 4 | 5 | # Atributos da classe 6 | name = "Jim Halpert" 7 | role = "Salesman" 8 | balance = 100 9 | 10 | # Métodos ou funções associadas 11 | def add_points(self, value): 12 | if self.role == "manager": 13 | value *= 2 14 | self.balance += value 15 | 16 | 17 | jim = Person() 18 | jim.add_points(500) 19 | print(jim.balance) 20 | 21 | 22 | print(Person.__dict__) 23 | 24 | 25 | pessoa1 = Person() 26 | pessoa2 = Person() 27 | 28 | print(pessoa1.name) 29 | print(pessoa2.name) 30 | 31 | 32 | print(id(pessoa1)) 33 | print(id(pessoa2)) 34 | 35 | print(id(pessoa1.name)) 36 | print(id(pessoa2.name)) 37 | print(id(Person.name)) 38 | 39 | pessoa1.add_points(100) 40 | pessoa2.add_points(200) 41 | 42 | print(pessoa1.__dict__) 43 | print(pessoa2.__dict__) 44 | 45 | 46 | class Fruit: 47 | name = "apple" 48 | 49 | 50 | apple = Fruit() 51 | apple.color = "red" 52 | 53 | banana = Fruit() 54 | banana.color = "yellow" 55 | 56 | print(apple.name, apple.color) 57 | print(banana.name, banana.color) 58 | 59 | 60 | class Fruit: 61 | def __init__(self, name, color): 62 | self.name = name 63 | self.color = color 64 | 65 | 66 | apple = Fruit(name="Apple", color="red") 67 | banana = Fruit("Banana", color="yellow") 68 | 69 | print(apple.name, apple.color) 70 | print(banana.name, banana.color) 71 | 72 | 73 | class Triangle: 74 | def __init__(self, a, b, c): 75 | self.a = a 76 | self.b = b 77 | self.c = c 78 | 79 | def area(self): 80 | perimeter = self.a + self.b + self.c 81 | s = perimeter / 2 82 | area = (s * (s - self.a) * (s - self.b) * (s - self.c)) ** 0.5 83 | return area 84 | 85 | 86 | triangle = Triangle(5, 12, 13) 87 | print(triangle.area()) 88 | 89 | triangle.a = 10 90 | print(triangle.area()) 91 | -------------------------------------------------------------------------------- /13_poo/oo_v2_abstracao.py: -------------------------------------------------------------------------------- 1 | class Person: 2 | """Represents a Person""" 3 | 4 | kingdom = "animalia" 5 | 6 | 7 | class Fruit: 8 | """Represents a fruit""" 9 | 10 | kingdom = "vegetalia" 11 | 12 | 13 | class Animal: 14 | """Represents an animal""" 15 | 16 | kingdom = "animalia" 17 | -------------------------------------------------------------------------------- /13_poo/oo_v3_heranca.py: -------------------------------------------------------------------------------- 1 | class Fruit: # Classe abstrata 2 | kingdom = "vegetalia" 3 | 4 | 5 | class Apple(Fruit): # Classe Material 6 | colors = ["red", "white"] 7 | image = "🍎" 8 | 9 | 10 | class Watermelon(Fruit): 11 | colors = ["green", "red"] 12 | image = "🍉" 13 | 14 | 15 | class Pineapple(Fruit): 16 | colors = ["yellow", "green"] 17 | image = "🍍" 18 | 19 | 20 | for fruit in [Apple(), Watermelon(), Pineapple()]: 21 | print(fruit.image, fruit.kingdom, fruit.colors) 22 | -------------------------------------------------------------------------------- /13_poo/oo_v4_abc.py: -------------------------------------------------------------------------------- 1 | class Fruit: # Classe abstrata 2 | kingdom = "vegetalia" 3 | 4 | 5 | class Apple(Fruit): # Classe Material 6 | colors = ["red", "white"] 7 | image = "🍎" 8 | 9 | 10 | fruit1 = Apple() # OK instancia criada a partir da classe material 11 | print(fruit1.kingdom) 12 | 13 | fruit2 = Fruit() # NÃO ok, instancia criada a partir da classe abstrata 14 | print(fruit2.kingdom) 15 | 16 | from abc import ABC 17 | 18 | 19 | class Fruit(ABC): # por convenção uma classe abstrata 20 | kingdom = "vegetalia" 21 | -------------------------------------------------------------------------------- /13_poo/oo_v5_polimorfismo.py: -------------------------------------------------------------------------------- 1 | objetos = [ 2 | ["Bruno"], # list 3 | ("Bruno",), # tuple 4 | set(["Bruno"]), # set 5 | {"Bruno": 1}, # dict 6 | ] 7 | 8 | for objeto in objetos: 9 | print("Bruno" in objeto) # todos implementam __contains__ 10 | 11 | 12 | class Dog: 13 | def make_sound(self): 14 | return "woof woof" 15 | 16 | 17 | class Cat: 18 | def make_sound(self): 19 | return "meow meow" 20 | 21 | 22 | class Bird: 23 | def make_sound(self): 24 | return "pew pew" 25 | 26 | 27 | def print_sound(obj): 28 | print(obj.make_sound()) 29 | 30 | 31 | print_sound(Dog()) 32 | print_sound(Cat()) 33 | print_sound(Bird()) 34 | 35 | # Todos implementam `make_sound` 36 | -------------------------------------------------------------------------------- /13_poo/oo_v6_encapsulamento.py: -------------------------------------------------------------------------------- 1 | class Conta: 2 | _tipo_de_conta = "corrente" 3 | __id_interno = 985645 4 | 5 | def __init__(self, cliente): 6 | self.cliente = cliente 7 | self._saldo = 0 8 | 9 | def depositar(self, value): 10 | self._saldo += value 11 | 12 | def sacar(self, value): 13 | self._saldo -= value 14 | return value 15 | 16 | def consultar(self): 17 | if self._saldo < 0: 18 | print("AVISO: Você está devendo") 19 | return self._saldo 20 | 21 | 22 | conta = Conta(cliente="Bruno") 23 | conta.depositar(100) 24 | conta.sacar(10) 25 | print(conta.consultar()) 26 | print(conta.cliente) 27 | print(dir(conta)) 28 | -------------------------------------------------------------------------------- /13_poo/oo_v7_properties.py: -------------------------------------------------------------------------------- 1 | class Conta: 2 | _tipo_de_conta = "corrente" 3 | __id_interno = 985645 4 | 5 | def __init__(self, cliente): 6 | self.cliente = cliente 7 | self._saldo = 0 8 | 9 | @property 10 | def saldo(self): 11 | if self._saldo < 0: 12 | print("AVISO: Você está devendo") 13 | return self._saldo 14 | 15 | @saldo.setter 16 | def saldo(self, value): 17 | self._saldo += value 18 | 19 | @saldo.deleter 20 | def saldo(self): 21 | self._saldo = 0 22 | 23 | 24 | conta = Conta(cliente="Bruno") 25 | conta.saldo = 100 26 | conta.saldo = -10 27 | print(conta.saldo) 28 | 29 | del conta.saldo 30 | print(conta.saldo) 31 | -------------------------------------------------------------------------------- /13_poo/oo_v8_protocolos.py: -------------------------------------------------------------------------------- 1 | # Printable 2 | # todos os objetos que implementam __str__ 3 | dados = [1, {"key": "value¨"}, True] 4 | print(dados) 5 | 6 | 7 | # customizando 8 | 9 | class Cor: 10 | icon = "⬜" 11 | 12 | def __str__(self): 13 | return self.icon 14 | 15 | 16 | class Amarelo(Cor): 17 | icon = "🟨" 18 | 19 | 20 | class Azul(Cor): 21 | icon = "🟦" 22 | 23 | 24 | class Vermelho(Cor): 25 | icon = "🟥" 26 | 27 | 28 | print("Cores primárias") 29 | print(Amarelo()) 30 | print(Azul()) 31 | print(Vermelho()) 32 | 33 | 34 | # Addible 35 | # Todos os objetos que implementam __add__ e/ou __radd__ 36 | 37 | 38 | class ColorMixError(Exception): 39 | """Error when mising colors doesn't result""" 40 | 41 | 42 | class Cor: 43 | def __str__(self): 44 | return self.icon 45 | 46 | def __eq__(self, other): 47 | return self.icon == other.icon 48 | 49 | def __add__(self, other): 50 | if not isinstance(other, Cor): 51 | raise ColorMixError("Unsuported types") 52 | if self == other: 53 | return self 54 | mixtable = [ 55 | ((Amarelo, Vermelho), Laranja), 56 | ((Azul, Amarelo), Verde), 57 | ((Vermelho, Azul), Violeta), 58 | ] 59 | for mix, result in mixtable: 60 | if isinstance(self, mix) and isinstance(other, mix): 61 | return result() 62 | 63 | 64 | class Amarelo(Cor): 65 | icon = "🟨" 66 | 67 | 68 | class Azul(Cor): 69 | icon = "🟦" 70 | 71 | 72 | class Vermelho(Cor): 73 | icon = "🟥" 74 | 75 | 76 | class Laranja(Cor): 77 | icon = "🟧" 78 | 79 | 80 | class Verde(Cor): 81 | icon = "🟩" 82 | 83 | 84 | class Violeta(Cor): 85 | icon = "🟪" 86 | 87 | 88 | print("Cores secundárias") 89 | print(Amarelo() + Vermelho()) 90 | print(Azul() + Amarelo()) 91 | print(Vermelho() + Azul()) 92 | print(Amarelo() + Amarelo()) 93 | 94 | # print("Tipagem forte") 95 | # print(Azul() + 1) 96 | 97 | 98 | # Iterable 99 | class Paleta: 100 | def __init__(self, *cores): 101 | self._cores = cores 102 | 103 | def __iter__(self): 104 | return iter([cor.icon for cor in self._cores]) 105 | 106 | 107 | print("rgb") 108 | rgb = Paleta(Vermelho(), Verde(), Azul()) 109 | for cor in rgb: 110 | print(cor, end="") 111 | 112 | 113 | # Container 114 | class Paleta: 115 | def __init__(self, *cores): 116 | self._cores = cores 117 | 118 | def __contains__(self, item): 119 | return item in [cor.icon for cor in self._cores] 120 | 121 | 122 | print("red in rgb?") 123 | rgb = Paleta(Vermelho(), Verde(), Azul()) 124 | print("🟥" in rgb) 125 | 126 | 127 | # Sized 128 | class Paleta: 129 | def __init__(self, *cores): 130 | self._cores = cores 131 | 132 | def __len__(self): 133 | return len(self._cores) 134 | 135 | 136 | print("rgb size") 137 | rgb = Paleta(Vermelho(), Verde(), Azul()) 138 | print(len(rgb)) 139 | 140 | 141 | # Sized + Container + Iterable = Collection 142 | 143 | class Paleta: 144 | def __init__(self, *cores): 145 | self._cores = cores 146 | 147 | def __len__(self): 148 | return len(self._cores) 149 | 150 | def __contains__(self, item): 151 | return item in [cor.icon for cor in self._cores] 152 | 153 | def __iter__(self): 154 | return iter([cor.icon for cor in self._cores]) 155 | 156 | # Uma `Paleta` é uma `Collection` de `Cor`es. 157 | 158 | 159 | # Subscriptable 160 | class Paleta: 161 | def __init__(self, *cores): 162 | self._cores = cores 163 | 164 | def __getitem__(self, item): 165 | if isinstance(item, (int, slice)): 166 | return self._cores[item] 167 | elif isinstance(item, str): 168 | for cor in self._cores: 169 | if cor.__class__.__name__.lower() == item.lower(): 170 | return cor 171 | 172 | rgb = Paleta(Vermelho(), Verde(), Azul()) 173 | print(rgb[0]) 174 | print(rgb["azul"]) 175 | 176 | 177 | # Mais protocolos 178 | # https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes 179 | 180 | 181 | class Thing: 182 | ... 183 | 184 | 185 | thing = Thing() 186 | print(thing) # __repr__ Representable 187 | thing == 1 # __eq__ Equality Comparable 188 | -------------------------------------------------------------------------------- /13_poo/procedural.py: -------------------------------------------------------------------------------- 1 | people = [ 2 | {"name": "Jim Halpert", "balance": 500, "role": "Salesman"}, 3 | {"name": "Dwight Schrute", "balance": 100, "role": "Manager"}, 4 | ] 5 | 6 | 7 | def add_points(person, value): 8 | if person["role"] == "manager": 9 | value *= 2 10 | person["balance"] += value 11 | return person 12 | 13 | 14 | for person in people: 15 | add_points(person, 100) 16 | 17 | print(people) 18 | -------------------------------------------------------------------------------- /13_poo/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/13_poo/requirements.txt -------------------------------------------------------------------------------- /14_modelagem/models.py: -------------------------------------------------------------------------------- 1 | import json 2 | from abc import ABC 3 | from dataclasses import dataclass 4 | from datetime import datetime 5 | from decimal import Decimal 6 | 7 | from dundie.database import connect 8 | from dundie.utils.email import check_valid_email 9 | 10 | 11 | class Serializable(ABC): 12 | def dict(self): 13 | return vars(self) 14 | 15 | 16 | @dataclass 17 | class Person(Serializable): 18 | pk: str 19 | name: str 20 | dept: str 21 | role: str 22 | 23 | def __post_init__(self): 24 | if not check_valid_email(self.pk): 25 | raise RuntimeError("Email is Invalid") 26 | 27 | 28 | @dataclass 29 | class Balance(Serializable): 30 | person: Person 31 | value: Decimal 32 | 33 | def dict(self): 34 | return {"person": self.person.pk, "value": str(self.value)} 35 | 36 | 37 | @dataclass 38 | class Movement(Serializable): 39 | person: Person 40 | date: datetime 41 | actor: str 42 | value: Decimal 43 | 44 | 45 | db = connect() 46 | 47 | people = [] 48 | for pk, data in db["people"].items(): 49 | people.append(Person(pk, **data)) 50 | 51 | 52 | person = people[0] 53 | print(person.dict()) 54 | 55 | print(json.dumps(person.dict())) 56 | 57 | balance = Balance(person=person, value=Decimal(100)) 58 | print(json.dumps(balance.dict())) 59 | -------------------------------------------------------------------------------- /14_modelagem/models_pydantic.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from decimal import Decimal 3 | from typing import Union 4 | from dundie.database import connect 5 | from pydantic import BaseModel, ValidationError, validator 6 | from dundie.utils.email import check_valid_email 7 | 8 | 9 | class Person(BaseModel): 10 | pk: str 11 | name: str 12 | dept: str 13 | role: str 14 | 15 | @validator("pk") 16 | def validate_email(cls, v): 17 | if not check_valid_email(v): 18 | raise ValidationError("Email is Invalid") 19 | return v 20 | 21 | 22 | class Balance(BaseModel): 23 | person: Person 24 | value: Union[Decimal, int, float] 25 | 26 | @validator("value", pre=True) 27 | def ensure_decimal(cls, v): 28 | return Decimal(v) 29 | 30 | class Config: 31 | json_encoders = {Person: lambda p: p.pk} 32 | 33 | 34 | class Movement(BaseModel): 35 | person: Person 36 | date: datetime 37 | actor: str 38 | value: Union[Decimal, int, float] 39 | 40 | @validator("value", pre=True) 41 | def ensure_decimal(cls, v): 42 | return Decimal(v) 43 | 44 | 45 | db = connect() 46 | 47 | people = [] 48 | for pk, data in db["people"].items(): 49 | people.append(Person(pk=pk, **data)) 50 | 51 | 52 | person = people[0] 53 | print(person.dict()) 54 | 55 | print(person.json()) 56 | 57 | balance = Balance(person=person, value=100) 58 | print(balance.json(models_as_dict=False)) 59 | -------------------------------------------------------------------------------- /14_modelagem/requirements.txt: -------------------------------------------------------------------------------- 1 | pydantic 2 | sqlalchemy 3 | sqlmodel 4 | -------------------------------------------------------------------------------- /14_modelagem/sqla_example.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import Column, ForeignKey, Integer, String, create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import relationship, sessionmaker 4 | 5 | # Precisamos de uma classe base do sqlalchemy para criar models 6 | # obtemos esta classe atráves de uma factory function 7 | Base = declarative_base() 8 | 9 | 10 | # Criamos nosso primeiro model 11 | class Person(Base): 12 | __tablename__ = "person" 13 | id = Column(Integer, primary_key=True, index=True, autoincrement=True) 14 | name = Column(String(255)) 15 | 16 | 17 | class Balance(Base): 18 | __tablename__ = "balance" 19 | id = Column(Integer, primary_key=True, index=True, autoincrement=True) 20 | value = Column(Integer, nullable=False) 21 | person_id = Column(Integer, ForeignKey(Person.id)) 22 | person = relationship("Person", foreign_keys="Balance.person_id") 23 | 24 | 25 | # Criamos a conexão com o banco de dados 26 | engine = create_engine("sqlite:///sqla_example.db") 27 | 28 | 29 | # Pedimos ao SQLA para criar as tabelas caso não existam 30 | Base.metadata.create_all(bind=engine) 31 | 32 | 33 | # Criamos uma Session para manipular e consultar dados 34 | SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) 35 | session = SessionLocal() 36 | 37 | 38 | # Agora podemos adicionar dados no banco de dados 39 | person = Person(name="Bruno") 40 | session.add(person) 41 | session.commit() 42 | 43 | # Inserimos um registro na tabela com relacionamento 44 | balance = Balance(value=100, person_id=person.id) 45 | session.add(balance) 46 | session.commit() 47 | 48 | # Para selecionar dados também utilizamos a session 49 | # e a função query 50 | results = session.query(Person).filter(Person.name == "Bruno") 51 | for result in results: 52 | print(result.name) 53 | 54 | # Efetuamos uma query com join 55 | results = session.query(Person.name, Balance.value).join(Balance, isouter=True) 56 | for result in results: 57 | print(result) 58 | 59 | # Usando relationships 60 | results = session.query(Balance) 61 | for result in results: 62 | print(result.person.name, result.value) 63 | -------------------------------------------------------------------------------- /14_modelagem/sqlite_example.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | con = sqlite3.connect("sqlite_example.db") 4 | con.execute("PRAGMA foreign_keys = ON;") 5 | 6 | 7 | instructions = """\ 8 | CREATE TABLE if not exists person ( 9 | id integer PRIMARY KEY AUTOINCREMENT, 10 | name varchar NOT NULL, 11 | email varchar UNIQUE NOT NULL, 12 | dept varchar NOT NULL, 13 | role varchar NOT NULL 14 | ); 15 | --- 16 | CREATE TABLE if not exists balance ( 17 | id integer PRIMARY KEY AUTOINCREMENT, 18 | person integer UNIQUE NOT NULL, 19 | value integer NOT NULL, 20 | FOREIGN KEY(person) REFERENCES person(id) 21 | ); 22 | --- 23 | CREATE TABLE if not exists movement ( 24 | id integer PRIMARY KEY AUTOINCREMENT, 25 | person integer NOT NULL, 26 | value integer NOT NULL, 27 | date datetime NOT NULL, 28 | actor varchar NOT NULL, 29 | FOREIGN KEY(person) REFERENCES person(id) 30 | ); 31 | --- 32 | CREATE TABLE if not exists user ( 33 | id integer PRIMARY KEY AUTOINCREMENT, 34 | person integer UNIQUE NOT NULL, 35 | password varchar NOT NULL, 36 | FOREIGN KEY(person) REFERENCES person(id) 37 | ); 38 | """ 39 | 40 | for instruction in instructions.split("---"): 41 | con.execute(instruction) 42 | 43 | 44 | instruction = """\ 45 | INSERT INTO person (name, email, dept, role) 46 | VALUES ('Karla', 'karla@rocha.com', 'Engineering', 'Programmer'); 47 | """ 48 | 49 | con.execute(instruction) 50 | con.commit() 51 | 52 | instruction = """\ 53 | SELECT id, name, email, dept, role 54 | FROM person ORDER BY name; 55 | """ 56 | 57 | cur = con.cursor() 58 | result = cur.execute(instruction) 59 | print(result) 60 | for row in result: 61 | print(row) 62 | 63 | instruction = """\ 64 | SELECT id, 100 65 | FROM person ORDER BY name; 66 | """ 67 | cur = con.cursor() 68 | result = cur.execute(instruction) # sqlite3.Cursor 69 | 70 | for row in result: # Cursor implementa o protocolo Iterable 71 | instruction = "INSERT INTO balance (person, value) VALUES (?, ?)" 72 | con.execute(instruction, row) 73 | con.commit() 74 | 75 | 76 | instruction = """\ 77 | SELECT person.name, person.email, balance.value 78 | from person 79 | LEFT JOIN balance 80 | WHERE person.id = balance.person 81 | """ 82 | cur = con.cursor() 83 | result = cur.execute(instruction) 84 | for row in result: 85 | print(row) 86 | -------------------------------------------------------------------------------- /14_modelagem/sqlmodel_example.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | from sqlmodel import ( 4 | Field, 5 | Relationship, 6 | Session, 7 | SQLModel, 8 | create_engine, 9 | select, 10 | ) 11 | 12 | 13 | # We have to monkey patch this attributes 14 | # https://github.com/tiangolo/sqlmodel/issues/189 15 | from sqlmodel.sql.expression import Select, SelectOfScalar 16 | SelectOfScalar.inherit_cache = True # type: ignore 17 | Select.inherit_cache = True # type: ignore 18 | 19 | 20 | class PersonDeptLink(SQLModel, table=True): 21 | dept_id: Optional[int] = Field( 22 | default=None, primary_key=True, foreign_key="dept.id" 23 | ) 24 | person_id: Optional[int] = Field( 25 | default=None, primary_key=True, foreign_key="person.id" 26 | ) 27 | 28 | 29 | class Dept(SQLModel, table=True): 30 | id: Optional[int] = Field(default=None, primary_key=True) 31 | name: str 32 | 33 | people: List["Person"] = Relationship( 34 | back_populates="depts", link_model=PersonDeptLink 35 | ) 36 | 37 | 38 | class Person(SQLModel, table=True): 39 | id: Optional[int] = Field(default=None, primary_key=True) 40 | name: str 41 | 42 | balance: "Balance" = Relationship(back_populates="person") 43 | 44 | depts: List[Dept] = Relationship( 45 | back_populates="people", link_model=PersonDeptLink 46 | ) 47 | 48 | 49 | class Balance(SQLModel, table=True): 50 | id: Optional[int] = Field(default=None, primary_key=True) 51 | value: int 52 | person_id: int = Field(foreign_key="person.id") 53 | 54 | person: Person = Relationship(back_populates="balance") 55 | 56 | 57 | engine = create_engine("sqlite:///sqlmodel_example.db", echo=False) 58 | SQLModel.metadata.create_all(bind=engine) 59 | 60 | 61 | with Session(engine) as session: 62 | person = Person(name="Bruno") 63 | session.add(person) 64 | 65 | balance = Balance(value=100, person=person) 66 | session.add(balance) 67 | 68 | session.commit() 69 | 70 | 71 | with Session(engine) as session: 72 | 73 | # select simples 74 | sql = select(Person) 75 | person = session.exec(sql).first() 76 | print(person) 77 | 78 | # com condicional 79 | sql = select(Person).where(Person.name == "Bruno") 80 | person = session.exec(sql).first() 81 | print(person) 82 | print(person.balance[0]) 83 | 84 | # utilizando referencia 85 | sql = select(Balance).where(person == person) 86 | balance = session.exec(sql).first() 87 | print(balance) 88 | print(balance.person.name) 89 | 90 | # join explicito 91 | sql = select(Person, Balance).where(Balance.person_id == Person.id) 92 | results = session.exec(sql) 93 | for person, balance in results: 94 | print(person.name, balance.value) 95 | 96 | # outer join (usando foreign keys) 97 | sql = select(Person, Balance).join(Balance, isouter=True) 98 | results = session.exec(sql) 99 | for person, balance in results: 100 | print(person.name, balance.value) 101 | 102 | 103 | with Session(engine) as session: 104 | for name in ["Sales", "Engineering", "Quality"]: 105 | session.add(Dept(name=name)) 106 | session.commit() 107 | 108 | 109 | with Session(engine) as session: 110 | sales = session.exec(select(Dept).where(Dept.name == "Sales")).first() 111 | quality = session.exec(select(Dept).where(Dept.name == "Quality")).first() 112 | 113 | person = Person( 114 | name="Jim", 115 | balance=[Balance(value=100)], 116 | depts=[sales, quality] 117 | ) 118 | session.add(person) 119 | session.commit() 120 | 121 | 122 | with Session(engine) as session: 123 | person = session.exec(select(Person).where(Person.name == "Jim")).first() 124 | print(f"Departments of {person.name}", person.depts, sep="\n") 125 | 126 | sales = session.exec(select(Dept).where(Dept.name == "Sales")).first() 127 | print(f"People on {sales.name}", sales.people, sep="\n") 128 | -------------------------------------------------------------------------------- /15_gui/kivy_example.py: -------------------------------------------------------------------------------- 1 | from kivy.app import App 2 | from kivy.uix.gridlayout import GridLayout 3 | from kivy.uix.label import Label 4 | from kivy.uix.bubble import Button 5 | from kivy.uix.textinput import TextInput 6 | 7 | 8 | class KivySum(App): 9 | def build(self): 10 | self.window = GridLayout() 11 | self.window.cols = 1 12 | self.window.size_hint = (0.6, 0.7) 13 | self.window.pos_hint = {"center_x": 0.5, "center_y": 0.5} 14 | 15 | # label 16 | self.window.add_widget( 17 | Label(text="Calculator", font_size=40, color="#ffcc00") 18 | ) 19 | 20 | # inputs 21 | self.x = TextInput( 22 | multiline=False, padding_y=(2, 2), size_hint=(1, 0.5), font_size=30 23 | ) 24 | self.window.add_widget(self.x) 25 | self.y = TextInput( 26 | multiline=False, padding_y=(2, 2), size_hint=(1, 0.5), font_size=30 27 | ) 28 | self.window.add_widget(self.y) 29 | 30 | # result label 31 | self.result = Label(text="", font_size=40, color="ffcc00") 32 | self.window.add_widget(self.result) 33 | 34 | # Buttons 35 | calcula = Button( 36 | text="Calcula", 37 | size_hint=(1, 0.5), 38 | bold=True, 39 | background_color="#00FFCE" 40 | ) 41 | calcula.bind(on_press=self.calcula) 42 | self.window.add_widget(calcula) 43 | 44 | sair = Button( 45 | text="Sair", 46 | size_hint=(0.5, 0.5) 47 | ) 48 | sair.bind(on_press=self.stop) 49 | self.window.add_widget(sair) 50 | 51 | return self.window 52 | 53 | def calcula(self, instance): 54 | self.result.text = str(int(self.x.text) + int(self.y.text)) 55 | 56 | 57 | if __name__ == "__main__": 58 | KivySum().run() 59 | -------------------------------------------------------------------------------- /15_gui/requirements.txt: -------------------------------------------------------------------------------- 1 | pysimplegui 2 | kivy 3 | -------------------------------------------------------------------------------- /15_gui/simplegui_example.py: -------------------------------------------------------------------------------- 1 | import PySimpleGUI as sg 2 | 3 | 4 | def soma(x: int, y: int) -> int: 5 | return x + y 6 | 7 | 8 | # https://pysimplegui.readthedocs.io/en/latest/#changlelookandfeel 9 | sg.theme("Reddit") 10 | 11 | layout = [ 12 | [sg.Text("X"), sg.In(size=(5, 1), enable_events=True, key="x")], 13 | [sg.Text("Y"), sg.In(size=(5, 1), enable_events=True, key="y")], 14 | [sg.Text("", key="result")], 15 | [sg.Button("Calcula")], 16 | [], 17 | [sg.Button("Sair")], 18 | ] 19 | 20 | window = sg.Window(title="Calcula", layout=layout, margins=(100, 50)) 21 | 22 | 23 | while True: 24 | event, values = window.read() 25 | if event == "Calcula": 26 | x = int(values["x"]) 27 | y = int(values["y"]) 28 | window["result"].update(soma(x, y)) 29 | elif event in (sg.WIN_CLOSED, "Sair"): 30 | break 31 | 32 | 33 | window.close() 34 | -------------------------------------------------------------------------------- /15_gui/tk_clock.py: -------------------------------------------------------------------------------- 1 | import tkinter 2 | from time import strftime 3 | 4 | relogio = tkinter.Label() 5 | 6 | relogio.pack() 7 | relogio['font'] = "Helvetica 120 bold" 8 | relogio['text'] = strftime("%H:%M:%S") 9 | 10 | 11 | def tictac(): 12 | agora = strftime("%H:%M:%S") 13 | if agora != relogio['text']: 14 | relogio['text'] = agora 15 | relogio.after(100, tictac) 16 | 17 | 18 | tictac() 19 | relogio.mainloop() 20 | -------------------------------------------------------------------------------- /15_gui/tk_example.py: -------------------------------------------------------------------------------- 1 | from tkinter import Tk, Label, Entry, Button, StringVar 2 | 3 | # Criamos a janela principal 4 | janela = Tk() 5 | 6 | # Criamos os widgets 7 | titulo = Label(janela, text="Seu Nome") 8 | nome = Entry(janela) 9 | var = StringVar() 10 | mensagem = Label(janela, textvariable=var) 11 | 12 | 13 | # Funções de callback 14 | def function(): 15 | nome_atual = nome.get() 16 | var.set(f"Olá, {nome_atual}") 17 | 18 | 19 | # Botões de ação 20 | diga_ola = Button(janela, text="Diga olá", command=function) 21 | sair = Button(janela, text="Sair", command=janela.destroy) 22 | 23 | 24 | # Posicionamos os elementos na janela 25 | titulo.grid(column=1, row=1) 26 | nome.grid(column=2, row=1) 27 | mensagem.grid(column=1, row=2) 28 | diga_ola.grid(column=2, row=3) 29 | sair.grid(column=1, row=4) 30 | 31 | 32 | # iniciamos o loop 33 | janela.mainloop() 34 | -------------------------------------------------------------------------------- /16_game/beers/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/16_game/beers/1.png -------------------------------------------------------------------------------- /16_game/beers/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/16_game/beers/2.png -------------------------------------------------------------------------------- /16_game/beers/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/16_game/beers/3.png -------------------------------------------------------------------------------- /16_game/beers/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/16_game/beers/4.png -------------------------------------------------------------------------------- /16_game/beers/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/16_game/beers/5.png -------------------------------------------------------------------------------- /16_game/game.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import pygame as pg 4 | import pygame.locals as keys 5 | 6 | # Constantes 7 | DIR = os.path.abspath(os.path.dirname(__file__)) 8 | PRETO = (0, 0, 0) 9 | BRANCO = (255, 255, 255) 10 | VERDE = (60, 220, 0) 11 | AMARELO = (255, 240, 60) 12 | CINZA = (50, 50, 50) 13 | TAMANHO_JANELA = (800, 800) 14 | 15 | # Variaveis 16 | tamanho = largura, altura = TAMANHO_JANELA 17 | largura_estrada = int(largura / 1.6) 18 | largura_separador = int(largura / 200) 19 | lado_direito = largura / 2 + largura_estrada / 4 20 | lado_esquerdo = largura / 2 - largura_estrada / 4 21 | velocidade = 1 22 | 23 | # Jogadores 24 | jogador = pg.image.load(os.path.join(DIR, "player", "player.png")) 25 | jogador = pg.transform.scale(jogador, (150, 150)) 26 | posicao_do_jogador = jogador.get_rect() 27 | posicao_do_jogador.center = lado_direito, altura * 0.8 28 | 29 | # Janela principal 30 | pg.init() 31 | tela = pg.display.set_mode(tamanho) 32 | pg.display.set_caption("Catch a beer") 33 | tela.fill(VERDE) 34 | pg.display.update() 35 | 36 | # Fontes 37 | letra = pg.font.SysFont("Comic Sans MS", 30) 38 | letra_grande = pg.font.SysFont("Comic Sans MS", 90) 39 | 40 | 41 | def carrega_cerveja_aleatoria(): 42 | i = random.randint(1, 5) 43 | cerveja = pg.image.load(os.path.join(DIR, "beers", f"{i}.png")) 44 | cerveja = pg.transform.scale(cerveja, (100, 100)) 45 | posicao_da_cerveja = cerveja.get_rect() 46 | if random.randint(0, 1) == 0: 47 | posicao_da_cerveja.center = lado_direito, altura * 0.2 48 | else: 49 | posicao_da_cerveja.center = lado_esquerdo, altura * 0.2 50 | return cerveja, posicao_da_cerveja 51 | 52 | 53 | # Valores de inicialização do jogo 54 | cerveja, posicao_da_cerveja = carrega_cerveja_aleatoria() 55 | bebeu = 0 56 | rodadas = 0 57 | executando = True 58 | pausado = True 59 | perdas = 0 60 | 61 | # Loop principal 62 | while executando: 63 | rodadas += 1 64 | 65 | # Fica mais rápido com o tempo 66 | if rodadas == 5000: 67 | velocidade += 0.15 68 | rodadas = 0 69 | print("Level UP", velocidade) 70 | 71 | # Detecção de colisão (bebeu a cerveja) 72 | if ( 73 | 10 < (posicao_do_jogador[1] - posicao_da_cerveja[1]) < 30 74 | and posicao_do_jogador[0] == posicao_da_cerveja[0] - 25 75 | ): 76 | bebeu += 1 77 | sound = random.choice(["sensacional.mp3", "olha_so.mp3"]) 78 | pg.mixer.music.load(os.path.join(DIR, "sound", sound)) 79 | pg.mixer.music.play(0) 80 | cerveja, posicao_da_cerveja = carrega_cerveja_aleatoria() 81 | 82 | # Animação da cerveja saindo do ponto inicial da reta Y (vertical) 83 | # E se movimentando a cada rodada 84 | posicao_da_cerveja[1] += velocidade 85 | 86 | # Captura Eventos do Pygame (teclas pressionadas) 87 | for event in pg.event.get(): 88 | if event.type == keys.QUIT: 89 | executando = False 90 | if event.type == keys.KEYDOWN: 91 | if event.key in (keys.K_a, keys.K_LEFT): 92 | posicao_do_jogador = posicao_do_jogador.move( 93 | (-int(largura_estrada / 2), 0) 94 | ) 95 | if event.key in (keys.K_d, keys.K_RIGHT): 96 | posicao_do_jogador = posicao_do_jogador.move( 97 | (int(largura_estrada / 2), 0) 98 | ) 99 | 100 | # Desenha a estrada no meio da tela 101 | pg.draw.rect( 102 | tela, 103 | CINZA, 104 | (largura / 2 - largura_estrada / 2, 0, largura_estrada, altura), 105 | ) 106 | 107 | # Desenha o separador da estrada 108 | pg.draw.rect( 109 | tela, 110 | AMARELO, 111 | (largura / 2 - largura_separador / 2, 0, largura_separador, altura), 112 | ) 113 | 114 | # Borda esquerda 115 | pg.draw.rect( 116 | tela, 117 | BRANCO, 118 | ( 119 | largura / 2 - largura_estrada / 2 + largura_separador * 2, 120 | 0, 121 | largura_separador, 122 | altura, 123 | ), 124 | ) 125 | # Borda direita 126 | pg.draw.rect( 127 | tela, 128 | BRANCO, 129 | ( 130 | largura / 2 + largura_estrada / 2 - largura_separador * 3, 131 | 0, 132 | largura_separador, 133 | altura, 134 | ), 135 | ) 136 | 137 | # Titulo 138 | titulo = letra.render( 139 | f"Catch a Beer! bebeu: {bebeu} vacilou: {perdas}", 1, BRANCO, PRETO 140 | ) 141 | tela.blit(titulo, (largura / 5, 0)) 142 | 143 | # Adiciona jogador e imagens na tela 144 | tela.blit(jogador, posicao_do_jogador) 145 | tela.blit(cerveja, posicao_da_cerveja) 146 | 147 | # Recarrega os gráficos na tela em suas posições alteradas no loop 148 | pg.display.update() 149 | 150 | # Espera o jogador pressionar uma tecla 151 | while pausado: 152 | msg = letra.render("Press any key to start", True, AMARELO, PRETO) 153 | tela.blit(msg, (largura / 4, 100)) 154 | pg.display.update() 155 | for event in pg.event.get(): 156 | if event.type == keys.KEYDOWN: 157 | pg.mixer.music.load(os.path.join(DIR, "sound", "vai.mp3")) 158 | pg.mixer.music.play(0) 159 | pausado = False 160 | 161 | # Verifica se o jogador deixou a cerveja cair 162 | if posicao_da_cerveja[1] > altura: 163 | perdas += 1 164 | cerveja, posicao_da_cerveja = carrega_cerveja_aleatoria() 165 | 166 | # Se cairem 3 cervejas o jogo acaba 167 | if perdas > 3: 168 | msg = letra_grande.render("GAME OVER", True, AMARELO, PRETO) 169 | pg.mixer.music.load(os.path.join(DIR, "sound", "zika.mp3")) 170 | pg.mixer.music.play(0) 171 | tela.blit(msg, (largura / 4, 100)) 172 | pg.display.update() 173 | wait_key = True 174 | while wait_key: 175 | for event in pg.event.get(): 176 | if event.type == keys.KEYDOWN: 177 | wait_key = executando = False 178 | pg.quit() 179 | 180 | pg.quit() 181 | -------------------------------------------------------------------------------- /16_game/player/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/16_game/player/player.png -------------------------------------------------------------------------------- /16_game/requirements.txt: -------------------------------------------------------------------------------- 1 | pygame 2 | -------------------------------------------------------------------------------- /16_game/sound/olha_so.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/16_game/sound/olha_so.mp3 -------------------------------------------------------------------------------- /16_game/sound/sensacional.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/16_game/sound/sensacional.mp3 -------------------------------------------------------------------------------- /16_game/sound/vai.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/16_game/sound/vai.mp3 -------------------------------------------------------------------------------- /16_game/sound/zika.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/16_game/sound/zika.mp3 -------------------------------------------------------------------------------- /17_tui/colorize.py: -------------------------------------------------------------------------------- 1 | from textual.app import App 2 | 3 | 4 | class Colorizer(App): 5 | 6 | async def on_load(self, event): 7 | await self.bind("r", "color('red')") 8 | await self.bind("g", "color('green')") 9 | await self.bind("b", "color('blue')") 10 | await self.bind("q", "quit") 11 | 12 | async def action_color(self, color: str) -> None: 13 | self.background = f"on {color}" 14 | 15 | 16 | Colorizer.run() 17 | -------------------------------------------------------------------------------- /17_tui/grid.py: -------------------------------------------------------------------------------- 1 | from textual.app import App 2 | from textual.widgets import Placeholder 3 | 4 | 5 | class SimpleApp(App): 6 | 7 | async def on_mount(self) -> None: 8 | await self.view.dock(Placeholder(), edge="left", size=40) 9 | await self.view.dock(Placeholder(), Placeholder(), edge="top") 10 | 11 | 12 | SimpleApp.run(log="textual.log") 13 | -------------------------------------------------------------------------------- /17_tui/processa_palavras.py: -------------------------------------------------------------------------------- 1 | # https://www.ime.usp.br/~pf/dicios/br-utf8.txt 2 | import unicodedata 3 | 4 | 5 | def tira_acento(s): 6 | one = unicodedata.normalize("NFD", s) 7 | two = one.encode("ascii", "ignore") 8 | three = two.decode("utf-8") 9 | return three 10 | 11 | 12 | original = open("br-utf8.txt").readlines() 13 | 14 | with open("palavras.txt", "w") as palavras: 15 | palavras.write( 16 | "\n".join( 17 | [ 18 | tira_acento(palavra.strip()) 19 | for palavra in original 20 | if len(palavra.strip()) == 5 21 | ] 22 | ) 23 | ) 24 | -------------------------------------------------------------------------------- /17_tui/pylavras.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | from rich.prompt import Prompt 4 | from rich.console import Console 5 | 6 | 7 | DIR = os.path.abspath(os.path.dirname(__file__)) 8 | emojis = {"correct_place": "🟩", "correct_letter": "🟨", "incorrect": "⬜"} 9 | 10 | 11 | def posicao_correta(letter): 12 | return f"[black on green]{letter}[/]" 13 | 14 | 15 | def letra_correta(letter): 16 | return f"[black on yellow]{letter}[/]" 17 | 18 | 19 | def incorreto(letter): 20 | return f"[black on white]{letter}[/]" 21 | 22 | 23 | def computa_tentativa(guess, answer): 24 | acertos = [] 25 | emojificado = [] 26 | for i, letter in enumerate(guess): 27 | if answer[i] == guess[i]: 28 | acertos += posicao_correta(letter) 29 | emojificado.append(emojis["correct_place"]) 30 | elif letter in answer: 31 | acertos += letra_correta(letter) 32 | emojificado.append(emojis["correct_letter"]) 33 | else: 34 | acertos += incorreto(letter) 35 | emojificado.append(emojis["incorrect"]) 36 | return "".join(acertos), "".join(emojificado) 37 | 38 | 39 | MENSAGEM = ( 40 | f"{posicao_correta('Boas vindas')} " 41 | f"{incorreto('ao')} " 42 | f"{letra_correta('Pylavras')}" 43 | ) 44 | INSTRUCAO = "Adivinhe a palavra de 5 letras.\n" 45 | 46 | 47 | def main(): 48 | palavra_correta = random.choice( 49 | open(os.path.join(DIR, "palavras.txt")).readlines() 50 | ).strip().lower() 51 | tentativas = 6 52 | rodadas = 0 53 | 54 | console = Console() 55 | console.print(MENSAGEM) 56 | console.print(INSTRUCAO) 57 | 58 | emojificados = [] 59 | acertados = [] 60 | while rodadas < tentativas: 61 | tentativa = Prompt.ask("Digite 5 letras.").strip().lower() 62 | if len(tentativa) != 5: 63 | console.print("Please type [red]5 letters[/]") 64 | continue 65 | rodadas += 1 66 | acertos, emojificado = computa_tentativa(tentativa, palavra_correta) 67 | acertados.append(acertos) 68 | emojificados.append(emojificado) 69 | console.clear() 70 | console.print(MENSAGEM) 71 | for acertos in acertados: 72 | console.print(acertos) 73 | if tentativa == palavra_correta: 74 | break 75 | print(f"\nPYLAVRAS {rodadas}/{tentativas}\n") 76 | for em in emojificados: 77 | console.print(em) 78 | 79 | 80 | if __name__ == "__main__": 81 | main() 82 | -------------------------------------------------------------------------------- /17_tui/requirements.txt: -------------------------------------------------------------------------------- 1 | textual 2 | -------------------------------------------------------------------------------- /18_web/app.py: -------------------------------------------------------------------------------- 1 | import json 2 | from flask import Flask, render_template 3 | 4 | 5 | app = Flask(__name__) 6 | 7 | 8 | @app.get("/") 9 | @app.post("/") 10 | def index(): 11 | return render_template("index.html", name="Karla") 12 | 13 | 14 | @app.route("/pessoas//") 15 | def pessoas(is_active): 16 | pessoas = get_pessoas(is_active=is_active.lower() == "active") 17 | return render_template("pessoas.html", pessoas=pessoas) 18 | 19 | 20 | def get_pessoas(is_active=None): 21 | with open("data.json") as datafile: 22 | data = json.loads(datafile.read()) 23 | 24 | if is_active is not None: 25 | return [pessoa for pessoa in data if pessoa["is_active"] == is_active] 26 | return data 27 | -------------------------------------------------------------------------------- /18_web/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 0, 4 | "name": "Lorna Montgomery", 5 | "picture": "http://placehold.it/32x32", 6 | "age": 27, 7 | "email": "lornamontgomery@lingoage.com", 8 | "about": "Fugiat in proident pariatur ut aliquip qui fugiat qui exercitation adipisicing. Est minim id reprehenderit consectetur veniam velit ipsum velit ipsum labore occaecat eiusmod. Irure ipsum adipisicing cillum laborum proident proident labore. Cillum velit officia magna veniam veniam. Quis incididunt consectetur incididunt magna est sit id. Fugiat non non minim laborum qui exercitation. Est eiusmod ea commodo incididunt nostrud.\r\n", 9 | "is_active": true 10 | }, 11 | { 12 | "id": 1, 13 | "name": "Mcclain Adkins", 14 | "picture": "http://placehold.it/32x32", 15 | "age": 34, 16 | "email": "mcclainadkins@lingoage.com", 17 | "about": "Ea tempor excepteur exercitation culpa eu in esse ullamco. Aute quis sit magna qui officia sunt veniam laborum cupidatat qui culpa aliqua deserunt tempor. Et pariatur tempor do id minim proident. Consectetur consequat occaecat culpa dolor ad anim sunt ipsum. Cupidatat anim ex tempor ex id proident nostrud ipsum laborum sit. Id pariatur elit exercitation velit quis fugiat proident magna magna ad dolor culpa dolor. Sit cillum eiusmod laborum irure consequat quis velit labore ad ex occaecat.\r\n", 18 | "is_active": true 19 | }, 20 | { 21 | "id": 2, 22 | "name": "Shanna England", 23 | "picture": "http://placehold.it/32x32", 24 | "age": 37, 25 | "email": "shannaengland@lingoage.com", 26 | "about": "Proident reprehenderit do irure excepteur esse aute anim elit et laboris incididunt laboris. Voluptate eiusmod esse do anim ea ipsum. Ullamco deserunt ad ut sint eu non labore sunt minim ut exercitation deserunt velit. Ad sunt do laborum magna nulla. Pariatur ex ea est elit dolor nisi cillum commodo consequat culpa excepteur mollit eu. Est dolor sint veniam non cupidatat.\r\n", 27 | "is_active": false 28 | }, 29 | { 30 | "id": 3, 31 | "name": "Brigitte Vincent", 32 | "picture": "http://placehold.it/32x32", 33 | "age": 35, 34 | "email": "brigittevincent@lingoage.com", 35 | "about": "Cupidatat magna dolor sunt do amet nulla Lorem pariatur non sit nostrud excepteur voluptate sunt. Do eiusmod proident pariatur exercitation commodo Lorem dolore excepteur velit ea ad irure consequat. Enim nostrud eu tempor duis est enim. Non consectetur veniam exercitation ipsum ipsum ad ut aliquip qui eu. Fugiat eu aute velit ea aute veniam aliqua dolore velit fugiat culpa. Pariatur exercitation eu consequat et. Cillum esse Lorem eiusmod eiusmod tempor aliqua dolor eu proident fugiat Lorem magna fugiat adipisicing.\r\n", 36 | "is_active": true 37 | }, 38 | { 39 | "id": 4, 40 | "name": "Larsen Gallagher", 41 | "picture": "http://placehold.it/32x32", 42 | "age": 40, 43 | "email": "larsengallagher@lingoage.com", 44 | "about": "Consectetur exercitation mollit esse fugiat aliqua mollit mollit nulla. Ullamco laborum consectetur dolor deserunt culpa incididunt enim id qui mollit aliqua ea labore fugiat. Ipsum irure ad ex nostrud minim velit elit. Aliqua commodo aute et excepteur. Occaecat sit irure excepteur non veniam nisi sit labore cupidatat veniam laboris velit. Dolor consectetur reprehenderit labore non ex fugiat irure consectetur cupidatat voluptate.\r\n", 45 | "is_active": true 46 | }, 47 | { 48 | "id": 5, 49 | "name": "Frieda Page", 50 | "picture": "http://placehold.it/32x32", 51 | "age": 22, 52 | "email": "friedapage@lingoage.com", 53 | "about": "Nisi officia esse laborum culpa exercitation laboris ipsum est nisi. Elit consectetur qui qui velit duis nulla do labore consectetur reprehenderit esse est. Proident quis nisi culpa eiusmod deserunt nostrud. Do dolor eu aliquip reprehenderit mollit tempor veniam ad non laboris.\r\n", 54 | "is_active": false 55 | }, 56 | { 57 | "id": 6, 58 | "name": "Lilian Shepherd", 59 | "picture": "http://placehold.it/32x32", 60 | "age": 27, 61 | "email": "lilianshepherd@lingoage.com", 62 | "about": "Deserunt est ullamco aliqua dolore et sunt in in. Quis voluptate quis laborum deserunt aliquip aliqua dolor velit amet laborum culpa esse duis laboris. Magna sint Lorem amet officia duis sint exercitation. Esse irure cillum et est et pariatur mollit pariatur minim aliquip quis. Tempor quis est consectetur id tempor dolore nisi incididunt nisi occaecat esse. Et Lorem fugiat aute reprehenderit consequat anim anim. Fugiat ad ex qui elit aute Lorem ipsum officia minim pariatur.\r\n", 63 | "is_active": true 64 | }, 65 | { 66 | "id": 7, 67 | "name": "Latoya Cruz", 68 | "picture": "http://placehold.it/32x32", 69 | "age": 36, 70 | "email": "latoyacruz@lingoage.com", 71 | "about": "Pariatur ea duis sunt fugiat fugiat laboris ex Lorem incididunt amet. Irure Lorem qui Lorem consequat ad aute ullamco adipisicing veniam magna. Duis quis ipsum quis nisi in dolor ex veniam eiusmod excepteur ut labore mollit.\r\n", 72 | "is_active": false 73 | }, 74 | { 75 | "id": 8, 76 | "name": "Oneil Lucas", 77 | "picture": "http://placehold.it/32x32", 78 | "age": 35, 79 | "email": "oneillucas@lingoage.com", 80 | "about": "Nisi aliquip ipsum consectetur esse excepteur enim in reprehenderit ex ex proident fugiat ullamco incididunt. Aliqua dolore incididunt dolore laborum pariatur irure ullamco. Pariatur dolore id consectetur Lorem adipisicing nulla officia.\r\n", 81 | "is_active": false 82 | }, 83 | { 84 | "id": 9, 85 | "name": "Miranda Alvarado", 86 | "picture": "http://placehold.it/32x32", 87 | "age": 37, 88 | "email": "mirandaalvarado@lingoage.com", 89 | "about": "Esse deserunt culpa culpa in occaecat dolor aute officia ea duis. Ipsum et consectetur culpa dolore ut proident mollit enim nisi. Veniam id anim nulla sit reprehenderit irure ea aute. Est tempor culpa culpa consequat tempor incididunt magna exercitation incididunt esse enim pariatur eiusmod dolore. Cillum reprehenderit velit aliquip eu Lorem. Laboris reprehenderit non minim est sint.\r\n", 90 | "is_active": false 91 | } 92 | ] -------------------------------------------------------------------------------- /18_web/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | -------------------------------------------------------------------------------- /18_web/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Demo Python Base 8 | 9 | 10 | 11 | {{name}} 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /18_web/templates/pessoas.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Demo Python Base 8 | 9 | 10 |
    11 | {%- for pessoa in pessoas -%} 12 |
  • {{pessoa.name}}
  • 13 | {%- endfor -%} 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /19_api/api.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import Optional, List, Dict, Any 3 | from fastapi import FastAPI 4 | from pydantic import BaseModel 5 | 6 | 7 | # Serializador de saida 8 | class PersonOut(BaseModel): 9 | id: int 10 | name: str 11 | picture: str 12 | age: int 13 | email: str 14 | about: Optional[str] = "" 15 | is_active: bool 16 | 17 | 18 | app = FastAPI() 19 | 20 | 21 | @app.get("/", response_model=List[PersonOut]) 22 | async def read_root(is_active: Optional[str] = None): 23 | if is_active is not None: 24 | is_active = is_active.lower() == "true" 25 | 26 | return get_pessoas(is_active=is_active) 27 | 28 | 29 | def get_pessoas(is_active=None) -> List[Dict[str, Any]]: 30 | with open("data.json") as datafile: 31 | data = json.loads(datafile.read()) 32 | 33 | if is_active is not None: 34 | return [pessoa for pessoa in data if pessoa["is_active"] == is_active] 35 | return data 36 | -------------------------------------------------------------------------------- /19_api/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 0, 4 | "name": "Lorna Montgomery", 5 | "picture": "http://placehold.it/32x32", 6 | "age": 27, 7 | "email": "lornamontgomery@lingoage.com", 8 | "about": "Fugiat in proident pariatur ut aliquip qui fugiat qui exercitation adipisicing. Est minim id reprehenderit consectetur veniam velit ipsum velit ipsum labore occaecat eiusmod. Irure ipsum adipisicing cillum laborum proident proident labore. Cillum velit officia magna veniam veniam. Quis incididunt consectetur incididunt magna est sit id. Fugiat non non minim laborum qui exercitation. Est eiusmod ea commodo incididunt nostrud.\r\n", 9 | "is_active": true 10 | }, 11 | { 12 | "id": 1, 13 | "name": "Mcclain Adkins", 14 | "picture": "http://placehold.it/32x32", 15 | "age": 34, 16 | "email": "mcclainadkins@lingoage.com", 17 | "about": "Ea tempor excepteur exercitation culpa eu in esse ullamco. Aute quis sit magna qui officia sunt veniam laborum cupidatat qui culpa aliqua deserunt tempor. Et pariatur tempor do id minim proident. Consectetur consequat occaecat culpa dolor ad anim sunt ipsum. Cupidatat anim ex tempor ex id proident nostrud ipsum laborum sit. Id pariatur elit exercitation velit quis fugiat proident magna magna ad dolor culpa dolor. Sit cillum eiusmod laborum irure consequat quis velit labore ad ex occaecat.\r\n", 18 | "is_active": true 19 | }, 20 | { 21 | "id": 2, 22 | "name": "Shanna England", 23 | "picture": "http://placehold.it/32x32", 24 | "age": 37, 25 | "email": "shannaengland@lingoage.com", 26 | "about": "Proident reprehenderit do irure excepteur esse aute anim elit et laboris incididunt laboris. Voluptate eiusmod esse do anim ea ipsum. Ullamco deserunt ad ut sint eu non labore sunt minim ut exercitation deserunt velit. Ad sunt do laborum magna nulla. Pariatur ex ea est elit dolor nisi cillum commodo consequat culpa excepteur mollit eu. Est dolor sint veniam non cupidatat.\r\n", 27 | "is_active": false 28 | }, 29 | { 30 | "id": 3, 31 | "name": "Brigitte Vincent", 32 | "picture": "http://placehold.it/32x32", 33 | "age": 35, 34 | "email": "brigittevincent@lingoage.com", 35 | "about": "Cupidatat magna dolor sunt do amet nulla Lorem pariatur non sit nostrud excepteur voluptate sunt. Do eiusmod proident pariatur exercitation commodo Lorem dolore excepteur velit ea ad irure consequat. Enim nostrud eu tempor duis est enim. Non consectetur veniam exercitation ipsum ipsum ad ut aliquip qui eu. Fugiat eu aute velit ea aute veniam aliqua dolore velit fugiat culpa. Pariatur exercitation eu consequat et. Cillum esse Lorem eiusmod eiusmod tempor aliqua dolor eu proident fugiat Lorem magna fugiat adipisicing.\r\n", 36 | "is_active": true 37 | }, 38 | { 39 | "id": 4, 40 | "name": "Larsen Gallagher", 41 | "picture": "http://placehold.it/32x32", 42 | "age": 40, 43 | "email": "larsengallagher@lingoage.com", 44 | "about": "Consectetur exercitation mollit esse fugiat aliqua mollit mollit nulla. Ullamco laborum consectetur dolor deserunt culpa incididunt enim id qui mollit aliqua ea labore fugiat. Ipsum irure ad ex nostrud minim velit elit. Aliqua commodo aute et excepteur. Occaecat sit irure excepteur non veniam nisi sit labore cupidatat veniam laboris velit. Dolor consectetur reprehenderit labore non ex fugiat irure consectetur cupidatat voluptate.\r\n", 45 | "is_active": true 46 | }, 47 | { 48 | "id": 5, 49 | "name": "Frieda Page", 50 | "picture": "http://placehold.it/32x32", 51 | "age": 22, 52 | "email": "friedapage@lingoage.com", 53 | "about": "Nisi officia esse laborum culpa exercitation laboris ipsum est nisi. Elit consectetur qui qui velit duis nulla do labore consectetur reprehenderit esse est. Proident quis nisi culpa eiusmod deserunt nostrud. Do dolor eu aliquip reprehenderit mollit tempor veniam ad non laboris.\r\n", 54 | "is_active": false 55 | }, 56 | { 57 | "id": 6, 58 | "name": "Lilian Shepherd", 59 | "picture": "http://placehold.it/32x32", 60 | "age": 27, 61 | "email": "lilianshepherd@lingoage.com", 62 | "about": "Deserunt est ullamco aliqua dolore et sunt in in. Quis voluptate quis laborum deserunt aliquip aliqua dolor velit amet laborum culpa esse duis laboris. Magna sint Lorem amet officia duis sint exercitation. Esse irure cillum et est et pariatur mollit pariatur minim aliquip quis. Tempor quis est consectetur id tempor dolore nisi incididunt nisi occaecat esse. Et Lorem fugiat aute reprehenderit consequat anim anim. Fugiat ad ex qui elit aute Lorem ipsum officia minim pariatur.\r\n", 63 | "is_active": true 64 | }, 65 | { 66 | "id": 7, 67 | "name": "Latoya Cruz", 68 | "picture": "http://placehold.it/32x32", 69 | "age": 36, 70 | "email": "latoyacruz@lingoage.com", 71 | "about": "Pariatur ea duis sunt fugiat fugiat laboris ex Lorem incididunt amet. Irure Lorem qui Lorem consequat ad aute ullamco adipisicing veniam magna. Duis quis ipsum quis nisi in dolor ex veniam eiusmod excepteur ut labore mollit.\r\n", 72 | "is_active": false 73 | }, 74 | { 75 | "id": 8, 76 | "name": "Oneil Lucas", 77 | "picture": "http://placehold.it/32x32", 78 | "age": 35, 79 | "email": "oneillucas@lingoage.com", 80 | "about": "Nisi aliquip ipsum consectetur esse excepteur enim in reprehenderit ex ex proident fugiat ullamco incididunt. Aliqua dolore incididunt dolore laborum pariatur irure ullamco. Pariatur dolore id consectetur Lorem adipisicing nulla officia.\r\n", 81 | "is_active": false 82 | }, 83 | { 84 | "id": 9, 85 | "name": "Miranda Alvarado", 86 | "picture": "http://placehold.it/32x32", 87 | "age": 37, 88 | "email": "mirandaalvarado@lingoage.com", 89 | "about": "Esse deserunt culpa culpa in occaecat dolor aute officia ea duis. Ipsum et consectetur culpa dolore ut proident mollit enim nisi. Veniam id anim nulla sit reprehenderit irure ea aute. Est tempor culpa culpa consequat tempor incididunt magna exercitation incididunt esse enim pariatur eiusmod dolore. Cillum reprehenderit velit aliquip eu Lorem. Laboris reprehenderit non minim est sint.\r\n", 90 | "is_active": false 91 | } 92 | ] -------------------------------------------------------------------------------- /19_api/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi 2 | uvicorn 3 | -------------------------------------------------------------------------------- /docs/d1/d1p01_intro.md: -------------------------------------------------------------------------------- 1 | # Python Base 2 | 3 | Meu nome é Bruno Rocha, trabalho como Engenheiro de Software na Red Hat. Tenho quase 20 anos de experiência com Python (comecei em 2003), hoje sou Senior Software Engineer na plataforma Ansible, uma das principais 4 | ferramentas de automação escrita em Python. 5 | 6 | Estou aqui na LINUXtips oferecendo a você o meu conhecimento acumulado 7 | nesses anos de carreira em forma de um pacote de treinamentos: Python Expert. 8 | 9 | Este aqui é o primeiro módulo e o chamamos de Python Base, pois é a fundação, 10 | os conceitos básicos para qualquer pessoa iniciar com programação e Python. 11 | 12 | Outros treinamentos da carreira Python Expert: 13 | 14 | 1. [Python Base](https://www.linuxtips.io/course/python-base) - Conceitos fundamentais para iniciar com Python. 15 | 2. [Python Web](https://www.linuxtips.io/course/python-para-web-e-api) - Python focado no desenvolvimento de backend para Web e APIs usando os 16 | principais frameworks do mercado, como Django, Flask e FastAPI. 17 | 3. Automação - Python com foco em automação de operações em ambientes 18 | DevOps, Cloud, Testes, Qualidade de Software, etc. 19 | 4. Engineer - Para quem quer ir além do básico, neste módulo vamos 20 | explorar conceitos avançados de Python. 21 | -------------------------------------------------------------------------------- /docs/d1/d1p02_programacao_linguagens.md: -------------------------------------------------------------------------------- 1 | # Programação e Linguagens 2 | 3 | ## O computador e as linguagens 4 | 5 | O computador, ou qualquer unidade computacional (um celular, um chip, etc.) é um 6 | dispositivo eletrônico digital que por sua natureza só entende informações em 7 | formato binário, o formato binário é um esquema lógico onde as informações são 8 | formadas por sequências de `0` e `1` encadeadas, cada um desses dígitos é 9 | chamado de bit e a sequência de 8 deles é chamada de Byte ex: `10010100`, portanto 10 | para enviar qualquer tipo de instrução ao computador precisamos colocar os bits 11 | na ordem desejada e essa é uma tarefa humanamente bem difícil. 12 | 13 | Por exemplo, toda vez que você pressiona a tecla `A` em seu teclado os componentes 14 | do teclado precisam enviar a mensagem `10000001` para o computador que internamente 15 | passa essa mensagem ao sistema operacional (Windows, Linux, MacOS, Android, etc.) 16 | e converte essa sequência em um número decimal, neste caso é o `65` e a partir 17 | deste número o sistema operacional consegue ir até uma tabela de caracteres e 18 | consultar a letra que está presente na posição `65` que neste caso é o `A` e 19 | só então o `A` pode ser usado, por exemplo, para ser mostrado em sua tela. 20 | 21 | Por isso que existem as linguagens de abstração para programação. Todas as 22 | linguagens de programação têm por objetivo abstrair a necessidade de fazer esses 23 | cálculos binários e trazer as instruções para uma camada mais próxima do ser 24 | humano e mais longe da máquina. 25 | 26 | Sendo assim, classificamos as linguagens de programação entre as de "Baixo Nível" 27 | que são aquelas que diretamente convertem suas instruções para o código binário e 28 | muitas vezes têm uma sintaxe de escrita mais difícil e menos natural. 29 | 30 | E as de "Alto Nível" que oferecem formas mais simples, em linguagem natural, com 31 | palavras normais da língua inglesa, porém entre o programa e o código binário 32 | final existe uma série de camadas de abstração. 33 | 34 | Python é uma linguagem de "Alto Nível" e vamos focar neste treinamento em suas 35 | facilidades e abstrações. 36 | 37 | ## Programa 38 | 39 | Um programa é um conjunto de instruções colocados de forma organizada em um ou 40 | mais arquivos que podem ser executados várias, vezes obtendo os mesmos 41 | resultados. 42 | 43 | Existem 2 categorias de programas, os programas interpretados e os compilados. 44 | 45 | Os compilados exigem que todas as linhas de código sejam avaliadas e validadas 46 | antes de o programa executável ser gerado já na linguagem de máquina (0,1...) e 47 | no momento da execução o programa está todo pronto para rodar. 48 | 49 | Os programas interpretados são aqueles que podem ser escritos em arquivos, mas 50 | são avaliados linha a linha, bloco a bloco, sem a necessidade de o programa 51 | inteiro estar avaliado, cada instrução é lida e logo em seguida interpretada e 52 | executada, este tipo de programação é mais fácil e mais dinâmica, mas pode ser 53 | também mais suscetível a erros. 54 | 55 | Python é uma linguagem dinâmica e interpretada e isso permite que a gente 56 | envie comandos individuais, linha a linha, para o interpretador e isso torna 57 | a experiência de aprendizado bastante agradável. 58 | -------------------------------------------------------------------------------- /docs/d1/d1p03_plataforma_python.md: -------------------------------------------------------------------------------- 1 | # Python 2 | 3 | Ao pensar na palavra Python, a primeira coisa que nos vem a mente é a linguagem 4 | de programação, certo? (O grupo de humor britânico também). 5 | 6 | Mas Python é muito mais do que somente a linguagem, Python é uma plataforma 7 | formada por uma série de componentes. 8 | 9 | ## PLR 10 | 11 | O primeiro e mais importante componente é a PLR (Python Language Reference) que 12 | é o documento contendo toda a especificação da linguagem, aqui estão as regras 13 | gramaticais da linguagem, aqui estão as palavras reservadas e todos os comportamentos 14 | esperados de uma implementação de Python, PLR é um extenso conjunto de textos 15 | escrito pelo criador do Python. 16 | 17 | ## Implementação 18 | 19 | A partir da PLR, essa especificação é programada para interpretar e 20 | executar programas Python. A implementação oficial é escrita na linguagem C 21 | e é essa que iremos utilizar, porém, existem outras implementações como IronPython para 22 | rodar dentro da plataforma .Net, o Jython que roda na máquina virtual Java, 23 | o PyPy que é um Python reescrito em Python para ser mais rápido, temos o 24 | MicroPython que é mais leve para ser usado em chips embarcados e várias outras 25 | implementações experimentais. 26 | 27 | ## Ecossistema 28 | 29 | o Ecossistema é formado por tudo que está em torno da implementação do Python, 30 | aqui temos bibliotecas, ferramentas, empresas, mas acima de tudo pessoas que formam 31 | a comunidade. 32 | 33 | ### Comunidades 34 | 35 | Em diversas localidades presenciais e virtuais existem pessoas que se juntam 36 | para compartilhar conhecimento de Python e essas comunidades 37 | muitas vezes estão organizadas em fundações, grupos de nicho e empresas que 38 | têm interesses em comum relacionados a Python. 39 | 40 | ## PSF 41 | 42 | A Python Software Foundation é a fundação internacional criada para proteger 43 | e gerir os recursos e direitos do Python, a linguagem é open-source e livre 44 | não existe uma empresa dona do Python, porém existe uma fundação oficial 45 | que faz a gestão de coisas como copyright da marca Python, avaliação de propostas 46 | de melhoria para a linguagem e apoio a comunidades locais. 47 | 48 | ## PyPI 49 | 50 | O Python Package Index é um repositório com mais de 300 mil pacotes e ferramentas 51 | para você reutilizar em seus projetos Python, esta infraestrutura é mantida por 52 | um sub grupo da PSF chamado Python Package Authority e é através do PyPI usando 53 | a ferramenta `pip` que instalamos bibliotecas e ferramentas. 54 | 55 | 56 | ## Você! 57 | 58 | E você que está iniciando agora com Python já pode se considerar parte deste 59 | ecossistema, boas-vindas à comunidade Python! :) 60 | 61 | Pessoas > Tecnologia :) 62 | -------------------------------------------------------------------------------- /docs/d1/d1p04_instalacao_ambiente_terminais_editor.md: -------------------------------------------------------------------------------- 1 | # Instalação 2 | 3 | 4 | ## Python 5 | 6 | O caminho recomendado para instalação do Python é através do site oficial 7 | (https://www.python.org/downloads/), nesta página você pode obter o seu 8 | instalador conforme o seu sistema operacional. 9 | 10 | Para este treinamento, usaremos o Python 3.6+, ou seja, qualquer versão acima 11 | do 3.6 irá funcionar. 12 | 13 | Se estiver em um sistema Linux, provavelmente o Python já se encontra instalado 14 | ou pode obtê-lo através do gerenciador de pacotes do seu sistema. 15 | 16 | Caso não possa instalar por algum motivo, temos ainda a alternativa de 17 | usar o Python online através das ferramenta (https://replit.com) ou 18 | (https://gitpod.io) para essas 2 ferramentas é necessário ter um cadastro 19 | no GitHub. 20 | 21 | ## Terminal 22 | 23 | Você pode usar o terminal de sua preferência desde que seja compatível com 24 | Linux. No Windows, por exemplo, pode-se usar o WSL(Windows Subsystem for Linux) 25 | que abre um terminal Linux dentro do Windows. 26 | 27 | *Curiosidade: no meu ambiente, utilizo Arch Linux, i3wm, Terminator, 28 | ZSH e starship.rs* 29 | 30 | ## Editor 31 | 32 | A escolha de editor é pessoal, escolha o que gostar mais e que te dê maior 33 | conforto e produtividade, eu vou recomendar que você evite neste primeiro 34 | momento o uso de IDE (Ambiente Integrado) as IDEs são ótimas, mas abstraem 35 | muitas coisas e, por exemplo, ao invés de ir ao terminal dar os comandos para 36 | rodar o programa, na IDE você cai na tentação de apertar um botão "run" que 37 | você acaba nem sabendo o que ele faz exatamente. 38 | 39 | Minha recomendação para nosso fluxo de trabalho é que você mantenha sempre 40 | 2 terminais abertos no seu sistema lado a lado, um para escrevermos o código e 41 | outro para executarmos. 42 | 43 | No caso de editor de termina, eu recomendo usar o micro-editor, pois ele é leve 44 | e tem funcionamento bem simples, mas você pode também preferir usar outros como 45 | Nano, Vim, Neovim, Emacs, mas eu só os recomendo caso você já tenha algum 46 | conhecimento no funcionamento deles. 47 | 48 | Fique à vontade para usar editores gráficos como Visual Studio Code ou Sublime 49 | Text. 50 | 51 | *Curiosidade: eu utilizo 3 editores e estou sempre alternando entre eles 52 | Micro-editor, Vim e VSCode, dependendo da tarefa eu acabo escolhendo um deles.* 53 | 54 | 55 | ## Python 56 | 57 | Agora, em seu terminal, já pode começar a interagir com o Python diretamente 58 | através do comando `python`. 59 | 60 | Para verificar a versão que está instalada use o comando: 61 | 62 | ```bash 63 | python --version 64 | ``` 65 | 66 | É muito importante que a versão seja pelo menos 3.6 (ou maior). 67 | 68 | Para enviar uma instrução (ou comando) para o Python, use o `-c`: 69 | 70 | ```bash 71 | python -c "1 + 1" 72 | ``` 73 | 74 | No comando acima, o Python recebe a expressão `1 + 1` interpreta, executa a 75 | operação matemática de adição, porém não exibe nenhum output. Para ter 76 | a resposta na tela, precisamos usar a função `print`: 77 | 78 | 79 | ```bash 80 | python -c "print(1 + 1)" 81 | ``` 82 | 83 | Ela retornará uma saída assim: 84 | 85 | ```bash 86 | 2 87 | ``` 88 | 89 | Outra maneira de se comunicar com o Python é através da execução de módulos 90 | com o `-m`. 91 | 92 | Para obter informações sobre os caminhos de instalação do Python: 93 | 94 | ```bash 95 | python -m site 96 | ``` 97 | 98 | `-m nome_do_modulo` executa um módulo que esteja instalado e habilitado para 99 | execução direta, alguns exemplos `json, http.server, pip, site`. 100 | 101 | E finalmente, para abrir o terminal interativo, use apenas `python`: 102 | 103 | ```bash 104 | python 105 | ``` 106 | Ele retornará uma saída assim: 107 | 108 | ```bash 109 | >>> 110 | ``` 111 | 112 | O sinal `>>>` é o prompt do Python e significa que ele está a espera de um 113 | comando. Ali você pode digitar `1 + 1` ou qualquer operação matemática, ou fazer 114 | chamadas de funções como `print("bruno".upper())`. 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /docs/d1/d1p07_tipos_de_instrucoes.md: -------------------------------------------------------------------------------- 1 | # Tipos de instruções 2 | 3 | O interpretador Python entende insruções que estão divididas em 3 categorias: 4 | expressões(expressions), declarações(statements) e atribuições(assignment). 5 | 6 | ## Expressões (expressions) 7 | 8 | Toda instrução que gera um processamento e espera um valor de retorno, 9 | exprimimos qual operação desejamos que seja computada usando funções ou 10 | operadores matemáticos e sempre esperamos obter um resultado para armazenar 11 | em variáveis ou efetuar operações de comparação. 12 | 13 | Exemplo: 14 | 15 | ```py 16 | # Expressão literal, retorno o próprio número 17 | >>> 1 18 | 1 19 | 20 | # Expressão, retorna o próprio texto 21 | >>> "Bruno" 22 | 'Bruno' 23 | 24 | # Expressão de chamada de método ou função 25 | >>> "Bruno".upper() 26 | BRUNO 27 | 28 | # Expressão com operador, retorna um resultado boleano 29 | >>> 1 > 2 30 | False 31 | 32 | >>> 89 >= 89 33 | True 34 | 35 | >>> "Bruno" != "Joao" 36 | True 37 | 38 | # Chamada de função 39 | >>> sum([1, 2, 3]) 40 | 6 41 | ``` 42 | 43 | 44 | ## Declarações (statements) 45 | 46 | São formadas por uma ou mais palavras-chave e servem para preparar o interpretador 47 | para efetuar alguma operação, são comandos que alteram estado ou declaram fluxo lógico. 48 | 49 | Algumas palavras chave que são statementes `if, else, elif, for, while, pass, def` 50 | 51 | Exemplos: 52 | 53 | ```py 54 | # Condicional com comparação de 55 | if 1 > 2: 56 | print("Eita, um é maior que 2?") 57 | 58 | # Comparação com comparação de igualdade 59 | if x == y: 60 | # faça isso 61 | else: 62 | # façá aquilo 63 | 64 | # Repetição com comparação de valor 65 | while numero < 10: 66 | numero += 1 67 | print(numero) 68 | 69 | # Instrução nula 70 | if nao_faca_nada: 71 | pass 72 | ``` 73 | 74 | Nos exemplos: `if 1 > 2:` temos um statement `if` seguido de uma expressão `1 > 2` 75 | 76 | ## Atribuição (assignment) 77 | 78 | É o nome dado a expressão que pega o resultado de uma expressão e salva em uma 79 | variável atribuindo um `nome/identificador` ao resultado que pode ser usado como 80 | referência para acesso. 81 | 82 | ```py 83 | preco = 10 84 | quantidade = 5 85 | total = preco * quantidade 86 | print(f"O total da sua compra é {total}") 87 | ``` 88 | 89 | A atribução é sempre feita com o sinal de `=` e do lado esquerdo definimos um 90 | identificador e do lado direito a expressão a ser atribuida. 91 | 92 | No exemplo `total = preco * quantidade` primeiro o Python resolve a expressão 93 | `10 * 5` resultando em `50` e então a a partir do sinal de `=` armazena `50` 94 | como valor da variável `total`. 95 | -------------------------------------------------------------------------------- /docs/d1/d1p08_blocos_de_codigo.md: -------------------------------------------------------------------------------- 1 | # Blocos de Código 2 | 3 | Para entender o funcionamento de blocos de código em Python vamos analisar 4 | as motivações do criador da linguagem. 5 | 6 | Antes de criar o Python, Guido Van Rossum trabalhou no desenvolvimento de 7 | outra linguagem chamada ABC e o objetivo dessa linguagem era ser uma 8 | linguagem de fácil leitura por pessoas de outras áreas acadêmicas. 9 | 10 | Ele partiu do princípio de que passamos muito mais horas lendo código 11 | do que escrevendo e concluiu que a maneira tradicional que as linguagens 12 | adotavam para delimitar código não seria tão natural para quem não está 13 | acostumado. 14 | 15 | Uma grande parte das linguagens utiliza chaves `{ }` para delimitar os blocos 16 | de código, ficando mais ou menos assim: 17 | 18 | ```c 19 | statement (condicao) { 20 | primeira linha do bloco; 21 | segunda linha do bloco; 22 | terceira linha (condicao) { 23 | primeira linha do sub bloco; 24 | } 25 | } 26 | ``` 27 | 28 | E para o Guido essa forma de organizar código não seria muito fácil de entender 29 | e manter e principalmente não seria tão agradável de ler em códigos grandes. 30 | 31 | ## Lista de compras 32 | 33 | Ao fazer comprar no supermercado geralmente criarmos uma lista de compras 34 | 35 | ```text 36 | Feijao 37 | Sabão 38 | Arroz 39 | Batata 40 | Laranja 41 | Shampoo 42 | Alface 43 | Café 44 | ``` 45 | 46 | Para tornar esta lista mais fácil podemos organizar utilizando as seções do 47 | mercado como separador. 48 | 49 | 50 | ```text 51 | Mercearia: 52 | Feijao 53 | Arroz 54 | Café 55 | Limpeza: 56 | Sabão 57 | Shampoo 58 | Feira: 59 | Batata 60 | Laranja 61 | Alface 62 | ``` 63 | 64 | A lista acima está muito mais organizado do que a primeira versão e permite 65 | que nossa experiência ao fazer compra seja mais produtiva, pois agora podemos 66 | percorrer os corredores um a um sem a necessidade de passar duas vezes no mesmo 67 | corredor. 68 | 69 | ## Edentação 70 | 71 | Indentation, Edentação ou Denticulação é o termo usado para a formatação da 72 | lista de compras acima, após cada categoria ou seção colocamos um **recuo** 73 | antes de começar o conteúdo. 74 | 75 | E pensando neste exemplo natural, o Python foi projetado, de forma que 76 | passamos muito mais tempo lendo código do que escrevendo. 77 | 78 | ## Blocos 79 | 80 | Em Python um bloco de código inicia sempre que existe a presença de `:` no final 81 | de uma linha. 82 | 83 | ```py 84 | if 1 > 2: # inicio de bloco 85 | ``` 86 | 87 | A linha que vem logo após o início do bloco deve obrigatoriamente ter um recuo (ou dente) 88 | e por isso chamamos de edentação. 89 | 90 | ```py 91 | if 1 > 2: 92 | # aqui começa o código do bloco 93 | # o bloco pode ter muitas linhas 94 | # desde que mantenha o mesmo recuo 95 | # o recuo padrão é de 4 espaços. 96 | ``` 97 | 98 | Dentro de um bloco de código podem existir muitos sub blocos, níveis internos 99 | de recuo, mas a recomendação é que no máximo existam 4 espaços. 100 | 101 | ```py 102 | if 1 > 2: 103 | # aqui inicia o bloco 104 | # recuo de 4 espaços 105 | 106 | while x < 10: 107 | # aqui inicia outro sub bloco 108 | # recuo de 8 espaços 109 | 110 | if x == 3: 111 | # ainda mais um bloco 112 | # recuo de 12 espaços 113 | 114 | # voltamos ao bloco anterior 115 | 116 | # agora voltamos para o bloco inicial 117 | 118 | # e aqui continuamos o bloco principal (main) 119 | ``` 120 | 121 | A maioria dos editores de código possui ferramentas 122 | que ajudam a visualizar as linhas de edentação. 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /docs/d2/d2p02_float_bool_none.md: -------------------------------------------------------------------------------- 1 | ### Float 2 | 3 | Floats são parecidos com inteiros mas além de armazenar a parte inteira do 4 | número eles também podem armazenar o ponto flutuante, a fração, e são usados 5 | para armazenar resultados que não podem ser armazenados em inteiros, por exemplo. 6 | 7 | ```py 8 | >>> valor = 5 / 2 # cindo dividido por 2 9 | >>> print(valor) 10 | 2.5 11 | ``` 12 | 13 | A presença de um `.` em um número faz com que o Python entenda que queremos 14 | armazena-lo em um objeto da classe `float` e assim como os inteiros ela 15 | possui todos os métodos especiais dunder para os protocolos que implementa 16 | e também métodos que são particulares apenas dos números floats. 17 | 18 | Exemplos de uso de um float 19 | 20 | ```py 21 | # Resultados de divisão 22 | valor = 5 / 2 23 | 24 | # Coordenadas geográficas 25 | latitude = -37.80467681 26 | longitude = 144.9659498 27 | 28 | # Saldo de pontuação (em jogos por exempo) 29 | pontos = 355.8 30 | ``` 31 | 32 | > **NOTA** Para trabalhar com dados monetários (dinheiro) damos preferência a 33 | > um tipo especializado chamado `Decimal` ao invés de `float` mas não se preocupe 34 | > que abordaremos isso em breve. 35 | 36 | ### Boleanos 37 | 38 | O tipo boleano é representado pela classe `bool` e ele pode armazenar apenas 39 | 2 estados `Verdadeiro` e `Falso`, em teoria poderíamos aplicar aqui a lógica 40 | binária e em nosso programa dizer que `0` é falso enquanto `1` é verdadeiro, e 41 | de fato é isso que Python faz por debaixo dos panos, porém para ficar com uma 42 | sintaxe mais bonita termos o tipo `bool` e suas variações `True` e `False`. 43 | 44 | Quando utilizamos esse tipo? sempre que precisamos de **flags**, variáveis 45 | que podem estar em um desses dois estados, veja alguns exemplos: 46 | 47 | ```py 48 | # Tornar um usuário administrador 49 | is_admin = True 50 | 51 | # Verificar se o usuário quer continuar uma operação 52 | continuar = False 53 | 54 | # Definir se um produto está ativo em uma loja 55 | active = True 56 | ``` 57 | 58 | Apesar de ser bastante simples, o tipo `bool` é muito útil e ele por sí só 59 | forma um protocolo chamado `Boolean`, com objetos boleanos podemos criar 60 | expressões condicionais, como as que criamos em nosso script `hello.py` 61 | 62 | ```py 63 | if current_language == "pt_BR": 64 | msg = "Hello, World!" 65 | ``` 66 | 67 | A parte `current_language == "pt_BR"` retorna um valor do tipo `bool` e sempre 68 | que usamos o statement `if` a expressão em seguida precisa obrigatoriamente 69 | retornar um objeto que tenha o protocolo `Boolean` assim como esse. 70 | 71 | Veja em seu terminal: 72 | 73 | ```py 74 | # inicialize a variável 75 | >>> current_language = "en_US" 76 | 77 | # obtenha um bool através de comparação por igualdade 78 | >>> current_language == "pt_BR" 79 | False 80 | 81 | # verifique o tipo diretamente 82 | >>> type(current_language == "pt_BR") 83 | bool 84 | 85 | # Isso também funciona com números int 86 | >>> type(1 == 1) 87 | True 88 | ``` 89 | 90 | Se você rodar o comando `dir(int)` verá que na lista de métodos especiais tem 91 | um chamado `__bool__` e é ele que é chamado quando fazemos operações `if` usando 92 | os inteiros. 93 | 94 | ```py 95 | if 500: 96 | print("Ok, 500 é um int que implementa __bool__") 97 | ``` 98 | 99 | Muitos objetos no Python implementam `__bool__` e podem ser usados diretamente 100 | após o `if` mesmo que não exista uma expressão de comparação. 101 | 102 | ### NoneType 103 | 104 | Em alguns casos precisamos inicializar uma variável porém ainda não temos 105 | o valor para armazenar nela, nesse caso usamos o objeto `None` 106 | 107 | ```py 108 | >>> type(None) 109 | NoneType 110 | ``` 111 | 112 | Este é um tipo especial que serve para quando não possuímos um valor mas precisamos 113 | da variável definida pois em algum momento no decorrer do programa iremos refazer 114 | a atribuição daquela variável. 115 | 116 | ```py 117 | produto = None 118 | 119 | if produto is None: 120 | produto = funcao_para_definicao_do_produto() 121 | 122 | ``` 123 | 124 | O objeto `None` é um singleton, só existe um `None` mesmo que você defina 125 | várias variáveis como `None` todas elas farão referência ao mesmo `None` 126 | 127 | ```py 128 | >>> a = None 129 | >>> b = None 130 | 131 | >>> id(a) 132 | 139862040616512 133 | 134 | >>> id(b) 135 | 139862040616512 136 | 137 | >>> a is b 138 | True 139 | 140 | a == b 141 | True 142 | ``` 143 | 144 | ## Exercicio 145 | 146 | 147 | Vamos criar um programa que imprime as tabuadas de 1 até 10 148 | -------------------------------------------------------------------------------- /docs/d2/d2p04_formatacao_de_textos.md: -------------------------------------------------------------------------------- 1 | ### Interpolação e Formatação de textos 2 | 3 | Uma das coisas mais úteis de se fazer com texto é a interpolação de variáveis 4 | dentro do texto e a formatação de acordo com template pre-definido. 5 | 6 | **Interpolação** é uma alternativa a **concatenação**, enquanto a concatenação 7 | usa o sinal de `+` como em `"Bruno" + "Rocha"` na interpolação usamos templates 8 | com posicionamento. 9 | 10 | Python oferece 3 maneiras de fazer **Interpolação**, a primeira e mais antiga 11 | delas segue um padrão universal adotado em muitos sistemas e em outras linguagens 12 | de programação e utiliza o sinal de `%` como marcador de template. 13 | 14 | ##### % 15 | 16 | ```py 17 | >>> mensagem = "Olá %s, você é o participante número %d e pode ganhar %f pontos." 18 | >>> nome = "Bruno" 19 | >>> numero = 4 20 | >>> pontos = 42.5 21 | >>> print(mensagem % (nome, numero, pontos)) 22 | Olá Bruno, você é o participante número 4 e pode ganhar 42.500000 pontos. 23 | ``` 24 | 25 | Este tipo de formatação usa o `%` acompanhado de `s` para str, `d` para int, ou 26 | `f` para float, e além de demarcar o **placeholder** onde a substituição irá 27 | ocorrer também podemos definir a precisão numérica como em `%.2f` que significa 28 | que queremos imprimir apenas 2 casas decimais do número float. 29 | 30 | ```py 31 | >>> mensagem = "Olá %s, você é o participante número %d e pode ganhar %.2f pontos." 32 | >>> print(mensagem % (nome, numero, pontos)) 33 | Olá Bruno, você é o participante número 4 e pode ganhar 42.50 pontos. 34 | ``` 35 | 36 | E também é possível utilizar parâmetros nomeados. 37 | 38 | ```py 39 | >>> mensagem = "Olá %(nome)s, você é o participante número %(num)d e pode ganhar %(pon).2f pontos." 40 | >>> print(mensagem % {"nome": "Bruno", "num": 4, "pon": 42.5}) 41 | Olá Bruno, você é o participante número 4 e pode ganhar 42.50 pontos. 42 | ``` 43 | 44 | 45 | Apesar do uso de `%` ter caído em desuso no Python 3, ainda existem bibliotecas 46 | como a `logging` que ainda utiliza este formato. 47 | 48 | ##### format 49 | 50 | Esta é a forma preferida para fazer interpolação de textos pois além 51 | de permitir a substituição de variáveis também permite a formatação 52 | dos valores, vejamos alguns exemplos: 53 | 54 | ```py 55 | >>> mensagem = "Olá {}, você é o participante número {} e pode ganhar {} pontos." 56 | >>> print(mensagem.format(nome, numero, pontos)) 57 | Olá Bruno, você é o participante número 4 e pode ganhar 42.5 pontos. 58 | ``` 59 | 60 | Repare que ao invés de `%` agora usamos `{}` para marcar um **placeholder** 61 | e ao invés de `%` usamos a chamada do método `.format` do próprio tipo `str` 62 | para passar os valores em sequência. 63 | 64 | E também podemos especificar tipos e a precisão numérica usando `:` e os mesmos 65 | marcadores dentro de `{}`. 66 | 67 | ```py 68 | >>> mensagem = "Olá {:s}, você é o participante número {:d} e pode ganhar {:.2f} pontos." 69 | >>> print(mensagem.format(nome, numero, pontos)) 70 | Olá Bruno, você é o participante número 4 e pode ganhar 42.50 pontos. 71 | ``` 72 | 73 | Podemos utilizar outras opções de formatação em cada uma das marcações entre `{}`. 74 | existe toda uma mini linguagem de formatação: 75 | 76 | ```py 77 | {[[fill]align][sign][#][0][width][grouping_option][.precision][type]} 78 | ``` 79 | 80 | ``` 81 | fill - 82 | align - "­<" | "­>" | "­=" | "­^" 83 | sign - "­+" | "­-" | " " 84 | width - digit+ 85 | grouping_option - "­_" | "­," 86 | precision - digit+ 87 | type - "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" 88 | ``` 89 | 90 | Exemplos: 91 | 92 | ```py 93 | # Centralizar fazendo ocupar exatamente 11 caracteres. 94 | >>> "{:^11}".format("Bruno") 95 | ' Bruno ' 96 | 97 | # A mesma coisa porém alinhado à direita. 98 | >>> "{:>11}".format("Bruno") 99 | ' Bruno' 100 | 101 | # Agora preenchendo os espaços com outro carectere 102 | >>> "{:*^11}".format("Bruno") 103 | '***Bruno***' 104 | 105 | # Definindo tipo e precisão para números 106 | >>> "{:*^11.2f}".format(45.30000041) 107 | '***45.30***' 108 | 109 | ``` 110 | 111 | O site Pyformat https://pyformat.info/ oferece um guia bastante intuitivo 112 | para utilizar as opções de formatação, elas são tantas que não daria para 113 | abordarmos todas elas neste treinamento, mas não se preocupe que durante os 114 | nossos exercícios vamos utilizar as mais comuns. 115 | 116 | Uma outra forma mais rápida de obter essa ajuda é abrindo o Python e digitando 117 | 118 | ```py 119 | help('FORMATTING') 120 | ``` 121 | 122 | ##### f strings 123 | 124 | No Python 3 foi introduzido um atalho bastante útil para usar o `format` e de 125 | uma forma mais natural agora podemos escrever strings que se auto formatam 126 | usando as variáveis existentes, o funcionamento respeita as mesmas opções 127 | vistas anteriormente, o que muda é só a forma de escrever, ao invés de chamar 128 | explicitamente `.format()` usamos `f"texto"`. 129 | 130 | ```py 131 | # Texto 132 | >>> nome = "Bruno" 133 | >>> f"{nome:*^11}" 134 | '***Bruno*** 135 | 136 | # Número 137 | >>> valor = 45.30000041 138 | >>> f"{valor:*^11.2f}" 139 | '***45.30***' 140 | ``` 141 | 142 | Uma utilidade interessante das f-strings é usar para fazer debugging. 143 | 144 | ```py 145 | >>> nome = "Bruno" 146 | >>> print(f"{nome=}") 147 | nome='Bruno' 148 | ``` 149 | 150 | Durante o treinamento usaremos: 151 | 152 | - `%s` para logs 153 | - `.format` para templates salvos, por exemplo para enviar e-mails 154 | - `f-string` para todas as outras mensagens do programa 155 | 156 | ### Emojis 157 | 158 | print("\U0001F600") 159 | print("\U0001F43C") 160 | print("\N{watermelon}") 161 | -------------------------------------------------------------------------------- /docs/d2/d2p05_tipos_compostos-tuplas.md: -------------------------------------------------------------------------------- 1 | # Tipos compostos 2 | 3 | Com os tipos `primários` temos a limitação de representar apenas uma única 4 | informação em cada objeto, porém existem casos em que desejamos compor um 5 | objeto único que contém mais de uma informação e para isso usamos os tipos 6 | compostos. 7 | 8 | ## Tuplas 9 | 10 | As tuplas são o tipo composto mais simples de todos e bastante comum de serem 11 | usadas em Python, da mesma forma que anteriormente vimos que a string "ABC" é 12 | uma sequência de caracteres, com as tuplas conseguimos fazer uma sequência de 13 | valores que podem ser de qualquer tipo. 14 | 15 | Exemplo de um sistema que armazena coordenadas sem o uso de tuplas: 16 | 17 | ```py 18 | coord_x = 140 19 | coord_y = 200 20 | coord_z = 9 21 | ``` 22 | 23 | Coordenadas desta forma são muito úteis em softwares de desenho gráfico ou 24 | mapas, ali temos a reta `x` e a reta `y` de um plano cartesiano, e ainda estamos 25 | adicionando a coordenada `z` que é a profundidade, usada em sistemas 3d. 26 | 27 | ![](./imgs/cartesiano.png) 28 | 29 | Cada uma das coordenadas se refere a um ponto nessa reta e para definir um 30 | **único** ponto nós usamos 3 variáveis e isso fica muito difícil de manter 31 | caso nosso sistema tenha muitas dessas coordenadas, e ai que entram as tuplas. 32 | 33 | ```py 34 | coord = 140, 200, 9 35 | 36 | # ou 37 | 38 | coord = (140, 200, 9) 39 | ``` 40 | 41 | Em Python sempre que um ou mais objetos forem encadeados com `,` isso será 42 | interpretado como um objeto do tipo `tupla` e a tupla pode opcionalmente ter 43 | parênteses, nos já usamos tupla lembra? quando falamos de interpolação de textos. 44 | 45 | ```py 46 | "Olá %s você é o %03d da fila" % (nome, senha) 47 | ``` 48 | 49 | No exemplo acima de interpolação os parenteses são obrigatórios mas 50 | no caso das nossas coordenas o jeito mais comum de declarar é mesmo usando 51 | a sintaxe sem os parenteses e usar os parenteses comente quando for necessário 52 | para desambiguar 53 | 54 | ```py 55 | coord = 140, 200, 9 56 | ``` 57 | 58 | Portanto com este tipo de objeto não temos mais as variáveis `x` e `y` e `z`, 59 | agora temos uma única `coord` e para acessar os objetos que estão dentro da 60 | tupla usamos o protocolo de **subscrição**, os objetos que possuem um método 61 | chamado `__getitem__` permitem que a gente acesse seus elementos usando `[ ]` e 62 | nós também já fizemos isso lá no primeiro script quando fatiamos a variável de 63 | ambiente. (`current_language = os.getenv("LANG")[:5]`) 64 | 65 | Então digamos que precisamos em nosso **jogo** posicionar um objeto na tela 66 | naquela exata coordenada como fazemos? 67 | 68 | 69 | ```py 70 | coord = 140, 200, 9 71 | 72 | mover_x_para_coordenada(coord[0]) 73 | mover_y_para_coordenada(coord[1]) 74 | mover_z_para_coordenada(coord[2]) 75 | ``` 76 | 77 | Repare que podemos acessar `coord[0]` e assim por diante usando `[numero]` e este 78 | número se refere a posição do valor que queremos dentro da tupla. 79 | 80 | Nestes casos, assumimos que seu software na hora de criar a variável `coord` se 81 | encarrega de colocar cada coisa em seu devido lugar :) 82 | 83 | Existe uma infinidade de usos práticos para as tuplas, nós ainda falaremos muito 84 | delas durante o treinamento e faremos os principais usos como em retorno de funções 85 | e leitura de banco de dados. 86 | 87 | ### Desempacotamento 88 | 89 | A característica mais interessante das tuplas se chama **unpacking** ou 90 | desempacotamento em português. 91 | (algumas linguagens chamam isso de **spread, espalhamento, explode**) 92 | 93 | O desempacotamento permite fazer a operação contrária da atribuição olha que 94 | interessante. 95 | 96 | ```py 97 | # Empacotamento (atribuição) 98 | coord = 140, 200, 9 99 | 100 | # Desempacotamento (atribuição multipla) 101 | x, y, z = coord 102 | ``` 103 | 104 | No desempacotamento o Python automaticamente vai pegar cada um dos elementos 105 | da tupla e usar para definir as variáveis que separarmos por `,`. 106 | 107 | 108 | > Aliás, está ai uma dica que ainda não falamos, é possível atribuir mais de 109 | > uma variável ao mesmo tempo em Python 110 | > `a, b, c, d = None` faz com que todas sejam referencias para `None` 111 | 112 | ### Imutabilidade 113 | 114 | Outra característica importante e que talvez seja decisiva na hora de escolher 115 | usar tuplas é o fato de que elas são imutáveis, uma vez criada a tupla, não 116 | é possível alterar, não dá para mudar os valores ou adicionar novos. 117 | (este tópico contém algumas exceções que veremos na nossa aula sobre escopos) 118 | 119 | ### Algumas coisas que podemos fazer com as tuplas 120 | 121 | ```py 122 | # Atribuir sem parenteses 123 | coord = 140, 200, 9 124 | 125 | # atribuir com parenteses 126 | coord = (140, 200, 9) 127 | 128 | # desempacotar 129 | x, y, z = coord 130 | 131 | # ignorar elementos (será atribuito apenas o x) 132 | x, *_ = coord 133 | 134 | # pegar apenas o primeiro e o último elemento 135 | x, *_, y = coord 136 | 137 | # Verificar o tamanho 138 | len(coord) 139 | 3 140 | 141 | # Acessar via subscrição pelo indice 142 | coord[0] 143 | 140 144 | 145 | # fatiar 146 | coord[1:] 147 | (200, 9) 148 | ``` -------------------------------------------------------------------------------- /docs/d2/d2p06_0_listas.md: -------------------------------------------------------------------------------- 1 | ## Listas 2 | 3 | Listas são bastante similares as tuplas e a maioria das operações que podemos 4 | fazer com tuplas também podemos fazer com as listas, uma das grandes diferenças 5 | está na implementação de protocolos de edição dos elementos, portanto as listas 6 | são mutáveis e permitem que incluamos novos itens, permitem a remoção de itens 7 | existentes e a reordenação. 8 | 9 | As listas são criadas usando os literais `[ ]` ou a chamada para a classe `list` 10 | 11 | Criando uma lista vazia 12 | 13 | ```py 14 | colors = [] # forma preferida 15 | # ou 16 | colors = list() 17 | ``` 18 | 19 | Adicionando elementos ao final da lista 20 | 21 | ```py 22 | colors.append("green") 23 | ``` 24 | 25 | Adicionando elementos ao inicio da lista 26 | 27 | ```py 28 | colors.insert(0, "red") 29 | ``` 30 | 31 | Adicionando em uma posição especifica 32 | 33 | ```py 34 | colors.insert(2, "blue") 35 | ``` 36 | 37 | Obtendo o tamanho da lista 38 | 39 | ```py 40 | len(colors) 41 | ``` 42 | 43 | Acessando elementos via índice 44 | 45 | ```py 46 | button_color = colors[0] 47 | ``` 48 | 49 | Desempacotamento (igual as tuplas) 50 | 51 | ```py 52 | red, green, blue = colors 53 | ``` 54 | 55 | E também é possível já iniciar uma lista com valores. 56 | 57 | ```py 58 | >>> colors = ["red", "green", "blue"] 59 | >>> colors[0] 60 | "red" 61 | ``` 62 | 63 | Podemos somar 2 listas (criando uma nova lista como resultado) 64 | 65 | ```py 66 | >>> nova_lista = colors + ["yellow"] 67 | >>> print(nova_lista) 68 | ["red", "green", "blue", "yellow"] 69 | ``` 70 | 71 | E podemos estender uma lista `in-place` 72 | 73 | ```py 74 | >>> colors.extend(["purple"]) 75 | >>> print(colors) 76 | ["red", "green", "blue", "purple"] 77 | 78 | 79 | # Ou usando um operador de acréscimo 80 | >>> colors += ["purple"] 81 | >>> print(colors) 82 | ["red", "green", "blue", "purple"] 83 | 84 | ``` 85 | 86 | Remover elementos 87 | ```py 88 | colors.remove("purple") 89 | # ou 90 | colors.pop() 91 | ``` 92 | 93 | Contar elementos 94 | 95 | ``` 96 | >>> colors.count("green") 97 | 1= 98 | ``` 99 | 100 | Mais uma vez vos digo que existe uma infinidade de coisas interessantes 101 | para fazermos com a lista e faremos tudo em nossos exercícios e projetos 102 | durante o treinamento. -------------------------------------------------------------------------------- /docs/d2/d2p06_1_exercicio_listas_tuplas.md: -------------------------------------------------------------------------------- 1 | ```py 2 | #!/usr/bin/env python3 3 | """Exibe relatório de crianças por atividade. 4 | 5 | Imprimir a lista de crianças agrupadas por sala 6 | que frequentas cada uma das atividades. 7 | """ 8 | __version__ = "0.1.0" 9 | 10 | # Dados 11 | sala1 = ["Erik", "Maia", "Gustavo", "Manuel", "Sofia", "Joana"] 12 | sala2 = ["Joao", "Antonio", "Carlos", "Maria", "Isolda"] 13 | 14 | aula_ingles = ["Erik", "Maia", "Joana", "Carlos", "Antonio"] 15 | aula_musica = ["Erik", "Carlos", "Maria"] 16 | aula_danca = ["Gustavo", "Sofia", "Joana", "Antonio"] 17 | 18 | atividades = [ 19 | ("Inglês", aula_ingles), 20 | ("Música", aula_musica), 21 | ("Dança", aula_danca), 22 | ] 23 | 24 | # Listar alunos em cada atividade por sala 25 | 26 | for nome_atividade, atividade in atividades: 27 | 28 | print(f"Alunos da atividade {nome_atividade}\n") 29 | print("-" * 40) 30 | 31 | atividade_sala1 = [] 32 | atividade_sala2 = [] 33 | 34 | for aluno in atividade: 35 | if aluno in sala1: 36 | atividade_sala1.append(aluno) 37 | elif aluno in sala2: 38 | atividade_sala2.append(aluno) 39 | 40 | print("Sala1 ", atividade_sala1) 41 | print("Sala2 ", atividade_sala2) 42 | 43 | print() 44 | print("#" * 40) 45 | 46 | ``` -------------------------------------------------------------------------------- /docs/d2/d2p07_sets.md: -------------------------------------------------------------------------------- 1 | ## Sets 2 | 3 | Na antiga 5 séria (atual 1 ano do ensino médio) aprendemos a teoria dos conjuntos. 4 | 5 | ![](./imgs/sets.jpg) 6 | 7 | Python tem um tipo de objeto para representar este tipo composto, 8 | as características de uso são bastante similares com listas e tuplas, 9 | mas é um objeto bastante particular e tem usos especificos. 10 | 11 | Sets podem ser criados usando as sintaxes: 12 | 13 | ```py 14 | # A partir de qualquer objeto iterável 15 | iteravel = [1, 2, 3] # list 16 | iteravel = 1, 2, 3 # tuple 17 | iteravel = "Banana" # str 18 | 19 | # usando a classe 20 | set(iteravel) 21 | 22 | # usando literais com { e } 23 | {1, 2, 3, 4} 24 | 25 | # desempacotando tuplas, listas ou textos 26 | {*iteravel} 27 | ``` 28 | 29 | Aplicamos a teoria dos conjuntos usando operadores 30 | 31 | 32 | ```py 33 | >>> conjunto_a = [1, 2, 3, 4, 5] 34 | >>> conjunto_b = [4, 5, 6, 7, 8] 35 | 36 | # | para união 37 | >>> set(conjunto_a) | set(conjunto_b) 38 | {1, 2, 3, 4, 5, 6, 7, 8} 39 | 40 | # & para intersecção 41 | >>> set(conjunto_a) & set(conjunto_b) 42 | {4, 5} 43 | 44 | # – para diferença 45 | >>> set(conjunto_a) - set(conjunto_b) 46 | {1, 2, 3} 47 | 48 | # para ^ diferença simétrica 49 | >>> set(conjunto_a) ^ set(conjunto_b) 50 | {1, 2, 3, 6, 7, 8} 51 | ``` 52 | 53 | Interessante mas você pode estar se perguntando onde usar isso? 54 | 55 | Pensa em uma rede social como o twitter, no conjunto A estao as pessoas 56 | que você segue, no conjunto B estão as que te seguem de volta, com este 57 | objeto você consegue determinar rapidamente quem não está te seguindo de volta. 58 | 59 | Você pode também usar set para determinar quais seguidores você e algum amigo 60 | tem em comum na mesma rede social. 61 | 62 | ### Performance 63 | 64 | Fazer buscar em sequencias é uma operação bastante pesada, imagina que no seu 65 | twitter você tem 5000 seguidores e você deseja buscar um deles ou fazer essas 66 | operações de comparação como fizemos com os conjuntos. 67 | 68 | Se você tiver uma lista `["joao", "bruno", "maria", ...]` contendo os elementos, e quiser 69 | por exemplo buscar pelo usuário `"alfredo"` o python vai ter que percorrer toda a lista 70 | e comparar elemento por elemento até encontrar o alfredo, e se o alfredo estiver no final? 71 | Vai demorar muito, essa é uma operação que tem uma complexidade algorítmica `O(n)` pois 72 | Python vai ter que efetuar uma comparação para cada item `n` da lista. 73 | 74 | Os sets implementam uma hash table! 🎉 75 | 76 | É como se eles tivessem um índice gravado neles com uma tabela invertida dizendo 77 | ```py 78 | "joao" -> "esta na posição 0" 79 | "alfredo" -> "esta na posicao 345" 80 | ``` 81 | Portanto quando precisarmos buscar o `alfredo` o python olha primeiro essa tabela 82 | e já vai diretamente na informação que está em `345` como se fizéssemos `users[345]` 83 | em uma lista e a complexidade desta operação passa a ser `O(1)` pois agora só 84 | tem uma comparação a ser feita. 85 | 86 | Bom, eu estou super simplificando a ideia aqui para você, tem mais detalhes 87 | internos nessa implementação mas deu para sacar né? 88 | 89 | Por quê isso importa? **Sets são mais rápidos!** 90 | 91 | operações como `if "alfredo" in usuarios:` se `usuarios` for um `set` irá ser 92 | bem mais rápido do que caso `usuarios` seja uma lista ou tupla. 93 | 94 | ### Mutabilidade 95 | 96 | Você pode criar um conjunto vazio e ir adicionando elementos e também pode 97 | remover elementos, eles são mutáveis 98 | 99 | ```py 100 | >>> a = set([1,2,3]) 101 | >>> a.add(4) 102 | >>> a.remove(1) 103 | >>> print(a) 104 | {2, 3, 4} 105 | ``` 106 | 107 | ### Deduplicação 108 | 109 | Esta é uma das característica mais interessante dos sets e talvez a sua maior 110 | utilidade, sets não permitem itens duplicados, então ao criar um set você 111 | elimina as duplicidades. 112 | 113 | ```py 114 | >>> conjunto = set() 115 | >>> conjunto.add("Bruno") 116 | >>> conjunto.add("Maria") 117 | >>> conjunto.add("Bruno") 118 | >>> conjunto.add("Maria") 119 | >>> conjunto.add("Bruno") 120 | >>> conjunto.add("Bruno") 121 | >>> conjunto.add("Bruno") 122 | >>> conjunto.add("Bruno") 123 | 124 | # Digamos que por algum motivo (ou engano) adicionou o mesmo item mais de uma vez 125 | # sem problemas :) 126 | 127 | >>> print(conjunto) 128 | {'Bruno', 'Maria'} 129 | 130 | # E isso também functiona em tempo de atribuição 131 | >>> {1, 2, 3, 1, 1, 1, 1, 5, 5, 5, 5} 132 | {1, 2, 3, 5} 133 | ``` 134 | 135 | ### Desvantagens dos sets? 136 | 137 | - Não respeitam a ordem de inserção, os elementos são ordenados automaticamente 138 | - Não permitem subscrição para acesso aos valores 139 | 140 | Ou seja, você não pode fazer `set[0]` para acessar o primeiro elemento. 141 | 142 | ```py 143 | >>> conjunto = {4, 5, 6, 7, 8} 144 | 145 | conjunto[0] 146 | --------------------------------------------- 147 | TypeError Traceback (most recent call last) 148 | Input In [60], in 149 | ----> 1 conjunto[0] 150 | 151 | TypeError: 'set' object is not subscriptable 152 | ``` 153 | 154 | mas pode usar `in` ou converter o set em uma lista. 155 | 156 | ```py 157 | >>> 4 in conjunto 158 | True 159 | 160 | 161 | >>> list(conjunto)[0] 162 | 4 163 | ``` -------------------------------------------------------------------------------- /docs/d2/imgs/ascii.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d2/imgs/ascii.png -------------------------------------------------------------------------------- /docs/d2/imgs/cartesiano.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d2/imgs/cartesiano.png -------------------------------------------------------------------------------- /docs/d2/imgs/memoria.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d2/imgs/memoria.png -------------------------------------------------------------------------------- /docs/d2/imgs/pasta_docs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d2/imgs/pasta_docs.jpg -------------------------------------------------------------------------------- /docs/d2/imgs/sets.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d2/imgs/sets.jpg -------------------------------------------------------------------------------- /docs/d3/d3p02_infix.md: -------------------------------------------------------------------------------- 1 | ```py 2 | #!/usr/bin/env python3 3 | """Calculadora infix. 4 | 5 | Funcionamento: 6 | 7 | [operação] [n1] [n2] 8 | 9 | Operações: 10 | sum -> + 11 | sub -> - 12 | mul -> * 13 | div -> / 14 | 15 | Uso: 16 | $ infixcalc.py sum 5 2 17 | 7 18 | 19 | $ infixcalc.py mul 10 5 20 | 50 21 | 22 | $ infixcalc.py 23 | operação: sum 24 | n1: 5 25 | n2: 4 26 | 9 27 | """ 28 | __version__ = "0.1.0" 29 | 30 | import sys 31 | arguments = sys.argv[1:] 32 | 33 | 34 | if not arguments: 35 | operation = input("operação:") 36 | n1 = input("n1:") 37 | n2 = input("n2:") 38 | arguments = [operation, n1, n2] 39 | elif len(arguments) != 3: 40 | print("Número de argumentos inválidos") 41 | print("ex: `sum 5 5`") 42 | sys.exit(1) 43 | 44 | operation, *nums = arguments 45 | 46 | valid_operations = ("sum", "sub", "mul", 'div') 47 | if operation not in valid_operations: 48 | print("Operação inválida") 49 | print(valid_operations) 50 | sys.exit(1) 51 | 52 | validated_nums = [] 53 | for num in nums: 54 | if not num.replace(".", "").isdigit(): 55 | print(f"Numero inválido {num}") 56 | sys.exit(1) 57 | if "." in num: 58 | num = float(num) 59 | else: 60 | num = int(num) 61 | validated_nums.append(num) 62 | 63 | n1, n2 = validated_nums 64 | 65 | 66 | if operation == "sum": 67 | result = n1 + n2 68 | elif operation == "sub": 69 | result = n1 - n2 70 | elif operation == "mul": 71 | result = n1 * n2 72 | elif operation == "div": 73 | result = n1 / n2 74 | 75 | print(f"O resultado é {result}") 76 | 77 | ``` -------------------------------------------------------------------------------- /docs/d3/d3p04_exercicio_notas.md: -------------------------------------------------------------------------------- 1 | ```py 2 | #!/usr/bin/env python3 3 | """Bloco de notas 4 | 5 | $ notes.py new "Minha Nota" 6 | tag: tech 7 | text: 8 | Anotacao geral sobre carreira de tecnologia 9 | 10 | $ notes.py 1 tech 11 | ... 12 | ... 13 | """ 14 | __version__ = "0.1.0" 15 | 16 | import os 17 | import sys 18 | 19 | cmds = ("read", "new") 20 | path = os.curdir 21 | filepath = os.path.join(path, "notes.txt") 22 | 23 | arguments = sys.argv[1:] 24 | if not arguments: 25 | print("Invalid usage") 26 | print(f"you must specify subcommand {cmds}") 27 | sys.exit(1) 28 | 29 | if arguments[0] not in cmds: 30 | print(f"Invalid command {argument[0]}") 31 | 32 | if arguments[0] == "read": 33 | # leitura das notas 34 | for line in open(filepath): 35 | title, tag, text = line.split("\t") 36 | if tag.lower() == arguments[1].lower(): 37 | print(f"title: {title}") 38 | print(f"text: {text}") 39 | print("-" * 30) 40 | print() 41 | 42 | if arguments[0] == "new": 43 | title = arguments[1] 44 | text = [ 45 | f"{title}", 46 | input("tag:").strip(), 47 | input("text:\n").strip(), 48 | ] 49 | # \t - tsv 50 | with open(filepath, "a") as file_: 51 | file_.write("\t".join(text) + "\n") 52 | 53 | ``` -------------------------------------------------------------------------------- /docs/d3/d3p05_exceptions.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #!/usr/bin/env python3 3 | import os 4 | import sys 5 | 6 | # EAFP - Easy to ASk Forgiveness than permission 7 | # (É mais fácil pedir perdão do que permissão) 8 | 9 | try: 10 | names = open("names.txt").readlines() # FileNotFoundError 11 | except FileNotFoundError as e: 12 | print(f"{str(e)}.") 13 | sys.exit(1) 14 | # TODO: Usar retry 15 | else: 16 | print("Sucesso!!!") 17 | finally: 18 | print("Execute isso sempre!") 19 | 20 | try: 21 | print(names[2]) 22 | except: 23 | print("[Error] Missing name in the list") 24 | sys.exit(1) 25 | ``` -------------------------------------------------------------------------------- /docs/d3/d3p06_logging.md: -------------------------------------------------------------------------------- 1 | ``` 2 | #!/usr/bin/env python3 3 | 4 | import os 5 | import logging 6 | from logging import handlers 7 | 8 | # BOILERPLATE 9 | log_level = os.getenv("LOG_LEVEL", "WARNING").upper() 10 | log = logging.Logger("bruno", log_level) 11 | #ch = logging.StreamHandler() # Console/terminal/stderr 12 | #ch.setLevel(log_level) 13 | fh = handlers.RotatingFileHandler( 14 | "meulog.log", 15 | maxBytes=300, # 10**6 16 | backupCount=10, 17 | ) 18 | fh.setLevel(log_level) 19 | fmt = logging.Formatter( 20 | '%(asctime)s %(name)s %(levelname)s ' 21 | 'l:%(lineno)d f:%(filename)s: %(message)s' 22 | ) 23 | # ch.setFormatter(fmt) 24 | fh.setFormatter(fmt) 25 | #log.addHandler(ch) 26 | log.addHandler(fh) 27 | 28 | 29 | """ 30 | log.debug("Mensagem pro dev, qe, sysadmin") 31 | log.info("Mensagem geral para usuarios") 32 | log.warning("Aviso que nao causa erro") 33 | log.error("Erro que afeta uma unica execucao") 34 | log.critical("Erro geral ex: banco de dados sumiu") 35 | """ 36 | 37 | try: 38 | 1 / 0 39 | except ZeroDivisionError as e: 40 | log.error("Deu erro %s", str(e)) 41 | ``` -------------------------------------------------------------------------------- /docs/d3/d3p07_allgoritmos.md: -------------------------------------------------------------------------------- 1 | # Algoritmos 2 | 3 | Sequencia de instruções lógicas que visam obter a solução de 4 | um problema. 5 | 6 | Problema: Ir a padaria e comprar pão: 7 | Premissa: Padaria da Esquina abre fds: até 12h, semana até 19h, feriado (exceto Natal) não abre. 8 | 9 | 1. A padaria está aberta? 10 | 1. Se é feriado e NÃO é natal: não 11 | 2. Senão, Se é sábado OU domingo E antes do meio dia: sim 12 | 3. Senão, se é dia de semana E antes das 19h: sim 13 | 4. senão: não 14 | 2. Se padaria está aberta E: 15 | 1. Se está chovendo: Pegar guarda-chuvas 16 | 2. Se está chovendo E calor: Pegar guarda-chuvas e garrafa de agua 17 | 3. Se está chovendo E frio OU nevando: pegar guarda chuva, blusa e botas 18 | 4. Ir até a padaria: 19 | 1. Se tem pao integral E baguete: Pedir 6 de cada 20 | 2. Senão, se tem apenas pao integral OU baguete: Pedir 12 21 | 3. Senão: Pedir 6 de qualquer pão 22 | 3. Senão 23 | 1. Ficar em casa em comer bolachas 24 | 25 | ## Statements 26 | 27 | - Se -> If (condicao) 28 | - Senão -> elif (condicao) / else 29 | 30 | ## Operadores lógicos 31 | 32 | - E -> and (condicao composta com porta lógica AND) 33 | - OU -> or (condicao composta com porta lógica OR) 34 | - NÃO -> not (sinal de negação) 35 | 36 | ## Assignments 37 | 38 | - A padaria está aberta? (boll, True|False) 39 | 40 | ## Expressions 41 | 42 | - É feriado e NÃO é natal 43 | - é sábado OU domingo E antes do meio dia? 44 | - é dia de semana E antes das 19h? 45 | - ... 46 | 47 | ## Ações 48 | 49 | - pegar 50 | - ir 51 | - pedir 52 | - tem 53 | - comer 54 | 55 | 56 | ## Transformando em código 57 | 58 | 59 | ```py 60 | 61 | import pegar, ir, pedir, tem, comer 62 | 63 | # Premissas 64 | today = "Segunda" 65 | hora_atual = 15 66 | natal = False 67 | chovendo = True 68 | frio = False 69 | nevando = True 70 | semana = ["Segunda", "Terça", "Quarta", "Quinta", "Sexta"] 71 | feriados = ["Quarta"] 72 | horario_padaria { 73 | "semana": 19, 74 | "fds": 12, 75 | } 76 | 77 | # Algoritmo 78 | 79 | # A padaria está aberta? 80 | if today in feriados and not natal: 81 | padaria_aberta = False 82 | elif today not in semana and hora_atual < horario_padaria["fds"]: 83 | padaria_aberta = True 84 | elif today in semana and hora_atual < horario_padaria["semana"]: 85 | padaria_aberta = True 86 | else: 87 | padaria_aberta = False 88 | 89 | if padaria_aberta: 90 | if chovendo and (frio or nevando): 91 | pegar("guarda chuva") 92 | pegar("blusa") 93 | pegar("botas") 94 | elif chovendo and not frio: 95 | pegar("guarda chuva") 96 | pegar("agua") 97 | elif chovendo: 98 | pegar("guarda chuva") 99 | ir("padaria") 100 | 101 | if tem("pao integral") and tem("baguete"): 102 | pedir(6, "pao integral") 103 | pedir(6 "baguete") 104 | elif tem("pao integral") or tem("baguete"): 105 | pedir(12, "pao integral ou baguete") 106 | else: 107 | pedir(6, "qualquer pao") 108 | else: 109 | comer("bolachas") 110 | ``` -------------------------------------------------------------------------------- /docs/d3/d3p08_condicionais_inline.md: -------------------------------------------------------------------------------- 1 | # Condicionais Inline 2 | 3 | 4 | Condicionais em Python são escritas com a palavra `if` exemplo: 5 | 6 | 7 | ```py 8 | aberto = True 9 | if aberto: 10 | print("Boas vindas, pode entrar") 11 | else: 12 | print("Desculpe, estamos fechados") 13 | ``` 14 | 15 | Essa mesma condicional pode ser expressa usando um condicional **ternário** 16 | também chamado de **if inline** 17 | 18 | ```py 19 | aberto = True 20 | print("Boas vindas, pode entrar" if aberto else "Desculpe, estamos fechados") 21 | ``` 22 | 23 | Essa construção é bastante útil em casos onde precisamos atribuir variáveis: 24 | 25 | ```py 26 | if temperatura > 30: 27 | mensagem = "Está calor" 28 | else: 29 | mensagem = "Está frio" 30 | ``` 31 | 32 | Pode ser reescrito com: 33 | 34 | ```py 35 | mensagem = "Está calor" if temperatura > 30 else "Está frio" 36 | ``` 37 | 38 | Operadores lógicos. 39 | 40 | Também é possível usar operadores lógicos para criar condicionais abreviadas. 41 | 42 | > **NOTA** Muito cuidado ao escolher esta opção, pois além de estar sujeita 43 | > a falsos positivos também não é tão fácil de ler. 44 | 45 | ```py 46 | aberto = True 47 | print(aberto and "Boas vindas, pode entrar" or "Desculpe, estamos fechados") 48 | ``` 49 | 50 | O interessante é ver como os operadores lógicos `and` e `or` podem ser 51 | usados para tomar decisões. -------------------------------------------------------------------------------- /docs/d3/d3p09_repeticoes.md: -------------------------------------------------------------------------------- 1 | # TODO: -------------------------------------------------------------------------------- /docs/d3/d3p10_exericios.md: -------------------------------------------------------------------------------- 1 | # Exercicios 2 | 3 | Agora vamos fazer uma série de exercícios de fixação. 4 | 5 | 6 | 7 | ## Faça um programa que imprime os números pares de 1 a 200 8 | 9 | ex 10 | `python numeros_pares.py` 11 | ```py 12 | 13 | 2 14 | 4 15 | 6 16 | 8 17 | ... 18 | ``` 19 | 20 | ## Alarme de temperatura 21 | 22 | Faça um script que pergunta ao usuário qual a temperatura atual e o indice de umidade do ar 23 | sendo que caso será exibida uma mensagem de alerta dependendo das condições: 24 | 25 | temp maior 45: "ALERTA!!! 🥵 Perigo calor extremo" 26 | temp maior que 30 e temo vezes 3 for maior ou igual a umidade: "ALERTA!!! 🥵♒ Perigo de calor úmido" 27 | temp entre 10 e 30: "😀 Normal" 28 | temp entre 0 e 10: Fr"🥶 Frio"io 29 | temp <0: "ALERTA!!! ⛄ Frio Extremo." 30 | 31 | ex: 32 | ```py 33 | python3 temp.py 34 | temperatura: 30 35 | umidade: 90 36 | ... 37 | "ALERTA!!! 🥵♒ Perigo de calor úmido" 38 | ``` 39 | 40 | ## Repete vogais 41 | 42 | Faça um programa que pede ao usuário que digite uma ou mais palavras e imprime cada uma das palavras 43 | com suas vogais duplicadas. 44 | 45 | ex: 46 | ```py 47 | python repete_vogal.py 48 | 'Digite uma palavra (ou enter para sair):' Python 49 | 'Digite uma palavra (ou enter para sair):' Bruno 50 | 'Digite uma palavra (ou enter para sair):' 51 | Pythoon 52 | Bruunoo 53 | ``` 54 | 55 | ## Reserva hotel 56 | 57 | Faça um programa de terminal que exibe ao usuário uma listas dos quartos disponiveis para 58 | alugar e o preço de cada quarto, esta informação está disponível em um arquivo de texto 59 | separado por virgulas. 60 | 61 | `quartos.txt` 62 | ``` 63 | # codigo, nome, preço 64 | 1,Suite Master,500 65 | 2,Quarto Familia,200 66 | 3,Quarto Single,100 67 | 4,Quarto Simples,50 68 | ``` 69 | 70 | O programa pergunta ao usuário o nome, qual o número do quarto a ser reservado 71 | e a quantidade de dias e no final exibe o valor estimado a ser pago. 72 | 73 | O programa deve salvar esta escolha em outro arquivo contendo as reservas 74 | 75 | `reservas.txt` 76 | ``` 77 | # cliente, quarto, dias 78 | Bruno,3,12 79 | ``` 80 | 81 | Se outro usuário tentar reservar o mesmo quarto o programa deve exibir uma 82 | mensagem informando que já está reservado. 83 | -------------------------------------------------------------------------------- /docs/d3/imgs/io.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d3/imgs/io.png -------------------------------------------------------------------------------- /docs/d3/imgs/precedencia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d3/imgs/precedencia.png -------------------------------------------------------------------------------- /docs/d4/_email.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | from email.mime.text import MIMEText 3 | 4 | # setamos algumas constantes 5 | SERVER = "localhost" 6 | PORT = 8025 7 | FROM = "eu@server.com" 8 | TO = ["destino@outroserver.com", "outro@server.com"] 9 | SUBJECT = "Assunto do e-mail" 10 | TEXT = "Este é meu e-mail enviado via Python no terminal :)" 11 | 12 | message = MIMEText(TEXT, "html") 13 | message["Subject"] = SUBJECT 14 | message["From"] = FROM 15 | message["To"] = ", ".join(TO) 16 | 17 | # with smtplib.SMTP(host=SERVER, port=PORT) as server: 18 | # server.sendmail(FROM, TO, message.as_string()) 19 | 20 | with smtplib.SMTP("smtp.mailtrap.io", 2525) as server: 21 | server.login("83f1618af77272", "ff77c56ae6ef22") 22 | server.sendmail(FROM, TO, message.as_string()) -------------------------------------------------------------------------------- /docs/d4/d4p01_funcoes_uteis-builtin.md: -------------------------------------------------------------------------------- 1 | # Funções incluídas no Python 2 | 3 | Funções são uma maneira de definir um bloco de código que pode ser reutilizado diversas vezes. 4 | 5 | Python vem com uma grande quantidade de funções úteis e estão divididas entre as **builtin** (embutidas) e as 6 | das **stdlib** (biblioteca padrão instalada junto com o Python) 7 | 8 | ## Funções builtin úteis 9 | 10 | Python já vem com uma série de funções úteis https://docs.python.org/3/library/functions.html 11 | 12 | ### SUM 13 | 14 | Obtem a soma dos elementos de um iterável contendo números 15 | 16 | ```py 17 | >>> sum([1, 2, 3]) 18 | 6 19 | ``` 20 | 21 | ### MAX 22 | 23 | Retorna o item com maior valor em uma sequência 24 | 25 | ```py 26 | >>> max([1, 2, 3]) 27 | 3 28 | ``` 29 | 30 | ### MIN 31 | 32 | Retorna o item com menor valor em uma sequência 33 | 34 | ```py 35 | >>> min([1, 2, 3]) 36 | 1 37 | ``` 38 | 39 | ### LEN 40 | 41 | Retorna o tamanho de uma sequência 42 | 43 | ```py 44 | >>> len([1, 2, 3]) 45 | 3 46 | >>> len("Bruno") 47 | 5 48 | ``` 49 | 50 | ### Reversed 51 | 52 | Retorna uma sequência invertida 53 | 54 | ```py 55 | >>> list(reversed([1, 2, 3])) 56 | [3, 2, 1] 57 | ``` 58 | 59 | ### Sorted 60 | 61 | Retorna uma sequência ordenada alfabeticamente 62 | 63 | ```py 64 | >>> list(sorted([9, 8, 1, 2, 3])) 65 | [1, 2, 3, 8, 9] 66 | ``` 67 | 68 | ### Filter 69 | 70 | Aplica um filtro em uma sequência, sendo que o filtro é uma função que deve retornar True ou False 71 | 72 | ```py 73 | >>> list(filter(str.isdigit, "Bruno987Rocha452")) 74 | ['9', '8', '7', '4', '5', '2'] 75 | ``` 76 | 77 | ### MAP 78 | 79 | Aplica uma função de transformação em cima de uma sequência 80 | 81 | ```py 82 | >>> list(map(str.upper, ["bruno", "rocha"])) 83 | ['BRUNO', 'ROCHA'] 84 | ``` 85 | 86 | ### All 87 | 88 | Retorna `True` se todos os elementos da sequência forem avaliados para True 89 | 90 | ```py 91 | >>> valores = [True, True, False] 92 | >>> all(valores) 93 | False 94 | ``` 95 | > **Atenção**: `all([])` é `True` 96 | 97 | ### Any 98 | 99 | 100 | Retorna True se pelo menos um elemento da lista for avaliada para True 101 | 102 | ```py 103 | >>> valores = [True, True, False] 104 | >>> any(valores) 105 | True 106 | ``` 107 | 108 | ### Enumerate 109 | 110 | Retorna um objeto iteravél que fornece a numeração de itens de uma sequência 111 | 112 | ```py 113 | >>> nomes = ["Bruno", "Joao", "Maria", "Sofia"] 114 | 115 | >>> for num, nome in enumerate(nomes): 116 | ... print(num, nome) 117 | 0 Bruno 118 | 1 Joao 119 | 2 Maria 120 | 3 Sofia 121 | 122 | >>> for num, nome in enumerate(nomes, start=5): 123 | ... print(num, nome) 124 | 5 Bruno 125 | 6 Joao 126 | 7 Maria 127 | 8 Sofia 128 | 129 | ``` 130 | 131 | ### ZIP 132 | 133 | Junta 2 sequências em pares 134 | 135 | ```py 136 | >>> colunas = ["nome", "sobrenome"] 137 | >>> dados = ["Bruno", "Rocha"] 138 | 139 | >>> zip(colunas, dados) 140 | Out[38]: 141 | 142 | >>> list(zip(colunas, dados)) 143 | [('nome', 'Bruno'), ('sobrenome', 'Rocha')] 144 | 145 | >>> dict(zip(colunas, dados)) 146 | {'nome': 'Bruno', 'sobrenome': 'Rocha'} 147 | 148 | ``` -------------------------------------------------------------------------------- /docs/d4/d4p03_primeira_funcao_e_formula_math.md: -------------------------------------------------------------------------------- 1 | # Criando Funções 2 | 3 | Função, na matemática é a uma estrutura que relaciona um conjunto A (dominio) a um conjunto B (contradominio) e seu subconjunto (imagem). 4 | 5 | A função da programação é um pouco diferente mas opera de maneira bastante similar, a função na programação recebe um input com um conjunto de dados (dominio) e opera este conjunto com relação ao seu resultado de retorno (contradominio). 6 | 7 | ```text 8 | f(x) = 5 * (x / 2) 9 | ``` 10 | 11 | Calma, nosso objetivo aqui por enquanto não é a matemática, apenas a estrutura da função. 12 | 13 | Em programação é chamada de função um bloco pre-definido de código que recebe em seu input um conjunto de dados (argumentos), aplica um algoritmo e retorna um resultado (retorno). 14 | 15 | ```python 16 | def f(x): 17 | return 5 * (x / 2) 18 | ``` 19 | 20 | As funções podem ser usadas para descrever fórmulas matemáticas como a do exemplo anterior, pois assim como na matemática as linguagens de programação oferecem as estruturas necessárias como variáveis, conjuntos e operadores. 21 | 22 | ![](./imgs/heron.png) 23 | 24 | Em Python 25 | 26 | ```python 27 | def heron(a, b, c): 28 | perimeter = a + b + c 29 | s = perimeter / 2 30 | area = (s * (s - a) * (s - b) * (s - c)) ** 0.5 31 | return area 32 | ``` 33 | 34 | Agora em qualquer parte do programa você pode reutilizar essa função quando precisar da area de um triangulo. 35 | 36 | Calculando a area de um triangulo: 37 | 38 | ```python 39 | a = int(input("Digite o valor de a: ").strip()) 40 | b = int(input("Digite o valor de b: ").strip()) 41 | c = int(input("Digite o valor de c: ").strip()) 42 | 43 | print("A área do triângulo é: ", heron(a, b, c)) 44 | ``` 45 | 46 | Calculando a area de multiplos triangulos: 47 | 48 | ```python 49 | triangulos = [ 50 | (3, 4, 5), 51 | (5, 12, 13), 52 | (8, 15, 17), 53 | (12, 35, 37), 54 | (3, 4, 5), 55 | (5, 12, 13), 56 | (8, 15, 17), 57 | (12, 35, 37) 58 | ] 59 | for t in triangulos: 60 | print("A área do triângulo é: ", heron(t[0], t[1], t[2])) 61 | 62 | # Ou usando unpacking 63 | for t in triangulos: 64 | print("A área do triângulo é: ", heron(*t)) 65 | ``` 66 | 67 | ### Anatomia de uma função 68 | 69 | A função é declarada usando a keyword `def` seguida de seu nome, seguido de parênteses `()` e o marcador de bloco de código `:`. 70 | 71 | ```python 72 | def nome_da_funcao(): 73 | # bloco de código 74 | ``` 75 | 76 | O nome de uma função é apenas um identificador, uma variável que aponta para o objeto função, nomeamos as funções usando `snake_case` e seguindo as mesmas restrições de nomes de variáveis. 77 | 78 | ![](./imgs/fun1.png) 79 | 80 | A função pode receber um ou mais argumentos, que são os valores que serão passados para a função utilizar em seu algoritmo. 81 | 82 | Cada argumento da função é uma variável, um identificador que vai apontar para o objeto que for passado para a função. 83 | 84 | Fazemos a chamada de função (também falamos "invocação da função") usando o nome da função, seguido de parênteses `()` e os valores que serão passados para os argumentos da função. 85 | 86 | ```python 87 | def nome_da_funcao(a, b, c): 88 | ... 89 | 90 | nome_da_funcao(1, 2, 3) 91 | ``` 92 | 93 | ![](./imgs/fun2.png) 94 | 95 | 96 | Toda função tem um retorno, que é o valor que será retornado pela função, quando não especificado, o retorno é sempre `None`. 97 | 98 | ```python 99 | def nome_da_funcao(a, b, c): 100 | ... 101 | 102 | resultado = nome_da_funcao(1, 2, 3) 103 | 104 | print(type(resultado)) 105 | ``` 106 | 107 | ![](./imgs/fun3.png) 108 | 109 | 110 | Podemos especificar o retorno da função usando a keyword `return` sempre na última linha do bloco de código. 111 | 112 | ```python 113 | def nome_da_funcao(a, b, c): 114 | return a + b + c 115 | 116 | resultado = nome_da_funcao(1, 2, 3) 117 | print(resultado) 118 | ``` 119 | 120 | ![](./imgs/./imgs/fun4.png) 121 | -------------------------------------------------------------------------------- /docs/d4/d4p04_anatomia_de_funcoes.md: -------------------------------------------------------------------------------- 1 | # Qual o motivo de usarmos funções? 2 | 3 | O primeiro motivo nós já vimos, que é a aplicação de funções matemáticas de acordo com suas respectivas fórmulas. 4 | 5 | Mas as funções também podem ser usadas para simplesmente organizar o código provendo: 6 | 7 | - Encapsulamento de código em escopo `protegido` 8 | - Reutilização de código 9 | - Composição com outras funções 10 | - Compartilhamento em forma de bibliotecas de funções 11 | - Organização de códigos semanticamente. 12 | 13 | ### Organização 14 | 15 | ```py 16 | print("Welcome to the test.) 17 | input("When you are ready press enter.) 18 | 19 | name = input("name:") 20 | print(f"It is nice to meet you {name}") 21 | 22 | color = input("Quat is your favorite color?") 23 | print(f"{color} is a great color!") 24 | 25 | input("Describe yourself") 26 | print("admirable!") 27 | 28 | print("Goodbye.) 29 | ``` 30 | 31 | Organizando: 32 | 33 | ```py 34 | def welcome(): 35 | print("Welcome to the test.") 36 | input("When you are ready press enter.") 37 | 38 | 39 | def ask_questions(): 40 | name = input("name:") 41 | print(f"It is nice to meet you {name}") 42 | 43 | color = input("Quat is your favorite color?") 44 | print(f"{color} is a great color!") 45 | 46 | input("Describe yourself") 47 | print("admirable!") 48 | 49 | 50 | def goodbye(): 51 | print("Goodbye.) 52 | 53 | 54 | welcome() 55 | ask_questions() 56 | goodbye() 57 | ``` 58 | 59 | Neste caso temos **procedimentos** armazenados como funções. 60 | 61 | ## Composição: 62 | 63 | ```py 64 | names = ["Bruno", "Joao", "Bernardo", "Barbara", "Brian"] 65 | 66 | def start_with_b(name): 67 | return name[0].lower() == "b" 68 | 69 | names_with_b = list(filter(start_with_b, names)) 70 | ``` 71 | 72 | ## Anatomia das funções 73 | 74 | As funções são formadas por alguns elementos: 75 | 76 | - definição (ou atribuição) - `def nome_da_funcao` 77 | - assinatura - Tudo o que estiver entre parenteses - `(a, b ,c)` e antes de `:` 78 | - código interno 79 | - valor de retorno - Tudo o que tiver depois de `return` 80 | 81 | ```python 82 | def nome_da_funcao(a, b, c): 83 | return a + b + c 84 | ``` 85 | 86 | ## Argumentos 87 | 88 | Ao passar os argumentos para as funções podemos passa-los posicionalmente ou nomeadamente. 89 | 90 | Argumentos posicionais: 91 | 92 | ```python 93 | nome_da_funcao(1, 2, 3) 94 | ``` 95 | 96 | Argumentos nominais: 97 | 98 | ```python 99 | nome_da_funcao(a=1, b=2, c=3) 100 | ``` 101 | 102 | A grande diferença é que no caso dos posiciais devemos nos atentar a sempre passar o valor correto na posição correta, enquanto nos nominais não precisamos nos preocupar com a ordem. 103 | 104 | ```python 105 | nome_da_funcao(b=2, a=1, c=3) 106 | ``` 107 | 108 | E também podemos passar argumentos nomeados e posicionais ao mesmo tempo. 109 | 110 | ```python 111 | nome_da_funcao(1, b=2, c=3) 112 | ``` 113 | 114 | Neste caso a regra é que os argumentos posicionais sempre são declarados antes dos nomeados. 115 | 116 | A partir do Python 3.4 podemos ainda anotar os tipos de dados dos argumentos de uma função: 117 | 118 | ```python 119 | def nome_da_funcao(a: int, b: int, c: int) -> int: 120 | return a + b + c 121 | ``` 122 | 123 | O trecho `a: int` indica que o argumento `a` é do tipo inteiro, 124 | isto é chamado `type hint` ou `dica de tipo` em português, o Python não usa essa informação, ela serve apenas para o programador ter uma melhor experiência ao utilizar as funções e para ferramentas externas fazerem verificações. (ainda falaremos mais sobre esse tópico em breve) 125 | 126 | Todas essas caracteristicas de uma função são o que chamamos de **assinatura de função** (nome, argumentos, ordem, tipos, tipo de retorno) 127 | 128 | Anteriormente já falamos um pouco sobre **tuplas** e sobre como podemos fazer coisas interessantes com elas como atribuição de multiplas variáveis e desempacotamento. 129 | 130 | ```python 131 | coordenadas = 1, 2, 3 # atribuição multipla 132 | x, y, x = coordenadas # desempacotamento 133 | ``` 134 | 135 | Isto também é bastante útil em funções pois elas podem retornar tuplas. 136 | 137 | ```python 138 | def nome_da_funcao(): 139 | return 1, 2, 3 # tupla 140 | 141 | x, y, z = nome_da_funcao() 142 | ``` 143 | 144 | E também podemos usar o **desempacotamento** para passar argumentos para funções, neste caso usamos um `*` para forçar o desempacotamento. 145 | 146 | ```python 147 | triangulo = (3, 4, 5) 148 | area = heron(*triangulo) # desempacotamento das posições da tupla 149 | print(f"A area do triangulo é {area}") 150 | ``` 151 | 152 | E o mesmo funciona quando os valores estão em um dicionário. 153 | 154 | ```python 155 | triangulo = {'a': 3, 'b': 4, 'c': 5} 156 | area = heron(**triangulo) # desempacotamento dos valores do dicionário 157 | print(f"A area do triangulo é {area}") 158 | 159 | ``` -------------------------------------------------------------------------------- /docs/d4/d4p06_lambdas.md: -------------------------------------------------------------------------------- 1 | ### Funções de primeira classe 2 | 3 | Em Python funções também são objetos, e podem ser utilizadas como qualquer outro objeto, ou seja, uma função pode ser passada como paramêtro para outra função. 4 | 5 | 6 | ```python 7 | 8 | # Digamos que tenhamos uma coleção de utilidades 9 | 10 | def transforma_em_maiusculo(texto): 11 | return texto.upper() 12 | 13 | def transforma_em_minusculo(texto): 14 | return texto.lower() 15 | 16 | def divide_por_2(numero): 17 | return numero // 2 18 | 19 | # e nossa função principal 20 | 21 | def faz_algo(valor, funcao): 22 | return funcao(valor) 23 | 24 | print(faz_algo("bruno", transforma_em_maiusculo)) 25 | # BRUNO 26 | 27 | print(faz_algo("BRUNO", transforma_em_minusculo)) 28 | # bruno 29 | 30 | print(faz_algo(10, divide_por_2)) 31 | # 5 32 | ``` 33 | 34 | E isso permite fazer uma enorme quantidade de composição de funções. 35 | 36 | ### Funções anonimas 37 | 38 | As vezes é conveniente passar uma função como paramêtro para outra função, mas não queremos que essa função seja definida, pois será uma função de uso único. 39 | 40 | ```python 41 | faz_algo(10, lambda x: x * 2) 42 | # 20 43 | faz_algo(10, lambda x: x // 2) 44 | # 5 45 | faz_algo("python é bom", lambda x: x.title()) 46 | # Python É Bom 47 | ``` 48 | 49 | A biblioteca padrão do Python utiliza deste recurso em uma grande parte de suas funções: 50 | 51 | ```python 52 | nomes = ["Bruno", "João", "Maria", "Carlos", "Erik"] 53 | print(sorted(nomes, key=len) 54 | # ['João', 'Erik', 'Bruno', 'Maria', 'Carlos'] 55 | 56 | filter(lambda x: x.startswith("B"), nomes) 57 | # ['Bruno'] 58 | ``` 59 | 60 | Algumas regras: 61 | 62 | - A função `lambda` pode receber argumentos 63 | - A função `lambda` não pode retornar valor 64 | - A função `lambda` não DEVE ser definida como variável 65 | - A função `lambda` não pode ter mais de uma expressão 66 | 67 | ## Protocolo callable 68 | 69 | As funções fazem parte dos objetos que implementam o protocolo `callable`, ao longo do treinamento veremos outros objetos `callable` e aprenderemos a adicionar este protocolo aos objetos. 70 | 71 | Para verificar se um objeto é `callable` basta utilizar a função `callable`: 72 | 73 | ```python 74 | print(callable(lambda x: x)) 75 | # True 76 | ``` -------------------------------------------------------------------------------- /docs/d4/d4p07_recursao_e_retry.md: -------------------------------------------------------------------------------- 1 | # Paradigmas de programação 2 | 3 | O paradigma de programação imperativo/procedural é o que usamos na maior parte do tempo 4 | neste paradigma as instruções são definidas uma a uma e utilizamos alocação de variáveis 5 | para manter o estado do programa. 6 | 7 | No paradigma funcional usamos funções e a habilidade de podermos passar funções como 8 | argumentos para outras funções e também o uso de composição com chamadas recursivas 9 | e evitamos ao máximo a alocação de variáveis para a funções não ter efeitos colaterais. 10 | 11 | ## Comparativo 12 | 13 | ```py 14 | """Imprime apenas os nomes iniciados com a letra B""" 15 | 16 | names = [ 17 | "Bruno", 18 | "Joao", 19 | "Bernardo", 20 | "Barbara", 21 | "Brian", 22 | ] 23 | 24 | ``` 25 | 26 | 27 | ### estilo funcional 28 | 29 | ```py 30 | print(*list(filter(lambda text: text[0].lower() == "b", names)), sep="\n") 31 | ``` 32 | 33 | ### Estilo procedural / imperativo 34 | 35 | ```py 36 | def starts_with_b(text): 37 | """Return bool if text starts with b""" 38 | return text[0].lower() == "b" 39 | 40 | 41 | filtro = filter(starts_with_b, names) 42 | filtro = list(filtro) 43 | for name in filtro: 44 | print(name) 45 | ``` 46 | 47 | ## Retry 48 | 49 | As vezes queremos tentar várias vezes executar uma tarefa sujeita a erros de maneira 50 | que possamos customizar a quantidade de tentativas. 51 | 52 | Isto é bastante útil em cenários onde dependemos de operações de I/O como leitura de 53 | arquivos, servidores e serviços que precisam ser executados etc. 54 | 55 | 56 | Neste script estamos abrindo um arquivo em modo leitura e lendo as suas 57 | linhas através do método `readlines()` que nos retorna uma lista contendo 58 | cada uma das linhas do arquivo. 59 | 60 | `cat errors.py` 61 | ```py 62 | #!/usr/bin/env python3 63 | import os 64 | import sys 65 | 66 | # EAFP - Easy to ASk Forgiveness than permission 67 | # (É mais fácil pedir perdão do que permissão) 68 | 69 | try: 70 | names = open("names.txt").readlines() # FileNotFoundError 71 | except FileNotFoundError as e: 72 | print(f"{str(e)}.") 73 | sys.exit(1) 74 | # TODO: Usar retry 75 | else: 76 | print("Sucesso!!!") 77 | finally: 78 | print("Execute isso sempre!") 79 | ``` 80 | 81 | Porém, caso o arquivo não exista teremos um erro chamado `FileNotFoundError` 82 | 83 | Logo após o `sys.exit(1)` nós colocamos um `TODO: Usar retry` e vamos agora desenvolver 84 | o retry. 85 | 86 | ### Retry com loop 87 | 88 | A primeira forma de efetuar um retry é usando `loop` 89 | 90 | - criamos uma função que tenta abrir o arquivo um certo número de tentativas 91 | - chamamos essa função em nosso script 92 | 93 | ```py 94 | #!/usr/bin/env python3 95 | import time 96 | import logging 97 | 98 | log = logging.Logger("errors") 99 | 100 | # EAFP - Easy to ASk Forgiveness than permission 101 | # (É mais fácil pedir perdão do que permissão) 102 | 103 | 104 | def try_to_open_a_file(filepath, retry=1): 105 | for attempt in range(1, retry + 1): 106 | print(f"tentativa número {attempt}") 107 | try: 108 | return open(filepath).readline() 109 | except FileNotFoundError as e: 110 | log.error("ERRO %s", e) 111 | time.sleep(2) 112 | # ^ isso aqui é só para fingir que estamos esperando um processo terminar 113 | else: 114 | print("Sucesso!!!") 115 | finally: 116 | print("Execute isso sempre!") 117 | return [] 118 | 119 | 120 | for line in try_to_open_a_file("names.txt", retry=5): 121 | print(line) 122 | ``` 123 | 124 | No código acima criamos uma função que podemos chamar passando o argumento `retry=5` 125 | e esta função irá tentar abrir o arquivo 5 vezes antes de falhar. 126 | 127 | ### Retry com recursão 128 | 129 | Recursão é quando uma função é capaz de invocar ela mesma para efetuar a repetição de seu 130 | próprio algoritmo. 131 | 132 | Python não é uma linguagem otimizada para recursão e possui um limite de 1000 chamadas 133 | portanto ao escrever funções recursivas precisamos nos atentar a validação deste limite 134 | e entre outros cuidados está também o correto tratamento de exceptions e o correto 135 | retorno do valor da função executada. 136 | 137 | ```py 138 | #!/usr/bin/env python3 139 | import time 140 | import logging 141 | 142 | log = logging.Logger("errors") 143 | 144 | 145 | # EAFP - Easy to Ask Forgiveness than permission 146 | # (É mais fácil pedir perdão do que permissão) 147 | 148 | def try_to_open_a_file(filepath, retry=1) -> list: 149 | """Tries to open a file, if error, retries n times.""" 150 | if retry > 999: 151 | raise ValueError( 152 | "Retry cannot be above 999 because of Python recursion limit" 153 | ) 154 | 155 | try: 156 | return open(filepath).readlines() # FileNotFoundError 157 | except FileNotFoundError as e: 158 | log.error("ERRO: %s", e) 159 | time.sleep(2) 160 | if retry > 1: 161 | # recursão 162 | return try_to_open_a_file(filepath, retry=retry - 1) 163 | else: 164 | print("Sucesso!!!") 165 | finally: 166 | print("Execute isso sempre!") 167 | 168 | return [] 169 | 170 | 171 | for line in try_to_open_a_file("names.txt", retry=5): 172 | print(line) 173 | ``` -------------------------------------------------------------------------------- /docs/d4/imgs/escopos.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d4/imgs/escopos.jpg -------------------------------------------------------------------------------- /docs/d4/imgs/fun1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d4/imgs/fun1.png -------------------------------------------------------------------------------- /docs/d4/imgs/fun2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d4/imgs/fun2.png -------------------------------------------------------------------------------- /docs/d4/imgs/fun3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d4/imgs/fun3.png -------------------------------------------------------------------------------- /docs/d4/imgs/fun4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d4/imgs/fun4.png -------------------------------------------------------------------------------- /docs/d4/imgs/fun5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d4/imgs/fun5.png -------------------------------------------------------------------------------- /docs/d4/imgs/fun6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d4/imgs/fun6.png -------------------------------------------------------------------------------- /docs/d4/imgs/fun7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d4/imgs/fun7.png -------------------------------------------------------------------------------- /docs/d4/imgs/fun8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d4/imgs/fun8.png -------------------------------------------------------------------------------- /docs/d4/imgs/heron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d4/imgs/heron.png -------------------------------------------------------------------------------- /docs/d4/imgs/pudb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d4/imgs/pudb.png -------------------------------------------------------------------------------- /docs/d4/imgs/vscodepdb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d4/imgs/vscodepdb.png -------------------------------------------------------------------------------- /docs/d5/README.md: -------------------------------------------------------------------------------- 1 | # Testes 2 | 3 | No Day 5 o código e material está incluido no projeto https://github.com/rochacbruno/dundie-rewards 4 | 5 | 6 | ```py 7 | # decorators 8 | from functools import wraps 9 | 10 | ## Dobra 11 | 12 | def dobra(f) 13 | @wraps(f) 14 | def modificador(a, b): 15 | return f(a * 2, b * 2) 16 | return modificador 17 | 18 | 19 | ## Aplicando o decorator 20 | funcao = dobra(funcao) 21 | 22 | ## OU 23 | 24 | @dobra 25 | def soma(a, b): 26 | return a + b 27 | 28 | 29 | assert soma(1, 2) == 6 30 | 31 | 32 | ## TExto HTML 33 | 34 | def bold(f): 35 | @wraps(f) 36 | def wrapper(text): 37 | result = f(text) 38 | return f"{result}" 39 | return wrapper 40 | 41 | 42 | def italic(f): 43 | @wraps(f) 44 | def wrapper(text): 45 | result = f(text) 46 | return f"{result}" 47 | return wrapper 48 | 49 | 50 | @bold 51 | @italic 52 | def hello(text): 53 | return f"Hello {text}" 54 | 55 | 56 | assert hello("Bruno") == 'Hello Bruno' 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/d5/project.md: -------------------------------------------------------------------------------- 1 | # Projeto Dundie Rewards 2 | 3 | Nós fomos contratados pela Dunder Mifflin, grande fabricante de papéis para desenvolver um sistema 4 | de recompensas para seus colaboradores. 5 | 6 | Michael, o gerente da empresa quer aumentar a motivação dos funcionários oferecendo um sistema 7 | de pontos que os funcionários podem acumular de acordo com as suas metas atingidas, bonus oferecidos 8 | pelo gerente e os funcionários podem também trocam pontos entre sí. 9 | 10 | O funcionário pode uma vez a cada ano resgatar seus pontos em um cartão de crédito para gastar onde 11 | quiserem. 12 | 13 | Acordamos em contrato que o MVP (Minimum Viable Product) será uma versão para ser executada no terminal 14 | e que no futuro terá também as interfaces UI, web e API. 15 | 16 | Os dados dos funcionários atuais serão fornecidos em um arquivo que pode ser no formato .csv ou .json 17 | e este mesmo arquivo poderá ser usado para versões futuras. `Nome, Depto, Cargo, Email` 18 | 19 | MVP - Terminal 0.1.0 20 | 21 | User Stories: 22 | 23 | Epic: Administração 24 | 25 | - EU como ADMIN quero ser capaz de EXECUTAR O COMANDO `dundie load people.txt` para alimentar o banco de dados com as informações dos funcionários. 26 | - Para cada funcionario no arquivo caso ainda não exista no banco de dados deverá ser criado com a pontuação inicial de `100` para gerentes e `500` para associados, caso já exista as informações diferentes deverão ser atualizadas e 27 | a pontuação somada. 28 | - O sistema deve evitar entrada de associados em duplicidade, e aceitar apenas e-mails válidos. 29 | - O sistema deve criar uma senha inicial para cada funcionário e enviar por email. 30 | - Os dados deverão ser armazenados em um banco de dados SQL. 31 | 32 | - EU como ADMIN quero ser capaz de VISUALIZAR no terminal um relatório contendo as informações dos funcionários 33 | - No terminal desejo ver Nome, e-mail, saldo de pontos, data da última atualização 34 | - Este relatório deverá ter a opção de ser salvo em um arquivo .txt 35 | - `dundie show --dept|--email|--output` 36 | 37 | - Eu como ADMIN quero ser capaz de atribuir pontos para um funcionário especifico ou para todo um departamento. 38 | - `dundie add --dept|--email --value=100` 39 | - `dundie remove --dept|--email --value=100` 40 | 41 | - Eu como ADMIN quero que as operações de ADMIN sejam protegidas por usuário e senha. 42 | 43 | Epic: Movimentação 44 | 45 | - Eu como FUNCIONARIO quero ser capaz de visualizar meu saldo de pontos e extrato de movimentações. 46 | - Eu como FUNCIONARIO quero ser capaz de transferir pontos para outro funcionário 47 | - Eu como FUNCIONARIO quero que as operações sejam protegidas por senha, impedindo que outro usuário altere minha conta 48 | -------------------------------------------------------------------------------- /docs/d5/rich_click.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d5/rich_click.png -------------------------------------------------------------------------------- /docs/d5/system_design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d5/system_design.png -------------------------------------------------------------------------------- /docs/d6/d6p01_paradigmas.md: -------------------------------------------------------------------------------- 1 | # Programação Orientada a Objetos 2 | 3 | ## Objetos 4 | 5 | Em Python tudo é objeto, desde o começo deste treinamento já estamos utilizando 6 | Objetos e já vimos aqui também que um objeto é formado sempre por um `valor`, um 7 | `tipo` e um `id` de memória. 8 | 9 | Até agora criamos nossos programas, como por exemplo o projeto `dundie` 10 | utilizando apenas os tipos de dados primários e compostos embutidos no Python 11 | como `int`, `str`, `list` e `dict` a além disso usamos `funções` para organizar 12 | e tornar o código menos repetitivo. 13 | 14 | ## Paradigmas 15 | 16 | Paradigma de programação é o modelo utilizado para expressar a lógica e manter 17 | o estado dos valores de um programa, existem alguns paradigmas sendo os mais 18 | famosos: Procedural, Declarativo, Funcional e Orientação a Objetos. 19 | 20 | Apesar de usarmos muitos objetos e biliotecas que aplicam a orientação a objetos 21 | como fizemos com `smtplib.SMTP`, `rich.Table` e `log.Logger` nós ainda não 22 | tivemos que criar nossos próprios objetos e você percebeu que é perfeitamente 23 | possível criar um programa em Python completo sem a necessidade de saber sobre 24 | orientação a objetos. 25 | 26 | Existem linguagens que são mais restritas como por exemplo algumas que são 27 | puramente funcionais como Haskell e Scheme, e outras como Java e C# que são 28 | estritamente orientadas a objetos. 29 | 30 | Em Python conseguimos usar uma mistura dos paradigmas imperativo, funcional e 31 | orientado a objetos, podemos orientar todo o nosso programa a apenas um deles ou 32 | na maioria dos casos juntar esses paradigmas em uma única solução. 33 | 34 | Vamos analisar alguns paradigmas que podemos aplicar com Python: 35 | 36 | 37 | ### Paradigma Imperativo (ou procedural) 38 | 39 | Em nosso projeto, nós aplicamos programação procedural e utilizamos um dicionário 40 | compartilhado para armazenar o estado do programa e as suas informações. 41 | 42 | ```py 43 | people = [ 44 | { 45 | "name": "Jim Halpert", 46 | "balance": 500, 47 | "role": "Salesman" 48 | }, 49 | { 50 | "name": "Dwight Schrute", 51 | "balance": 100, 52 | "role": "Manager" 53 | } 54 | ] 55 | 56 | def add_points(person, value): 57 | if person["role"] == "manager": 58 | value *= 2 59 | person["balance"] += value 60 | return person 61 | 62 | for person in people: 63 | add_points(person, 100) 64 | 65 | print(people) 66 | ``` 67 | 68 | Ao executar a saida será: 69 | 70 | ```py 71 | [{'name': 'Jim Halpert', 'balance': 600, 'role': 'Salesman'}, 72 | {'name': 'Dwight Schrute', 'balance': 200, 'role': 'Manager'}] 73 | ``` 74 | Repare que o `balance` dos funcinários foi aumentado. 75 | 76 | No exemplo acima temos um objeto do tipo `list` que em cada uma de suas posições 77 | tem um objeto do tipo `dict` que contém chaves `str` e valores `str` e `int`. 78 | 79 | Nós também criamos uma `função` chamada `add_points` que recebe um dict `pessoa` 80 | e um valor `value` e então aplica uma regra de negócio. 81 | 82 | Na programação procedural utilizamos estruturas de dados como um `dict` para 83 | manter os dados e objetos desacoplados como `function` para definir comportamento. 84 | 85 | ### Misturando com funcional 86 | 87 | Poderiamos neste mesmo programa utilizar um pouco de programação funcional ao 88 | substituir nosso `for` por uma abordagem funcional. 89 | 90 | ```py 91 | map(lambda person: add_points(person, 100), people) 92 | ``` 93 | 94 | E ao executar a saída será: 95 | 96 | ```py 97 | [{'name': 'Jim Halpert', 'balance': 500, 'role': 'Salesman'}, 98 | {'name': 'Dwight Schrute', 'balance': 100, 'role': 'Manager'}] 99 | ``` 100 | 101 | Repare que nada aconteceu com os dados, apesar de termos declarado o `map` 102 | ele não foi executado e não teve `side effects` **ainda** em nossos dados. 103 | 104 | Construções como `map` e `filter` e `reduce` tem avaliação preguiçosa, nós podemos 105 | declarar esses objetos mas a execução acontecerá somente quando consumirmos. 106 | 107 | ```py 108 | result = map(lambda person: add_points(person, 100), people) 109 | print(list(result)) 110 | ``` 111 | 112 | Pensando em paradigma funcional daria para escrevermos este mesmo código de 113 | forma que ele não faria alterações nos dados inicias mas sim criaria uma nova 114 | coleção de dados sem `side effects` e para atingir isso deveriamos escrever 115 | funções "puras" que retornam sempre novos dados sem modificar dados existentes. 116 | 117 | ```py 118 | 119 | def add_points(person, value): 120 | data = person.copy() # copiamos o valor de entrada ao invés de altera-lo 121 | if data["role"] == "manager": 122 | value *= 2 123 | data["balance"] += value 124 | return data 125 | 126 | 127 | result = map(lambda person: add_points(person, 100), people) 128 | print("Resultado funcional:", list(result)) 129 | print("Dados originais sem side effects:", people) 130 | ``` -------------------------------------------------------------------------------- /docs/d6/d6p02_intro_a_oo.md: -------------------------------------------------------------------------------- 1 | ### Orientação a objetos 2 | 3 | A programação orientada a objetos surgiu em 1970 e naquela época os programas 4 | eram escritos das maneiras procedural e funcional, Alan Kay, um matemático 5 | que foi trabalhar na Xerox desenvolvendo uma espécie de tablet chamado Dynabook 6 | sentiu a necessidade de criar uma linguagem de programação onde fosse possível 7 | representar as estruturas de dados de uma maneira mais próxima a objetos do 8 | mundo real e criou a linguagem `Smalltalk` a primeira linguagem orientada a 9 | objetos e que acabou por influenciar a maioria das linguagens que usamos hoje 10 | em dia. 11 | 12 | A orientação a objetos é construida utilizando alguns componentes como 13 | 14 | - Classes: Usando a keyword `class` definimos um tipo de objeto. 15 | - Objetos: Instancias criadar a partir das classes. 16 | - Atributos: As classes podem definir valores nomeados assim como os dicionários. 17 | - Métodos: As classes podem definir funções associadas. 18 | 19 | Exemplo: 20 | 21 | ```py 22 | # Definição da classe 23 | class Person: 24 | """Represents a Person""" 25 | 26 | # Atributos da classe 27 | name = "Jim Halpert" 28 | role = "Salesman" 29 | balance = 100 30 | 31 | # Métodos ou funções associadas 32 | def add_points(person, value): 33 | if person.role == "manager": 34 | value *= 2 35 | person.balance += value 36 | 37 | jim = Person() # Instanciação de um objeto a partir da classe 38 | 39 | jim.add_points(500) # Chamada de método associado 40 | 41 | print(jim.balance) # Acesso a atributo 42 | ``` 43 | 44 | Usamos a palavra `class` seguida de um nome para atribuir esse nome ao objeto 45 | de memória que irá conter o código e o escopo de dados da classe. 46 | 47 | A regra de estilo agora difere das funções e precisa ter suas palavras iniciadas 48 | em Maiusculo portanto uma classe para representar uma maçã vermelha se chamaria 49 | `RedApple` ao invés de `red_apple` ou `Red_Apple`, este padrão é chamado de 50 | `PascalCase` ou `UpperCamelCase`. 51 | 52 | A classe é um namespace, portanto dentro da sua definição iniciamos um novo 53 | bloco de código após os `:` que seguem o seu nome e a partir dai todas as 54 | regras que já conhecememos continuam valendo, podemos dentro do corpo da classe 55 | definir variáveis usando qualquer tipo de dados mas agora chamaremos essas 56 | variáveis de `atributos` e também podemos escrever funções dentro da classe 57 | e essas funções serão associadas a esta classe e chamaremos de `métodos`. 58 | 59 | Uma classe é uma estrutura de dados composta e de fato internamente o Python 60 | usará um dicionário para armazenar suas informações: 61 | 62 | ```py 63 | print(Person.__dict__) 64 | ``` 65 | ```py 66 | { 67 | 'name': 'Jim Halpert', 68 | 'role': 'Salesman', 69 | 'balance': 100, 70 | 'add_points': , 71 | '__doc__': 'Represents a Person' 72 | } 73 | ``` 74 | 75 | Esses atributos que consultamos em `Person.__dict__` são chamados `atributos de classe` 76 | e eles serão atribuidos a todos os objetos criados a partir desta mesma classe. 77 | 78 | ```py 79 | pessoa1 = Person() 80 | pessoa2 = Person() 81 | 82 | print(pessoa1.name) 83 | print(pessoa1.__dict__) 84 | print(pessoa2.name) 85 | ``` 86 | ```py 87 | Jim Halpert 88 | Jim Halpert 89 | ``` 90 | 91 | Repare que as nossas 2 instancias `pessoa1` e `pessoa2` agora possuem o mesmo 92 | valor no atributo `nome` e faria mais sentido principalmente para nosso projeto 93 | `dundie` termos pessoas com nomes diferentes mas todos os objetos criados 94 | a partir de uma mesma classe possuem todos os atributos definidos no corpo da 95 | classe. 96 | 97 | Quando fazermos o instanciamento de um objeto usando uma classe, o Python cria 98 | um novo objeto na memória para cada instância. 99 | 100 | ```py 101 | print(id(pessoa1)) 102 | print(id(pessoa2)) 103 | 140015571746576 104 | 140015571746528 105 | ``` 106 | 107 | porém os atributos do corpo da classe 108 | sempre serão os mesmos. 109 | 110 | ```py 111 | print(id(pessoa1.name)) 112 | print(id(pessoa2.name)) 113 | 140197426339504 114 | 140197426339504 115 | ``` 116 | 117 | Lembre-se que a atribuição de `name` ocorreu no corpo da classe, portanto 118 | ocorreu uma única vez quando a classe foi criada. 119 | 120 | ```py 121 | print(id(Person.name)) 122 | 140197426339504 123 | ``` 124 | 125 | **E como fazemos para criar objetos diferentes a partir de uma mesma classe?** 126 | 127 | Para que objetos criados a partir de uma mesma classe tenham atributos distintos 128 | estes atributos devem ser atribuidos diretamente na instância. 129 | 130 | ```py 131 | jim = Person() 132 | jim.name = "Jim Halpert" 133 | ``` 134 | 135 | Ou dentro de métodos, os métodos por padrão atuam em cada uma das instancias separadamente, veja o exemplo de nosso método 136 | `add_points` 137 | 138 | ```py 139 | def add_points(person, value): 140 | if person.role == "manager": 141 | value *= 2 142 | person.balance += value 143 | ``` 144 | 145 | Um método de **instância** sempre recebe como injeção de dependência em seu 146 | primeiro parametro a própria instancia e quando queremos atribuir algum valor 147 | a instância sem afetar outros objetos da mesma classe sempre devemos fazer isso 148 | na instância, no nosso exemplo chamamos de `person` e, `def add_points(person,` 149 | mas por convenção é comum nomearmos esse argumento como `**self**`. 150 | 151 | ```py 152 | pessoa1.add_points(100) 153 | pessoa2.add_points(200) 154 | print(pessoa1.__dict__) 155 | print(pessoa1.balance) 156 | print(pessoa2.__dict__) 157 | print(pessoa1.balance) 158 | {'balance': 200} 159 | 200 160 | {'balance': 300} 161 | 300 162 | ``` 163 | -------------------------------------------------------------------------------- /docs/d6/d6p03_init_method.md: -------------------------------------------------------------------------------- 1 | # Inicialização de objetos 2 | 3 | **E como fazemos para criar objetos diferentes a partir de uma mesma classe?** 4 | 5 | Para que objetos criados a partir de uma mesma classe tenham atributos distintos 6 | estes atributos devem ser atribuidos diretamente na instância. 7 | 8 | ```py 9 | jim = Person() 10 | jim.name = "Jim Halpert" 11 | ``` 12 | 13 | Ou dentro de métodos, os métodos por padrão atuam em cada uma das instancias separadamente, veja o exemplo de nosso método 14 | `add_points` 15 | 16 | ```py 17 | def add_points(person, value): 18 | if person.role == "manager": 19 | value *= 2 20 | person.balance += value 21 | ``` 22 | 23 | Um método de **instância** sempre recebe como injeção de dependência em seu 24 | primeiro parametro a própria instancia e quando queremos atribuir algum valor 25 | a instância sem afetar outros objetos da mesma classe sempre devemos fazer isso 26 | na instância, no nosso exemplo chamamos de `person` e, `def add_points(person,` 27 | mas por convenção é comum nomearmos esse argumento como `**self**`. 28 | 29 | ```py 30 | pessoa1.add_points(100) 31 | pessoa2.add_points(200) 32 | print(pessoa1.__dict__) 33 | print(pessoa1.balance) 34 | print(pessoa2.__dict__) 35 | print(pessoa1.balance) 36 | {'balance': 200} 37 | 200 38 | {'balance': 300} 39 | 300 40 | ``` 41 | 42 | Vamos utilizar um exemplo mais simples para ficar mais fácil de compreender 43 | a estrutura de uma classe. 44 | 45 | Digamos que em nosso programa desejamos representar frutas. 46 | 47 | ```py 48 | class Fruit: 49 | name = "apple" 50 | 51 | 52 | apple = Fruit() 53 | apple.color = "red" 54 | 55 | banana = Fruit() 56 | banana.color = "yellow" 57 | 58 | print(apple.name, apple.color) 59 | print(banana.name, banana.color) 60 | ``` 61 | ``` 62 | apple red 63 | apple yellow 64 | ``` 65 | 66 | **Algo está errado! a nossa segunda fruta deveria ter no name=banana** 67 | 68 | Lembre-se, neste caso devemos ou efetuar a alteração explicitamente em cima 69 | do objeto `banana` como fizemos com a cor, ou então usar um método de inicialização. 70 | 71 | O protocolo de classes do Python especifica que sempre que existir um método 72 | chamado `__init__` em uma classe, esse método será chamado assim que o objeto for criado 73 | para inicializar a instância do objeto, e esse método é bastante útil para inicializar 74 | objetos com atributos distintos. 75 | 76 | 77 | ```py 78 | class Fruit: 79 | def __init__(self, name, color): 80 | self.name = name 81 | self.color = color 82 | 83 | 84 | apple = Fruit(name="Apple", color="red") 85 | banana = Fruit("Banana", color="yellow") 86 | 87 | print(apple.name, apple.color) 88 | print(banana.name, banana.color) 89 | ``` 90 | ``` 91 | Apple red 92 | Banana yellow 93 | ``` 94 | 95 | Desta forma nós temos uma classe `Fruit` que em sua definição tem apenas um 96 | método chamado `__init__` que por sua vez inicializa instancias cada uma com 97 | seu conjunto separado de atributos e valores. 98 | 99 | **Se uma classe é uma estrutura similar a um dicionário e em um dicionário nós 100 | também podemos armazenar valores e funções qual o motivo de usarmos classes?** 101 | 102 | Vamos analisar isso em mais um exemplo prático, lembra da nossa função que 103 | calcula a area de um triangulo? 104 | 105 | ```py 106 | def heron(a, b, c): 107 | perimeter = a + b + c 108 | s = perimeter / 2 109 | area = (s * (s - a) * (s - b) * (s - c)) ** 0.5 110 | return area 111 | ``` 112 | 113 | e o uso que fizemos dessa função 114 | 115 | ```py 116 | triangulos = [ 117 | (3, 4, 5), 118 | (5, 12, 13), 119 | (8, 15, 17), 120 | (12, 35, 37), 121 | (3, 4, 5), 122 | (5, 12, 13), 123 | (8, 15, 17), 124 | (12, 35, 37), 125 | ] 126 | for t in triangulos: 127 | print("A área do triângulo é: ", heron(*t)) 128 | ``` 129 | 130 | Isso foi feito no modelo imperativo onde a função `heron` ficou separada dos dados 131 | `(a, b, c)` presente em cada triangulo, vamos reescrever usando P.O.O. 132 | 133 | ```py 134 | class Triangle: 135 | def __init__(self, a, b, c): 136 | self.a = a 137 | self.b = b 138 | self.c = c 139 | 140 | def area(self): 141 | perimeter = self.a + self.b + self.c 142 | s = perimeter / 2 143 | area = (s * (s - self.a) * (s - self.b) * (s - self.c)) ** 0.5 144 | return area 145 | 146 | 147 | triangle = Triangle(5, 12, 13) 148 | print(triangle.area()) 149 | ``` 150 | ``` 151 | 30.0 152 | ``` 153 | 154 | Qual a vantagem? é que agora podemos alterar o triangulo interativamente e 155 | recalcular sua área usando o método que está associado. 156 | 157 | ```py 158 | triangle.a = 10 159 | print(triangle.area()) 160 | ``` 161 | ``` 162 | 56.99506557588999 163 | ``` 164 | 165 | O principal motivo para definirmos os nossos próprios tipos de dados é a padronização, 166 | e os outros estão explicados nos 4 pilares da O.O que veremos a seguir. -------------------------------------------------------------------------------- /docs/d6/d6p05_propriedades.md: -------------------------------------------------------------------------------- 1 | # Propriedades 2 | 3 | A outras maneira de encapsular no Python é usando propriedades, é uma forma 4 | bastante elegante e que utiliza um protocolo chamado `Descriptor`, 5 | este modelo se parece bastante com o que vemos em outras linguagens de programação 6 | como Java utilizando getters, setters e deleters. 7 | 8 | ```py 9 | class Conta: 10 | _tipo_de_conta = "corrente" 11 | __id_interno = 985645 12 | 13 | def __init__(self, cliente): 14 | self.cliente = cliente 15 | self._saldo = 0 16 | 17 | @property # getter 18 | def saldo(self): 19 | if self._saldo < 0: 20 | print("AVISO: Você está devendo") 21 | return self._saldo 22 | 23 | @saldo.setter 24 | def saldo(self, value): 25 | self._saldo += value 26 | 27 | @saldo.deleter 28 | def saldo(self): 29 | self._saldo = 0 30 | 31 | 32 | conta = Conta(cliente="Bruno") 33 | conta.saldo = 100 34 | conta.saldo = -10 35 | print(conta.saldo) 36 | ``` 37 | ``` 38 | 90 39 | ``` 40 | 41 | ```py 42 | del conta.saldo 43 | print(conta.saldo) 44 | ``` 45 | ``` 46 | 0 47 | ``` 48 | 49 | Uma grande vantagem em usar o padrão de properties é a possibilidade de 50 | definir métodos internamente e expor como atributos sem a necessidade de 51 | parenteses para chamada. -------------------------------------------------------------------------------- /docs/d7/d7p02_exemplo_orm.md: -------------------------------------------------------------------------------- 1 | # Um ORM escrito com Pydantic 2 | 3 | ORM significa Objetct Relational Mapping e é o nome dado a abordagem 4 | de mapear dados serializados em bancos de dados relacionais com classes e objetos. 5 | 6 | No projeto dundie implementamos um ORM baseado em classes Pydantic. 7 | 8 | O objetivo é a utilização no formato: 9 | 10 | ```py 11 | from dundie.database import connect, commit 12 | from dundie.models import Person, Movement 13 | 14 | db = connect() # carrega os dados do arquivo JSON 15 | 16 | pam = db[Person].get_by_pk("pam@dm.com") # Busca Person através do e-mail 17 | pam_movements = db[Movement].filter(person__pk=pam.pk) # Filtro 18 | 19 | sales_persons = db[Person].filter(dept="Sales") 20 | for person in sales_persons: # iteração 21 | print(person.name) 22 | 23 | pam.dept = "Management" # update 24 | commit(db) # salva de volta no banco de dados 25 | ``` 26 | 27 | A implementação detalhada está em [https://github.com/rochacbruno/dundie-rewards/pull/22/files](https://github.com/rochacbruno/dundie-rewards/pull/22/files) 28 | 29 | 30 | As principais alterações ocorreram nos arquivos: 31 | 32 | - database.py 33 | - models.py 34 | - core.py 35 | 36 | > Não foi necessário alterar nem o cli.py nem o esquema do banco dados. 37 | 38 | 39 | Você pode obter localmente utilizando: 40 | 41 | ```bash 42 | # Se já tiver um repositório com o projeto 43 | git checkout -b orm 44 | git pull https://github.com/rochacbruno/dundie-rewards 45 | 46 | # Se quiser clonar em um projeto novo 47 | git clone https://github.com/rochacbruno/dundie-rewards pasta_destino 48 | cd pasta_destino 49 | git fetch -all 50 | git checkout pydantic_orm 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/d7/d7p08_final.md: -------------------------------------------------------------------------------- 1 | # Finalização do Projeto e Desafios 2 | 3 | 4 | Chegamos so final do day7, calma, o curso ainda não acabou, ainda temos o day8 5 | onde veremos demonstrações de vários tipos de projeto com Python. 6 | 7 | Mas o projeto dundie nós finalizamos o MVP porém sobraram alguns desafios 8 | para você resolver. 9 | 10 | 11 | ## Contribuindo com o Projeto Dundie 12 | 13 | Essas instruções são para os alunos do treinamento Python Base 14 | [https://www.linuxtips.io/products/python-base](https://www.linuxtips.io/products/python-base) 15 | 16 | Você tem 4 issues para resolver e pode ve-las em: [https://github.com/rochacbruno/dundie-rewards/milestone/4](https://github.com/rochacbruno/dundie-rewards/milestone/4) 17 | 18 | ## Requisitos 19 | 20 | - Escreva testes para as funcionalidades que adicionar 21 | - Os testes precisam passar no CI quando enviar o Pull Request 22 | 23 | ## Código de conduta 24 | 25 | - Sem ofensas 26 | - Ajude os colegas de treinamento 27 | 28 | ## Passo a passo para resolver os execicios 29 | 30 | ### Tenha um fork do repositório 31 | 32 | - Clique em [https://github.com/rochacbruno/dundie-rewards/fork](https://github.com/rochacbruno/dundie-rewards/fork) e crie um fork (cópia) do repositório em sua conta do github 33 | 34 | A partir de agora o repositório encontra-se em https://github.com/ SEU USER NAME / dundie-rewards 35 | 36 | ### Obtenha um clone do seu repositório 37 | 38 | ```bash 39 | # se usar https 40 | git clone https://github.com/seunome/dundie-rewards 41 | 42 | # se tiver configurado o SSH 43 | git clone git@github.com:seunome/dundie-rewards.git 44 | ``` 45 | 46 | ### acesse a pasta e configure o `remote` 47 | 48 | O remote `upstream` deve apontar para o repósitorio de `rochacbruno` 49 | 50 | ```bash 51 | cd dundie-rewards 52 | git remote add upstream https://github.com/rochacbruno/dundie-rewards 53 | ``` 54 | 55 | ### Prepare o ambiente 56 | 57 | ```bash 58 | make virtualenv 59 | make install 60 | make test 61 | ``` 62 | 63 | Neste ponto você já tem o projeto funcionando e já pode rodar 64 | 65 | ```bash 66 | source .venv/bin/activate 67 | dundie --help 68 | ``` 69 | 70 | no terminal para interagir com o programa. 71 | 72 | ### Implementação 73 | 74 | Resolva as issues na ordem proposta em [https://github.com/rochacbruno/dundie-rewards/milestone/4](https://github.com/rochacbruno/dundie-rewards/milestone/4) 75 | 76 | 1. Crie uma branch para cada issue e.x: 77 | 78 | ```bash 79 | git checkout -b issue_7 80 | ``` 81 | 82 | > Com o comando acima o git cria uma branch `issue_7` e você agora pode trabalhar no código 83 | 84 | 2. Abra o seu editor favorito e faça a implementação do código! boa sorte 🎉 85 | 86 | 3. Assegure-se da qualidade 87 | ``` 88 | make fmt 89 | make lint 90 | make test 91 | ``` 92 | - Os testes devem passar 93 | - Você deve adicionar novos testes para funcionalidades novas 94 | - A formatação do código tem que estar correta 95 | 96 | 4. Faça o commit ex: 97 | 98 | ```bash 99 | git add . # adiciona todos os arquivos alterados 100 | git commit -m "Implementei a issue 7" 101 | ``` 102 | 5. Faça o push 103 | 104 | Para fazer um push você vai precisar de um access token do git e obter em 105 | 106 | [https://github.com/settings/tokens](https://github.com/settings/tokens/new) 107 | clique em "gerar access token", expiration "nunca", dê um nome "git" e marque todas as opções e clique em generate token. 108 | 109 | Na próxima página copie seu token e salve em local seguro. 110 | 111 | Mais ajuda em: 112 | https://docs.github.com/pt/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token 113 | 114 | ```bash 115 | #configure seu cache de token 116 | git config --global credential.helper cache 117 | ``` 118 | 119 | ``` 120 | git push -u origin HEAD 121 | Username: seunome 122 | Password: 123 | ``` 124 | 125 | > Agora que fez o push a branch `issue_7` foi para seu repositório e você pode ir 126 | a [https://github.com/rochacbruno/dundie-rewards](https://github.com/rochacbruno/dundie-rewards) 127 | e clicar no botão "Novo Pull Request" e abrir o seu PR. 128 | 129 | Ou se preferir na URL abaixo, substitua `seunome` pelo seu user do github. 130 | ``` 131 | https://github.com/rochacbruno/dundie-rewards/compare/main...seunome:issue_7?expand=1 132 | ``` 133 | 134 | > **atenção**: Não será feito merge do seu pull request, o objetivo é apenas rodar o CI e 135 | > fazer os testes passarem, o seu PR ficará esperando aprovação para rodar os testes. 136 | 137 | 5. Volte a sua branch main e faça o rebase 138 | 139 | ```py 140 | git checkout main 141 | git rebase origin/issue_7 142 | git log -n 1 143 | ``` 144 | 145 | > Agora você pode repetir o processo para implementar as outras issues. 146 | 147 | 6. Repita desde o item `1` para as outras issues, substituindo `issue_7` pela issue que estiver 148 | implementando, ex: a próxima da lista é a `issue_4` 149 | 150 | -------------------------------------------------------------------------------- /docs/d7/imgs/db_designer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d7/imgs/db_designer.png -------------------------------------------------------------------------------- /docs/d7/imgs/sql_lang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d7/imgs/sql_lang.png -------------------------------------------------------------------------------- /docs/d7/imgs/vs_open_database.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d7/imgs/vs_open_database.png -------------------------------------------------------------------------------- /docs/d7/imgs/vs_sqlite_explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d7/imgs/vs_sqlite_explorer.png -------------------------------------------------------------------------------- /docs/d7/imgs/vs_sqlite_select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rochacbruno/python-base/806488acd82f00d53d506765fdc95118fcdaefba/docs/d7/imgs/vs_sqlite_select.png -------------------------------------------------------------------------------- /docs/d8/README.MD: -------------------------------------------------------------------------------- 1 | Exemplos em código 2 | 3 | - GUI - Desktop https://github.com/rochacbruno/python-base/tree/main/15_gui 4 | - Game - https://github.com/rochacbruno/python-base/tree/main/16_game 5 | - TUI - https://github.com/rochacbruno/python-base/tree/main/17_tui 6 | - WEB HTML - https://github.com/rochacbruno/python-base/tree/main/18_web 7 | - WEB API - https://github.com/rochacbruno/python-base/tree/main/19_api 8 | --------------------------------------------------------------------------------