Programação Modular com Funções

Beginner

This tutorial is from open-source community. Access the source code

Introdução

Esta seção introduz o conceito de módulos e o trabalho com funções que se estendem por múltiplos arquivos.

Este é um Lab Guiado, que fornece instruções passo a passo para ajudá-lo a aprender e praticar. Siga as instruções cuidadosamente para completar cada etapa e ganhar experiência prática. Dados históricos mostram que este é um laboratório de nível iniciante com uma taxa de conclusão de 82%. Recebeu uma taxa de avaliações positivas de 100% dos estudantes.

Módulos e importação

Qualquer arquivo fonte Python é um módulo.

## foo.py
def grok(a):
    ...
def spam(b):
    ...

A declaração import carrega e executa um módulo.

## program.py
import foo

a = foo.grok(2)
b = foo.spam('Hello')
...

Namespaces (Espaços de Nomes)

Um módulo é uma coleção de valores nomeados e às vezes é dito ser um namespace (espaço de nomes). Os nomes são todas as variáveis globais e funções definidas no arquivo fonte. Após a importação, o nome do módulo é usado como um prefixo. Daí o namespace (espaço de nomes).

import foo

a = foo.grok(2)
b = foo.spam('Hello')
...

O nome do módulo está diretamente ligado ao nome do arquivo (foo -> foo.py).

Definições Globais

Tudo o que é definido no escopo global é o que preenche o namespace (espaço de nomes) do módulo. Considere dois módulos que definem a mesma variável x.

## foo.py
x = 42
def grok(a):
    ...
## bar.py
x = 37
def spam(a):
    ...

Neste caso, as definições de x referem-se a variáveis diferentes. Uma é foo.x e a outra é bar.x. Módulos diferentes podem usar os mesmos nomes e esses nomes não entrarão em conflito entre si.

Módulos são isolados.

Módulos como Ambientes

Módulos formam um ambiente envolvente para todo o código definido dentro.

## foo.py
x = 42

def grok(a):
    print(x)

Variáveis globais estão sempre ligadas ao módulo envolvente (mesmo arquivo). Cada arquivo fonte é seu próprio pequeno universo.

Execução do Módulo

Quando um módulo é importado, todas as instruções no módulo são executadas uma após a outra até o final do arquivo ser alcançado. O conteúdo do namespace (espaço de nomes) do módulo são todos os nomes globais que ainda estão definidos no final do processo de execução. Se houver instruções de script que realizam tarefas no escopo global (impressão, criação de arquivos, etc.), você as verá rodar na importação.

Declaração import as

Você pode alterar o nome de um módulo ao importá-lo:

import math as m
def rectangular(r, theta):
    x = r * m.cos(theta)
    y = r * m.sin(theta)
    return x, y

Funciona da mesma forma que uma importação normal. Ele apenas renomeia o módulo naquele arquivo.

Importação from module

Isso seleciona símbolos específicos de um módulo e os disponibiliza localmente.

from math import sin, cos

def rectangular(r, theta):
    x = r * cos(theta)
    y = r * sin(theta)
    return x, y

Isso permite que partes de um módulo sejam usadas sem ter que digitar o prefixo do módulo. É útil para nomes usados com frequência.

Comentários sobre importação

Variações na importação não alteram a forma como os módulos funcionam.

import math
## vs
import math as m
## vs
from math import cos, sin
...

Especificamente, import sempre executa o arquivo inteiro e os módulos ainda são ambientes isolados.

A declaração import module as está apenas alterando o nome localmente. A declaração from math import cos, sin ainda carrega o módulo math inteiro nos bastidores. Ela simplesmente copia os nomes cos e sin do módulo para o espaço local depois de concluído.

Carregamento de Módulos

Cada módulo carrega e executa apenas uma vez. Observação: Importações repetidas apenas retornam uma referência ao módulo carregado anteriormente.

sys.modules é um dicionário de todos os módulos carregados.

>>> import sys
>>> sys.modules.keys()
['copy_reg', '__main__', 'site', '__builtin__', 'encodings', 'encodings.encodings', 'posixpath', ...]
>>>

Atenção: Uma confusão comum surge se você repetir uma declaração import após alterar o código-fonte de um módulo. Devido ao cache de módulos sys.modules, importações repetidas sempre retornam o módulo carregado anteriormente - mesmo que uma alteração tenha sido feita. A maneira mais segura de carregar código modificado no Python é sair e reiniciar o interpretador.

Localizando Módulos

Python consulta uma lista de caminhos (sys.path) ao procurar por módulos.

