De um arquivo a uma pasta de módulos
Um único arquivo deixa de bastar quando o projeto cresce. Um pacote (package) é uma pasta de módulos que o Python pode importar como uma unidade. Marque a pasta com um arquivo chamado __init__.py (pode ser vazio) e cada arquivo .py dentro dela vira um módulo do pacote, indicado com pontos: quant/pricing.py é quant.pricing, e quant/data/loaders.py é quant.data.loaders. Pastas dentro de um pacote são subpacotes e precisam do próprio __init__.py.
# A small project on disk
#
# quant-tools/
# pyproject.toml
# README.md
# quant/
# __init__.py
# pricing.py
# data/
# __init__.py
# loaders.py
# tests/
# test_pricing.py
# quant/pricing.py
def mid(bid, ask):
return (bid + ask) / 2
# anywhere else in the project
from quant.pricing import mid
import quant.data.loaders
print(mid(184.0, 185.0)) # 184.5Uma estrutura que escala
Mantenha o código importável em uma pasta de pacote com o nome do projeto e todo o resto ao lado, não dentro: testes em tests/, um README.md que explique o projeto, um pyproject.toml que o nomeie e liste as dependências, e dados ou notebooks em suas próprias pastas. Arquivos de teste se chamam test_*.py para que ferramentas como pytest os encontrem. Módulos pequenos e focados, com nomes claros (pricing.py, loaders.py), são mais fáceis de testar e reutilizar do que um utils.py longo.
# pyproject.toml (names the project and its dependencies)
#
# [project]
# name = "quant-tools"
# version = "0.1.0"
# requires-python = ">=3.11"
# dependencies = ["numpy"]
# tests/test_pricing.py: found automatically because of the name
from quant.pricing import mid
def test_mid():
assert mid(184.0, 185.0) == 184.5Importar dentro de um pacote
Dentro do pacote você pode importar pelo caminho completo a partir do topo (from quant.pricing import mid, importação absoluta) ou relativo ao módulo atual (from .pricing import mid, um ponto para o mesmo pacote, dois para o pai, importação relativa). As absolutas costumam ser mais claras. O __init__.py roda na primeira importação do pacote, então pode reexportar os nomes de que os usuários precisam (from .pricing import mid) e import quant; quant.mid(...) funciona. Rode o código de um pacote com python -m quant.data.loaders, não com python quant/data/loaders.py, para que os nomes com pontos sejam resolvidos.
# quant/__init__.py: runs on the first "import quant"
from .pricing import mid # relative: same package
__all__ = ["mid"] # what "from quant import *" would give
# quant/data/loaders.py
from quant.pricing import mid # absolute: always starts at the top
from .. import pricing # relative: two dots = the parent package
# In a terminal, from the project folder:
# python -m quant.data.loaders (runs the module as part of the package)
# pytest -q (finds tests/test_*.py)# A file path and its module name are two spellings of one thing
path = "quant/data/loaders.py"
name = path[:-3].replace("/", ".")
print(name) # quant.data.loaders
print(name.split(".")[0]) # quant (the top-level package)
# __init__.py stands for its folder
print("quant/__init__.py"[:-3].replace("/", ".")) # quant.__init__ -> the package is "quant"__init__.py (um «pacote de namespace»), mas ferramentas, executores de teste e instaladores se comportam de forma inconsistente, e imports que funcionavam na sua máquina falham em outras. Dê um __init__.py a cada pasta de pacote. O lab pede que você encontre as pastas que têm código mas não têm um.- Um pacote é uma pasta com
__init__.py;quant/data/loaders.pyé o móduloquant.data.loaders. - Mantenha o código no pacote; testes, README,
pyproject.tomle dados ao lado. - Prefira imports absolutos; rode o código de um pacote com
python -m package.module.
A seguir: ambientes virtuais e pip, para que cada projeto tenha exatamente as bibliotecas de que precisa.
Lab: o que é avaliado
- Transformar um caminho de arquivo em nome de módulo com
module_name25 pts - Listar os módulos importáveis de um projeto com
find_modules25 pts - Identificar as pastas sem __init__.py com
missing_init25 pts - Escrever a instrução de import de um módulo com
import_line25 pts