Dependências de montagem (build) do Python

Ocasionalmente precisamos instalar o Python na máquina montando (buildando) ele pelo código fonte, seja através de ferramentas como o pyenv ou o asdf como até manualmente. Para isso são necessárias algumas bibliotecas instaladas, segue a lista delas e o comando para instalar em sistemas baseados no Debian: sudo apt-get install dpkg-dev \ build-essential \ python-dev \ python3-dev \ libncursesw5-dev \ libsqlite3-dev \ libreadline-dev \ libbz2-dev \ libffi-dev \ libssl-dev \ libgdbm-dev \ zlib1g-dev \ libjpeg-dev \ libtiff-dev \ libpq-dev \ libxml2-dev \ libxslt1-dev \ libsdl2-dev \ libsm-dev \ libxtst-dev \ libcurl4-openssl-dev

17 de junho de 2021 · 1 min de leitura · Lucas Polo

Micro tutorial de como funcionam corrotinas

import asyncio from random import randint import time async def funcao_assincrona_com_possivel_chamada_sincrona(n: int): # A corrotina é uma função educadinha, que quando vai fazer # algo que pode demorar fala assim: # "Cara, isso aqui vai demorar pois é operação de IO, podem ir fazendo outra coisa" # Assin o interpretador é liberado para executar outras instruções. for i in range(10): print(f'Task {n} - {i}') # Neste ponto (await) a corrotina concede o direito de execução # de volta, ai é permitido rodar outras corrotinas # que estiverem aguardando, é aqui que a rotina fala # "Gente, pode continuar ai que vou demorar aqui um pouco" # Aqui poderia ser uma requisição web demorada, # um acesso a bancos de dados e outras coisas, por exemplo. print(f'Liberando task {n} - {i}') await asyncio.sleep(randint(0,3)) print(f'Retomando task {n} - {i}') # Aqui acontece a quebra, existe a chance (1 em 1000) de # ser executado um processo blocante que irá # blocar todos as tarefas que estão rodando concorrentemente # Ela não é tão educada quanto parecia quando entra aqui. sorte = randint(0, 1000) if sorte == 50: print print(f'Task {n} blocou a GIL no passo {i}, que azar') time.sleep(3) # Isso aqui blocante! print(f'Concluindo task {n} - {i}') async def main(): # Irá criar mil tarefinhas que serão disparadas em "paralelo" (na verdade concorrentemente) tasks_assincronas_que_podem_blocar = { asyncio.create_task( funcao_assincrona_com_coisa_assincrona(i) ) for i in range(10000) } # Executa todas elas, aguardando todas serem concluidas await asyncio.wait( tasks_assincronas_que_podem_blocar, return_when=asyncio.ALL_COMPLETED ) if __name__ == "__main__": asyncio.run(main())

29 de março de 2020 · 2 min de leitura · Lucas Polo

JoKenPo em Python

Fazer um jogo de JoKemPo em Python é simples, mas para complementar fiz alguns tratamentos diferentes, como a captura de KeyboardException para tratar a saída do programa. from random import choice # Esta função serve para escolher aleatoriamente um elemento da lista! # Dicionário de movimentos, na chave a opção e no valor quem ela ganha! MOVES = { 'rock': 'scissors', 'paper': 'rock', 'scissors': 'paper', } # Lista de opções OPTIONS = list(MOVES.keys()) def _get_user_choice(): """ Recupera e valida a opção do usuário """ while True: user_choice = input('Choose one option [rock/paper/scissors] - ctrl+c to exit: ') if user_choice not in OPTIONS: print('Choose a valid option!') continue return user_choice def _jokenpo(user_choice, computer_choice): """ Valida a regra do jogo, comparando a escolha do usuário com a do computador! """ if MOVES[user_choice] == computer_choice: print('You win!') elif MOVES[computer_choice] == user_choice: print('I win!') else: print('Meh!') if __name__ == "__main__": while True: # Roda infinitamente try: user_choice = _get_user_choice() except KeyboardInterrupt: print('\nBye!') # Caso o usuário aperte ctrl+c sairá do loop infinito break computer_choice = choice(OPTIONS) # Escolhe a opção do computador _jokenpo( user_choice=user_choice, computer_choice=computer_choice, )

11 de fevereiro de 2020 · 1 min de leitura · Lucas Polo

Python que nem Javascript!

Disclaimer: Nunca faça isso na real! Python tem uma natureza funcional muito boa (não tão boa quanto linguagens funcionais, é claro), o que de certo modo faz ele similar com Javascript, utilizando closures e afins. Inclusive permite construções similares a esta abaixo: def Pessoa(nome: str, sobrenome:str, idade:int): def getNome(): return nome def getSobrenome(): return sobrenome def getNomeCompleto(): return f'{nome} {sobrenome}' def getIdade(): return idade return { 'getNome': getNome, 'getSobrenome': getSobrenome, 'getNomeCompleto': getNomeCompleto, 'getIdade': getIdade, } p = Pessoa('Jar Jar', 'Binks', 38) print(p['getNomeCompleto'](), p['getIdade']()) Python não define um meio de criar objetos dinâmicos como Javascript, devido a sua forte tipagem, por isso usei a estrutura de dicionário. O que acontece na verdade é que devolvemos uma coleção de funções que acessam os atributos do “construtor” através de closures. ...