>>> import sys
>>> sys.path
[
  '',
  '/usr/local/lib/python36/python36.zip',
  '/usr/local/lib/python36',
  ...
]

O diretório de trabalho atual geralmente é o primeiro.

Caminho de Busca de Módulos

Como observado, sys.path contém os caminhos de busca. Você pode ajustar manualmente se precisar.

import sys
sys.path.append('/project/foo/pyfiles')

Os caminhos também podem ser adicionados via variáveis de ambiente.

% env PYTHONPATH=/project/foo/pyfiles python3
Python 3.6.0 (default, Feb 3 2017, 05:53:21)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)]
>>> import sys
>>> sys.path
['','/project/foo/pyfiles', ...]

Como regra geral, não deve ser necessário ajustar manualmente o caminho de busca de módulos. No entanto, isso às vezes surge se você estiver tentando importar código Python que está em um local incomum ou não é facilmente acessível a partir do diretório de trabalho atual.

Para este exercício envolvendo módulos, é fundamental garantir que você esteja executando o Python em um ambiente adequado. Módulos frequentemente apresentam aos novos programadores problemas relacionados ao diretório de trabalho atual ou às configurações de caminho do Python. Para este curso, presume-se que você está escrevendo todo o seu código no diretório ~/project. Para obter os melhores resultados, você deve garantir que também está nesse diretório ao iniciar o interpretador. Caso contrário, você precisa garantir que ~/project seja adicionado a sys.path.

Exercício 3.11: Importações de Módulos

Na seção 3, criamos uma função de uso geral parse_csv() para analisar o conteúdo de arquivos de dados CSV.

Agora, vamos ver como usar essa função em outros programas. Primeiro, inicie em uma nova janela do shell. Navegue até a pasta onde você tem todos os seus arquivos. Vamos importá-los.

Inicie o modo interativo do Python.

$ python3
Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

Depois de fazer isso, tente importar alguns dos programas que você escreveu anteriormente. Você deve ver a saída deles exatamente como antes. Só para enfatizar, importar um módulo executa seu código.

>>> import bounce
... watch output ...
>>> import mortgage
... watch output ...
>>> import report
... watch output ...
>>>

Se nada disso funcionar, você provavelmente está executando o Python no diretório errado. Agora, tente importar seu módulo fileparse e obter alguma ajuda sobre ele.

>>> import fileparse
>>> help(fileparse)
... look at the output ...
>>> dir(fileparse)
... look at the output ...
>>>

Tente usar o módulo para ler alguns dados:

>>> portfolio = fileparse.parse_csv('/home/labex/project/portfolio.csv',select=['name','shares','price'], types=[str,int,float])
>>> portfolio
... look at the output ...
>>> pricelist = fileparse.parse_csv('/home/labex/project/prices.csv',types=[str,float], has_headers=False)
>>> pricelist
... look at the output ...
>>> prices = dict(pricelist)
>>> prices
... look at the output ...
>>> prices['IBM']
106.28
>>>

Tente importar uma função para que você não precise incluir o nome do módulo:

>>> from fileparse import parse_csv
>>> portfolio = parse_csv('/home/labex/project/portfolio.csv', select=['name','shares','price'], types=[str,int,float])
>>> portfolio
... look at the output ...
>>>

Exercício 3.12: Usando seu módulo de biblioteca

Na seção 2, você escreveu um programa report.py que produzia um relatório de ações como este:

      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

Pegue esse programa e modifique-o para que todo o processamento do arquivo de entrada seja feito usando funções em seu módulo fileparse. Para fazer isso, importe fileparse como um módulo e altere as funções read_portfolio() e read_prices() para usar a função parse_csv().

Use o exemplo interativo no início deste exercício como guia. Depois, você deve obter exatamente a mesma saída de antes.

Exercício 3.13: Intencionalmente deixado em branco (pular)

Exercício 3.14: Usando mais importações de biblioteca

Na seção 1, você escreveu um programa pcost.py que lia um portfólio e calculava seu custo.

>>> import pcost
>>> pcost.portfolio_cost('/home/labex/project/portfolio.csv')
44671.15
>>>

Modifique o arquivo pcost.py para que ele use a função report.read_portfolio().

Comentário

Quando você terminar este exercício, deverá ter três programas. fileparse.py que contém uma função de uso geral parse_csv(). report.py que produz um relatório agradável, mas também contém as funções read_portfolio() e read_prices(). E, finalmente, pcost.py que calcula o custo do portfólio, mas faz uso da função read_portfolio() escrita para o programa report.py.

Resumo

Parabéns! Você concluiu o laboratório de Módulos. Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.