Introdução
Ao escrever um programa maior, você realmente não quer organizá-lo como uma grande coleção de arquivos independentes no nível superior. Esta seção introduz o conceito de um pacote (package).
This tutorial is from open-source community. Access the source code
Ao escrever um programa maior, você realmente não quer organizá-lo como uma grande coleção de arquivos independentes no nível superior. Esta seção introduz o conceito de um pacote (package).
Qualquer arquivo fonte Python é um módulo.
## foo.py
def grok(a):
...
def spam(b):
...
Uma declaração import carrega e executa um módulo.
## program.py
import foo
a = foo.grok(2)
b = foo.spam('Hello')
...
Para coleções maiores de código, é comum organizar módulos em um pacote.
## De
pcost.py
report.py
fileparse.py
## Para
porty/
__init__.py
pcost.py
report.py
fileparse.py
Você escolhe um nome e cria um diretório de nível superior. porty no exemplo acima (claramente, escolher este nome é o primeiro passo mais importante).
Adicione um arquivo __init__.py ao diretório. Ele pode estar vazio.
Coloque seus arquivos fonte no diretório.
Um pacote serve como um namespace para imports.
Isso significa que agora existem imports de múltiplos níveis.
import porty.report
port = porty.report.read_portfolio('portfolio.csv')
Existem outras variações de declarações de import.
from porty import report
port = report.read_portfolio('portfolio.csv')
from porty.report import read_portfolio
port = read_portfolio('portfolio.csv')
Existem dois problemas principais com esta abordagem.
Então, basicamente, tudo quebra. Mas, fora isso, funciona.
Imports entre arquivos no mesmo pacote agora devem incluir o nome do pacote no import. Lembre-se da estrutura.
porty/
__init__.py
pcost.py
report.py
fileparse.py
Exemplo de import modificado.
from porty import fileparse
def read_portfolio(filename):
return fileparse.parse_csv(...)
Todos os imports são absolutos, não relativos.
import fileparse ## QUEBRA. fileparse não encontrado
...
Em vez de usar diretamente o nome do pacote, você pode usar . para se referir ao pacote atual.
from . import fileparse
def read_portfolio(filename):
return fileparse.parse_csv(...)
Sintaxe:
from . import modname
Isso facilita a renomeação do pacote.
Executar um submódulo de pacote como um script principal quebra.
$ python porty/pcost.py ## QUEBRA
...
Razão: Você está executando Python em um único arquivo e Python não vê o restante da estrutura do pacote corretamente (sys.path está errado).
Todos os imports quebram. Para corrigir isso, você precisa executar seu programa de uma maneira diferente, usando a opção -m.
$ python -m porty.pcost ## FUNCIONA
...
__init__.pyO objetivo principal desses arquivos é unir módulos.
Exemplo: consolidando funções
## porty/__init__.py
from .pcost import portfolio_cost
from .report import portfolio_report
Isso faz com que os nomes apareçam no nível superior (top-level) ao importar.
from porty import portfolio_cost
portfolio_cost('portfolio.csv')
Em vez de usar os imports de múltiplos níveis.
from porty import pcost
pcost.portfolio_cost('portfolio.csv')
Como observado, agora você precisa usar -m package.module para executar scripts dentro do seu pacote.
$ python3 -m porty.pcost portfolio.csv
Há outra alternativa: Escrever um novo script de nível superior (top-level).
#!/usr/bin/env python3
## pcost.py
import porty.pcost
import sys
porty.pcost.main(sys.argv)
Este script reside fora do pacote. Por exemplo, observando a estrutura de diretórios:
pcost.py ## script de nível superior (top-level-script)
porty/ ## diretório do pacote
__init__.py
pcost.py
...
A organização do código e a estrutura de arquivos são fundamentais para a manutenibilidade de uma aplicação.
Não existe uma abordagem "tamanho único" para Python. No entanto, uma estrutura que funciona para muitos problemas é algo como isto.
porty-app/
README.txt
script.py ## SCRIPT
porty/
## CÓDIGO DA BIBLIOTECA
__init__.py
pcost.py
report.py
fileparse.py
O nível superior porty-app é um contêiner para todo o resto -- documentação, scripts de nível superior, exemplos, etc.
Novamente, os scripts de nível superior (se houver) precisam existir fora do pacote de código. Um nível acima.
#!/usr/bin/env python3
## porty-app/script.py
import sys
import porty
porty.report.main(sys.argv)
Neste ponto, você tem um diretório com vários programas:
pcost.py ## calcula o custo do portfólio
report.py ## Cria um relatório
ticker.py ## Produz um ticker de ações em tempo real
Há uma variedade de módulos de suporte com outras funcionalidades:
stock.py ## Classe Stock
portfolio.py ## Classe Portfolio
fileparse.py ## Parsing CSV
tableformat.py ## Tabelas formatadas
follow.py ## Seguir um arquivo de log
typedproperty.py ## Propriedades de classe tipadas
Neste exercício, vamos limpar o código e colocá-lo em um pacote comum.
Crie um diretório chamado porty/ e coloque todos os arquivos Python acima nele. Adicionalmente, crie um arquivo __init__.py vazio e coloque-o no diretório. Você deve ter um diretório de arquivos como este:
porty/
__init__.py
fileparse.py
follow.py
pcost.py
portfolio.py
report.py
stock.py
tableformat.py
ticker.py
typedproperty.py
Remova o arquivo __pycache__ que está no seu diretório. Ele contém módulos Python pré-compilados de antes. Queremos começar do zero.
Tente importar alguns dos módulos do pacote:
>>> import porty.report
>>> import porty.pcost
>>> import porty.ticker
Se essas importações falharem, vá para o arquivo apropriado e corrija as importações do módulo para incluir uma importação relativa ao pacote. Por exemplo, uma instrução como import fileparse pode mudar para o seguinte:
## report.py
from . import fileparse
...
Se você tiver uma instrução como from fileparse import parse_csv, altere o código para o seguinte:
## report.py
from .fileparse import parse_csv
...
Colocar todo o seu código em um "pacote" (package) geralmente não é suficiente para uma aplicação. Às vezes, existem arquivos de suporte, documentação, scripts e outras coisas. Esses arquivos precisam existir FORA do diretório porty/ que você criou acima.
Crie um novo diretório chamado porty-app. Mova o diretório porty que você criou no Exercício 9.1 para dentro desse diretório. Copie os arquivos de teste portfolio.csv e prices.csv para este diretório. Adicionalmente, crie um arquivo README.txt com algumas informações sobre você. Seu código agora deve ser organizado da seguinte forma:
porty-app/
portfolio.csv
prices.csv
README.txt
porty/
__init__.py
fileparse.py
follow.py
pcost.py
portfolio.py
report.py
stock.py
tableformat.py
ticker.py
typedproperty.py
Para executar seu código, você precisa ter certeza de que está trabalhando no diretório de nível superior porty-app/. Por exemplo, no terminal:
$ cd porty-app
$ python3
>>> import porty.report
>>>
Tente executar alguns de seus scripts anteriores como um programa principal:
$ cd porty-app
$ python3 -m porty.report portfolio.csv prices.csv txt
Name Shares Price Change
---------- ---------- ---------- ----------
AA 100 9.22 -22.98
IBM 50 106.28 15.18
CAT 150 35.46 -47.98
MSFT 200 20.89 -30.34
GE 95 13.48 -26.89
MSFT 50 20.89 -44.21
IBM 100 106.28 35.84
$
Usar o comando python -m é frequentemente um pouco estranho. Você pode querer escrever um script de nível superior que simplesmente lida com as peculiaridades dos pacotes. Crie um script print-report.py que produza o relatório acima:
#!/usr/bin/env python3
## print-report.py
import sys
from porty.report import main
main(sys.argv)
Coloque este script no diretório de nível superior porty-app/. Certifique-se de que você pode executá-lo nesse local:
$ cd porty-app
$ python3 print-report.py portfolio.csv prices.csv txt
Name Shares Price Change
---------- ---------- ---------- ----------
AA 100 9.22 -22.98
IBM 50 106.28 15.18
CAT 150 35.46 -47.98
MSFT 200 20.89 -30.34
GE 95 13.48 -26.89
MSFT 50 20.89 -44.21
IBM 100 106.28 35.84
$
Seu código final agora deve ser estruturado mais ou menos assim:
porty-app/
portfolio.csv
prices.csv
print-report.py
README.txt
porty/
__init__.py
fileparse.py
follow.py
pcost.py
portfolio.py
report.py
stock.py
tableformat.py
ticker.py
typedproperty.py
Parabéns! Você concluiu o laboratório de Pacotes (Packages). Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.