Skip to content

Tag: Python

Python: capturando o retorno da linha anterior

Lendo um código eu me deparei com o operador _ do Python.
Ele é uma variável especial para ser usada quando estamos trabalhando no console e queremos referenciar o valor de retorno da linha anterior.
Por exemplo:

>>> 42
42
>>> 1 + _
43

>>> import os
>>> os.getcwd()
'/home/silveira'
>>> _ + '/pasta'
'/home/silveira/pasta'

Eu gostaria ter sabido disso quando eu usava o console do Python pelo meu antigo celular…

Criando uma galeria de imagens com Python

Esse é um script que eu uso muito rotineiramente. Eu escrevi ele porque eu tentei várias soluções mas nenhuma era exatamente o que eu precisava e o que eu preciso é geralmente bem simles.

Só quero pegar um monte de fotos de várias resoluções diferentes e gerar uma página em HTML com as miniaturas das imagens com largura de 500 pixeis e com o link para a imagem original. É uma implementação bem simples, sem muita sofisticação. Eu coloco aqui porque ele é fácil de adaptar para outros usos.

#!/usr/bin/env python
import os
import Image

cwd = os.getcwd()
for arquivo in os.listdir(cwd):
   if arquivo.endswith('.JPG'):
      im = Image.open(arquivo)
      im.thumbnail((500,375), Image.ANTIALIAS)
      nome = arquivo.split('.')[0]
      tnome = nome + "_thumb.jpg"
      im.save(tnome, "JPEG")
      print '
' % (arquivo, tnome)

Ele procura os arquivos do diretório que terminam com .JPG, cria uma miniatura de tamanho 500 por 375 e cospe o HTML na saída padrão. Para usar ele, entre no terminal do diretório onde você quer fazer a galeria e execute o script:

python galeria.py > saida.html

Ele cria galerias bem simples como essa ou essa.

Teste unitário automático em Python

Suponha que um cliente (um cliente muito estranho) te pediu para implementar uma função que calculasse o número de fibonacci.

Então você criou o seguinte código (em Python):

def fibo(n):
   if n < 2:
      return n
   else:
      return fibo(n-1) + fibo(n-2)

Devido ao alto número de chamadas recursivas você nunca criaria esse código. Ele só está aí a título de ilustração. =)

O código está pronto, será que acabou o serviço? Como saber se os requisitos foram atendidos? Os testes unitários podem te ajudar. Basicamente você o comportamento da função para certas entradas e se elas se comportarem bem para essas entradas você admite que ela está correta. Por exemplo, você sabe que fibonacci de 1 é 1 e que o fibonacci de 10 é 55. O que você faria normalmente seria abrir um console Python ou criaria um programa de teste para testar esses valores.

O problema é que depois de um tempo alguém pode alterar a função que você criou. Ou pior, alguém pode alterar um código numa outra parte do programa que o seu código usava para fazer o serviço. Um bom discípulo da engenharia de software iria fazer novos testes unitários toda vez que alguém mexer no código, mas um discípulo ninja mesmo, vai automatizar essa tarefa.

Se você estiver trabalhando com Python há pelo menos duas formas fáceis de você automatizar essa tarefa usando os módulos doctest ou unittest. Esse módulos já vem com o Python por padrão.

Doctest

Com o doctest você só cria testes unitários simplesmente adicionando algumas linhas de comentários ao seu código e depois fazendo uma chamada ao doctest:

def fibo(n):
   """
   >>> fibo(0)
   0
   >>> fibo(1)
   1
   >>> fibo(10)
   55
   """
   if n < 2:
      return n
   else:
      return fibo(n-1) + fibo(n-2)

import doctest
doctest.testmod()

As últimas duas linhas do programa importam o módulo doctest e pedem para testar aquele programa. Se você salvar o programa como fibo.py e executa-lo, nada aparecerá. Isso é bom, quer dizer que você fez tudo certinho. Vamos supor que eu alterei a função fibo de forma que fibo(10)=20, ou seja, um erro. Então você obtem esse comportamento:

