Blog em português onde relato a minha aprendizagem de Python. Sendo um blog, ele deve ser lido de baixo para cima e é escrito orientado a uma audiência com alguns conhecimentos de programação. Não tentando ser uma fonte exaustiva de conhecimento sobre Python, pode, no entanto, servir como crash course a esta linguagem.

Saturday, September 5, 2009

Pacotes

Pacotes são uma forma de estruturar conjuntos de módulos de uma forma lógica e útil.

Suponha que quer construir um conjunto de módulos para lidar de forma transparente com vários tipos de imagens. Ler e escrever vários tipos de formatos bem como conseguir aplicar diferentes tipos de efeitos gráficos. Uma possível estrutura para os diferentes módulos é a seguinte:

Imagens/
  formatos/
    jpgread.py
    jpgwrite.py
    bmpread.py
    ...
  efeitos/
    blur.py
    sharpen.py
    ...

Em python aquilo que transforma um conjunto de módulos e directorias num pacote é a presença de um ficheiro chamado __init__.py  na directoria de topo. Este ficheiro é executado quando o pacote ou algum módulo do pacote é importado e, na sua forma mais simples pode ser um ficheiro vazio. A partir de Python 2.5, uma subdirectoria de um pacote é automáticamente um pacote mesmo que esta não contenha o seu __init__.py e esta regra é válida para todas as profundidades.

 Módulos complexos devem usar o ficheiro __init__.py para inicializações. Assim, ficamos com a seguinte hierarquia:

Imagens/
  __init__.py

  formatos/
    jpgread.py
    jpgwrite.py
    bmpread.py
    ...
  efeitos/
    blur.py
    sharpen.py
    ...

cujos  módulos podem ser importados de forma parecida ao Java. Exemplo:
import Imagens.efeitos.blur
cujas funções teriam que ser referenciadas com o nome completo. Para contornar este "problema" podemos também usar a forma from Imagens.efeitos import blur cuja semântica é exactamente igual que quando um módulo não pertencente a um pacote é importado.


Módulos podem importar-se entre si usando caminhos absolutos (a partir de imagens) ou mesmo caminhos relativos.


Por último, os pacotes podem residir no sistema de ficheiros (numa qualquer directoria referenciada por PYTHONPATH) ou ainda num ficheiro do tipo zip de forma transparente.

Wednesday, September 2, 2009

Módulos

É possível definir módulos em python. Qualquer ficheiro com código pode ser um módulo. Para importar um módulo deve-se escrever import moduleName.
Ao importar um módulo, as suas definições não são inseridas no ambiente actual, pelo contrário, apenas o nome do módulo é inserido no ambiente importador.
Vejamos exemplos (tirados de http://docs.python.org/tutorial/modules.html).

Considere-se o ficheiro fibo com o seguinte conteúdo.
# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print b,
        a, b = b, a+b

def fib2(n): # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while b < n:
        result.append(b)
        a, b = b, a+b
    return result
 
Ao fazer import fibo, o ficheiro acima é lido, compilado no momento e o 
nome fibo fica associado (no ambiente importador) ao objecto do tipo Module.
 
Se se quiser que as funcoes e variáveis definidas num módulo fiquem 
visíveis no módulo importador deve-se usar a construção
from module import name1, name2, ...
 
No exemplo anterior, se o objectivo fosse o de inserir as funções fib e fib2
no ambiente importador, poderíamos escrever:
from fibo import fib, fib2
ou até 
from fibo import *
Não aconselho esta última variante pois pode redefinir de uma forma
pouco clara determinadas funções no ambiente importador.
Note-se ainda que estas variantes não introduzem o nome fibo no ambiente.
Tal como em Java, existe um conjunto de directorias onde são procurados
os módulos quando importados. Primeiro na directoria actual e depois, por 
ordem, nas directorias definidas na variável de ambiente PYTHONPATH e por último
numa directoria defeito (normalmente onde o Python está instalado).
Como cada ficheiro pode potencialmente ser visto como um módulo, existe uma forma comum para o código distinguir se está a ser corrido ou importado.
Quando um módulo é executado, o seu atributo __name__ é associado a '__main__'. Quando é importado não é, Assim, é muito comum ver construções do tipo:
if __name__ == '__main__':
  #code executed when this file is executed like a script.
 
Considera-se boa práctica que um módulo puro quando executado directamente
corra testes de integridade ou sirva alguma funcionalidade ao utilizador.
Assim, por exemplo o módulo fibo anterior poderia ter:

if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))
e portanto poderia ser importado e usado por outros programas ou ser usado
directamente como um programa que calcula o fibonacci do seu primeiro
argumento.