19 de janeiro de 2020 · 2 min de leitura · Lucas Polo

Fazendo upload de arquivos para o Google Cloud Storage com Python (versão de 2020)

O processo é bem simples, porém é necessário antes configurar algumas coisas no Google Cloud e gerar as credenciais necessárias, para este processo pode seguir este tutorial. Lembre-se também de criar uma variável de ambiente com o nome GOOGLE_APPLICATION_CREDENTIALS apontando para o caminho do json, no Linux basta fazer: export GOOGLE_APPLICATION_CREDENTIALS=/caminho/para/arquivo.json Depois disso é possível executar o código abaixo (é claro, o bucket e o arquivo indicado deve existir): from datetime import timezone, datetime from typing import BinaryIO from google.cloud import storage def upload_file( data: BinaryIO, bucket: str, file_path: str, link_lifetime: int = 3600 ) -> str: """ Função que realiza o upload do arquivo """ storage_client = storage.Client() bucket = storage_client.bucket(bucket) blob = bucket.blob(file_path) blob.upload_from_file(data) # Faz o upload do arquivo binário e cria um objeto associado ao arquivo lifetime = int( datetime.now(tz=timezone.utc).timestamp() ) + link_lifetime # Gera um link para o arquivo com tempo de expiração url = blob.generate_signed_url(lifetime) return def main(): bucket = 'meu-pequeno-bucket' # Bucket name in GCS file_name = 'arquivo_legal.pdf' # Filename with open(file_name, 'rb') as f: url = upload_file( data=f, bucket=bucket, file_path=file_name, ) print(f'URL for file: {url}') if __name__ == "__main__": main()

10 de janeiro de 2020 · 1 min de leitura · Lucas Polo

Drops: Quicksort em Python

from typing import List def quicksort(l: List): """ Recebe uma lista de elementos e devolve eles ordenados """ # Caso base! Nunca se esqueça disso em funções recursivas@ if not len(l): return l # Escolhemos um pivot, removemos ele da lista! # Reduzir a entrada também é essêncial! pivot = l.pop(0) # Separamos os elementos menores lower = [e for e in l if e <= pivot] # Separamos os maiores uppper = [e for e in l if e > pivot] # Os menores ficam na esquerda do pivo # Os maiores ficam na direita # Ai acontece a magia da recursão... # Ordedamos os menores e os maiores com a mesma função. return quicksort(lower) + [pivot] + quicksort(uppper) def main(): elems = [3,2,3,6,7,4,2,-1] print(quicksort(elems)) if __name__ == '__main__': main()

3 de janeiro de 2020 · 1 min de leitura · Lucas Polo

Utilizando Celery junto com o SQS

Uma das formas de lidar com processamento assíncrono no Python (e diversas outras linguagens) sem a necessidade de usar threads e afins é utilizando filas e tasks (que são aplicações que rodam conforme demanda, em um processamento similar a batches). Para isso o Python dispõe de uma biblioteca chamada Celery, que de uma maneira bem simples permite realizar o processamento assíncrono. Explicando de uma maneira simples, ao invocar uma função, ao invés de executar seu código, o Celery pega os parâmetros e mais algumas meta-informações da chamada e coloca numa fila, enquanto isso, em outro lugar (processo, computador ou continente), o Celery captura as mensagens desta fila e dispara as tasks. Aqui está uma implementação básica de uma task que soma dois valores: ...

17 de março de 2019 · 2 min de leitura · Lucas Polo

Usando terminal e programando em Python no Android

O terminal é uma das ferramentas mais poderosas que temos ao manipular informações no computador, desde o desenvolvimento de software até o hacking, passando por manipulação de texto, administração de sistemas e também para algumas brincadeiras. O acesso ao terminal é simples quando você está dentro de um Linux no computador (e até no Windows agora), porém nem sempre temos um notebook por perto, que por mais que seja portátil, não é simples de carregar por ai. Então, nas pesquisas pela internet, buscando uma alternativa para o tablet e smartphone, eu encontrei o Termux. ...

25 de fevereiro de 2019 · 2 min de leitura · Lucas Polo

Construindo um interpretador de Lisp em Python

Ultimamente tenho me interessado cada vez mais em como linguagens de programação funcionam e encontrei um material bem legal, simples e prático para ajudar nos estudos. É um artigo do Peter Norvig sobre como criar um interpretador de Scheme em Python, confira: http://norvig.com/lispy.html

22 de janeiro de 2019 · 1 min de leitura · Lucas Polo

Desempacotando parâmetros em Python

Uma das coisas mais interessantes do Python é como ele interage com as suas estruturas de dados padrão, sendo um dos exemplos mais interessantes o desempacotamento de listas e dicionários. A situação é simples, vamos supor que você tenha uma lista de parâmetros e deseja passar para uma função, podemos testar a seguinte situação: def funcao(parametro1, parametro2, parametro3): print(parametro1, parametro2, parametro3) parametros = [1,2,3] funcao(parametros) Mas temos o seguinte erro: ...

4 de janeiro de 2019 · 2 min de leitura · Lucas Polo