2.19. Escrevendo módulos

Qualquer arquivo .py é um módulo. Dividir um script que está crescendo em alguns arquivos mantém cada arquivo curto e permite que auxiliares comuns sejam compartilhados entre scripts.

2.19.1. Dividindo um script

Tire um grupo relacionado de funções para seu próprio arquivo:

camera_utils.py

def banner():
    print("OpenMV")

def label(text):
    return "[" + text + "]"

main.py

import camera_utils

camera_utils.banner()
print(camera_utils.label("ready"))

Saída:

OpenMV
[ready]

Os dois arquivos ficam lado a lado no mesmo diretório. Quando main.py roda, import camera_utilscamera_utils.py uma vez, executa suas instruções de nível superior e vincula o objeto de módulo resultante ao nome camera_utils em main. Um segundo import camera_utils de qualquer outro lugar retorna o mesmo objeto – os módulos ficam em cache após seu primeiro carregamento.

O nome de um módulo vem de seu nome de arquivo, então camera_utils.py é importado como import camera_utils.

2.19.2. Módulos de múltiplos arquivos (pacotes)

Um módulo também pode ser um diretório de arquivos em vez de um único .py. O nome do diretório torna-se o nome do módulo, e os arquivos dentro dele são seus submódulos:

camera_utils/
    __init__.py
    text.py
    timing.py

__init__.py é o arquivo que roda quando o próprio pacote é importado; ele pode estar vazio ou pode reexportar nomes selecionados dos submódulos. Os submódulos são acessados com um nome pontuado:

import camera_utils.text
from camera_utils.timing import elapsed

camera_utils.text.label("ready")

Dentro do pacote, os submódulos podem acessar uns aos outros tanto pelo nome pontuado completo quanto por um import relativo que usa um ponto inicial para significar “este pacote”:

camera_utils/timing.py

from . import text             # the sibling submodule

def stamp(value):
    return text.label(str(value))

Para trazer um nome específico em vez disso, nomeie-o após o irmão pontuado:

from .text import label

def stamp(value):
    return label(str(value))

Os imports relativos mantêm um pacote autocontido: renomear o diretório do pacote não exige editar todos os submódulos.

Use um pacote quando um único arquivo crescer além de um tamanho confortável, ou quando um conjunto de módulos relacionados pertence junto sob um mesmo namespace. Para scripts do dia a dia, um único arquivo .py é suficiente.

2.19.3. A proteção __name__

Todo módulo tem um nome embutido __name__. Seu valor depende de como o arquivo está sendo usado:

  • Quando o arquivo é executado diretamente, __name__ é definido como a string "__main__".

  • Quando o arquivo é importado por outro script, __name__ é definido como o nome do módulo – o nome do arquivo sem .py.

O idioma que usa isso é:

label_util.py

def label(text):
    return "[" + text + "]"

if __name__ == "__main__":
    print(label("self-test"))

Saída (quando executado diretamente):

[self-test]

Quando o mesmo arquivo é importado em vez disso, __name__ é definido como o nome do módulo, então o bloco if é ignorado e nada extra é executado:

>>> import label_util
>>> label_util.__name__
'label_util'

Use o padrão para anexar um teste rápido de fumaça ou uma demonstração a um arquivo de biblioteca sem perturbar scripts que o importam.