Ferramenta web para visualização de execução

Muitas vezes procurei por uma ferramenta legal para que os alunos pudessem visualizar a execução passo a passo de um programa escrito em Python. Nunca encontrava nada, a não ser os tradicionais depuradores. Hoje me deparei com a seguinte ferramenta: http://people.csail.mit.edu/pgbovine/python, desenvolvida no MIT, que cria uma representação visual do programa em execução, mostrando de forma didática as variáveis alocadas, bem como a execução do programa.

 

Sugiro a todos que estão iniciando seus estudos em programação que dêem uma olhada nesse projeto.

http://people.csail.mit.edu/pgbovine/python

Anúncios

Calculando o hash de strings em Python

Usamos o termo hashing para nos referirmos a uma técnica muito utilizada em programação, quando queremos garantir determinadas propriedades sobre os dados que estamos manipulando e transmitindo. Obter o hash de um conjunto de dados significa obter uma string de tamanho fixo que é calculada com base no conteúdo do conjunto de dados.

Por exemplo, o hash (calculado usando o algoritmo md5) da palavra “teste” é mostrado abaixo:

"teste" --> "1ceae7af21732ab80f454144a414f2fa"

Uma mínima modificação na string “teste” irá gerar um hash totalmente diferente:

"testa" --> "9dd18b1a48164eaec9979df1a6aa84aa"

O hashing é muito utilizado para verificar a integridade de um arquivo durante a transmissão deste pela rede. Ao disponibilizar um arquivo para download, uma empresa pode disponibilizar também o hash calculado sobre o arquivo. Assim, para ter certeza de que efetuou o download do arquivo correto (sem este ter sido corrompido), o usuário pode calcular o hash do arquivo recebido e comparar o hash calculado com o hash disponibilizado pela empresa. Se houverem diferenças entre os hashes, isso significa que o arquivo está corrompido.

hashlib

Python oferece um módulo chamado hashlib que fornece funções para cálculo de hash de dados. Como usá-lo?

import hashlib
h = hashlib.md5()
h.update("uma frase qualquer")
print h.hexdigest()

O código acima utiliza a função md5 para obter o hash da string “uma frase qualquer” e imprimí-lo utilizando o valor do hash obtido em hexadecimal. Além do md5, a hashlib implementa os seguintes algoritmos para cálculo de hash:

  • md5
  • sha1
  • sha224
  • sha256
  • sha384
  • sha512

Assim, para utilizar a função sha256, basta fazer:

import hashlib
h = hashlib.sha256()
h.update("uma frase qualquer")
print h.hexdigest()

Maiores informações podem ser obtidas na documentação oficial: http://docs.python.org/library/hashlib.html

range() vs xrange()

(válido somente para Python 2.x)

A função range()

Em Python, é muito comum usarmos a seguinte estrutura para realizar uma repetição baseada em um contador:

for i in range(0, 10):
    print i,

A função range(x, y) gera uma lista de números inteiros de x até y (sem incluir o segundo). Assim, range(0, 10), gera a seguinte lista:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Desse modo, a variável i é iterada sobre essa lista, através da estrutura de repetição for. O trecho de código:

for i in range(0, 10):
    print i,

pode ser lido como:

"Para cada elemento na lista [0,1,2,3,4,5,6,7,8,9], imprima tal elemento"

Usar range() ou xrange()? Eis a questão…

É comum ouvirmos ou lermos algum desenvolvedor Python aconselhando a utilização da função xrange() ao invés da função range(), por questões de desempenho. Mas o que é essa tal de xrange()?

A xrange() nada mais é do que uma função que pode, em muitos casos (não sempre), substituir o uso da função range(), fornecendo ainda melhor desempenho. Veja o código abaixo:

for i in xrange(0, 10):
    print i,

O resultado dessa execução é o mesmo de quando utilizamos a função range(), porém, por gerar um elemento de cada vez, o código que utiliza a função xrange() apresenta um desempenho superior.

Quando executamos:

for i in range(0, 1000000000):
    pass

A função range() irá imediatamente gerar uma lista contendo um bilhão de inteiros e alocar essa lista na memória. Uma lista contendo um bilhão de inteiros é capaz de encher a memória de um computador pessoal.

Já com a função xrange(), ao executarmos:

for i in xrange(0, 1000000000):
    pass

Cada um dos inteiros (dos 1 bilhão) será gerado de uma vez, economizando memória e tempo de startup.

Vamos então testar o desempenho usando o módulo timeit().

 

A hora da verdade

junior@qwerty:~ $ python -m timeit "for i in xrange(10000000): pass"
 10 loops, best of 3: 246 msec per loop
junior@qwerty:~-$ python -m timeit "for i in range(10000000): pass"
 10 loops, best of 3: 342 msec per loop

Como podemos ver, o loop que utiliza a função xrange() foi quase 100 milisegundos mais rápido do que o loop que utiliza a função range(). Além disso, se fizermos uma análise de consumo de memória, veremos que a o código que utiliza a função range() utiliza uma quantidade de memória muito maior, pois gera a lista inteira antes de executar a iteração do for.

Então nunca mais vou usar o range(), certo?

Errado! Existe uma diferença fundamental entre as duas funções: a função xrange() não gera uma lista. Isso torna inviável, por exemplo, o slicing e a gravação de seu resultado como uma lista em uma variável. Vejamos:

>>> x = range(0, 10)
>>> print x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> y = xrange(0, 10)
>>> print y
xrange(10)

Ou seja, apesar de nos fornecer um desempenho superior ao desempenho obtido com a range(), a função xrange() não substitui a anterior em todos os seus casos.