$ python fibo.py
****************************
File "fibo.py", line 7, in __main__.fibo
Failed example:
fibo(10)
Expected:
55
Got:
20
****************************
1 items had failures:
1 of 3 in __main__.fibo
***Test Failed*** 1 failures.

Excelente não é? Se você quiser um relatório mais detalhado use a opção verbose do doctest usando a linha de comando python fibo.py -v.

Unittest

Como o nome já diz, o módulo unittest foi feito para fazer testes unitários. Com ele você pode fazer coisas mais avançadas além de testar coisas como função(parâmetro) = resultado_esperado. na verdade o módulo unittest é um framework para testes unitários.

No exemplo, vamos importar a função fibo do arquivo fibo.py e depois criar uma clase do tipo TestCase.

import unittest
from fibo import fibo

class testa_fibonacci(unittest.TestCase):
   def teste_um(self):
      self.assertEqual(fibo(0),0)

   def teste_dois(self):
      self.assertEqual(fibo(1),1)

   def teste_tres(self):
      self.assertEqual(fibo(7),13)

   def teste_quatro(self):
      self.assertEqual(fibo(10),55)

unittest.main()

A execução dele seria assim:

$ python teste.py
....
----------------------------------------------------------------------
Ran 4 tests in 0.001s

OK

Isso foi só uma brevíssima introdução sobre essas ferramentas. Elas conseguem fazer coisas que você nem imagina. Se você se interessa no assunto eu recomendo fortemente a leitura da documentação do módulo unittest.

Para saber mais: Quality Control in Python, Documentação oficial do unittest e Documentação oficial do módulo doctest.

SHA1 em Python

Calcular o SHA1 de uma string em Python é feito quase da mesma forma do calculo do md5 que eu já mostrei aqui antes.

A partir da versão do Python 2.5 a maneira correta de se fazer é assim:

import hashlib
print hashlib.sha1('Silveira').hexdigest()

Isso vai imprimir isto:

25e58a0147633e39c2a2fcceff9a13a181e672b9

Para fazer o calculo do MD5, também se usa a hashlib:

import hashlib
print hashlib.md5('Silveira').hexdigest()

Que vai nos dar o md5 da string ‘Silveira’:

43eb9e4547c642db6cd19713b5c1dff2

O módulo hashlib possui os contrutores md5(), sha1(), sha224(), sha256(), sha384(), e sha512(). Dependendo da implementação da OpenSSL que você tem instalada você poderá ganhar alguns outros construtores.

Maiores informações: documentação da hashlib

Função MD5 em Python

MD5, Message-Digest algorithm 5, é um algoritmo de hash de 128 bits, unidirecional. Ele é muito útil como método de verificação de integridade de arquivos, armazenamento de senhas, criptografia ou para hashing em geral. Eu utilizo ele com muita frequência.

Em Python você calcula o hash de uma string em duas linhas:

import md5
print md5.new('silveira').hexdigest()

O md5.new() retorna um objeto que cria md5. Ele é bem flexível e pode ser utilizado várias vezes. O hexdigest é a representação hexadecimal do md5, aquela que pode ser impressa.

Esse código imprime isso:

3df2175295d900d6f0c2f3a521d957cd

Que é o md5 de silveira.

Manipulando HTML com Python

Criar um parse de XML em Python é trivial, especialmente quando se trata de um documento HTML.

Nesse exemplo, criamos uma classe Parser que vai informar quando se abre ou fecha uma tag. Depois que criamos e instanciamos o Parser, alimentamos ele com o método feed com um documento HTML. Esse documento é pego através do urlopen do módulo urllib, que é um stream e portanto usamos o método read para leitura.

from HTMLParser import HTMLParser
from urllib import urlopen

class Parser(HTMLParser):
   def handle_starttag(self, tag, attrs):
      print "abre tag %s" % tag
   def handle_endtag(self, tag):
      print "fecha tag %s" % tag

url = 'http://www.silveiraneto.net'
Parser().feed( urlopen(url).read() )

Esse é um exemplo bem legal se você quiser brincar com mineração ou obtenção de dados.