Organizando Programas Maiores com Funções

Intermediate

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

Introdução

À medida que seus programas começam a ficar maiores, você desejará se organizar. Esta seção introduz brevemente funções e módulos de biblioteca. O tratamento de erros com exceções também é introduzido.

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 intermediário com uma taxa de conclusão de 74%. Recebeu uma taxa de avaliações positivas de 100% dos estudantes.

Funções Personalizadas

Use funções para código que você deseja reutilizar. Aqui está uma definição de função:

def sumcount(n):
    '''
    Retorna a soma dos primeiros n inteiros
    '''
    total = 0
    while n > 0:
        total += n
        n -= 1
    return total

Para chamar uma função:

a = sumcount(100)

Uma função é uma série de instruções que executam alguma tarefa e retornam um resultado. A palavra-chave return é necessária para especificar explicitamente o valor de retorno da função.

Funções de Biblioteca

Python vem com uma grande biblioteca padrão. Módulos de biblioteca são acessados usando import. Por exemplo:

import math
x = math.sqrt(10)

import urllib.request
u = urllib.request.urlopen('http://www.python.org/')
data = u.read()

Cobriremos bibliotecas e módulos com mais detalhes mais tarde.

Erros e Exceções

Funções relatam erros como exceções. Uma exceção faz com que uma função seja abortada e pode fazer com que todo o seu programa pare se não for tratada.

Tente isso no seu REPL Python.

>>> int('N/A')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'N/A'
>>>

Para fins de depuração, a mensagem descreve o que aconteceu, onde o erro ocorreu e um traceback mostrando as outras chamadas de função que levaram à falha.

Capturando e Tratando Exceções

Exceções podem ser capturadas e tratadas.

Para capturar, use a instrução try - except.

for line in file:
    fields = line.split(',')
    try:
        shares = int(fields[1])
    except ValueError:
        print("Couldn't parse", line)
    ...

O nome ValueError deve corresponder ao tipo de erro que você está tentando capturar.

É frequentemente difícil saber exatamente que tipos de erros podem ocorrer com antecedência, dependendo da operação que está sendo realizada. Para o bem ou para o mal, o tratamento de exceções geralmente é adicionado depois que um programa travou inesperadamente (ou seja, "ah, esquecemos de capturar esse erro. Devemos tratá-lo!").

Levantando Exceções

Para levantar uma exceção, use a instrução raise.

raise RuntimeError('What a kerfuffle')

Isso fará com que o programa seja abortado com um traceback de exceção. A menos que seja capturado por um bloco try-except.

% python3 foo.py
Traceback (most recent call last):
  File "foo.py", line 21, in <module>
    raise RuntimeError("What a kerfuffle")
RuntimeError: What a kerfuffle

Exercício 1.29: Definindo uma função

Tente definir uma função simples:

>>> def greeting(name):
        'Issues a greeting'
        print('Hello', name)

>>> greeting('Guido')
Hello Guido
>>> greeting('Paula')
Hello Paula
>>>

Se a primeira instrução de uma função for uma string, ela serve como documentação. Tente digitar um comando como help(greeting) para vê-la exibida.

Exercício 1.30: Transformando um script em uma função

Pegue o código que você escreveu para o programa pcost.py no Exercício 1.27 e transforme-o em uma função portfolio_cost(filename). Esta função recebe um nome de arquivo como entrada, lê os dados do portfólio nesse arquivo e retorna o custo total do portfólio como um float.

Para usar sua função, altere seu programa para que ele se pareça com isto:

## pcost.py
def portfolio_cost(filename):
    """
    Computes the total cost (shares*price) of a portfolio file
    """
    total_cost = 0.0

    with open(filename, "rt") as f:
        rows = f.readlines()
        headers = rows[0].strip().split(",")
        for row in rows[1:]:
            row_data = row.strip().split(",")
            nshares = int(row_data[1])
            price = float(row_data[2])
            total_cost += nshares * price

    return total_cost


import sys

if len(sys.argv) == 2:
    filename = sys.argv[1]
else:
    filename = input("Enter a filename:")

cost = portfolio_cost(filename)
print("Total cost:", cost)

Quando você executar seu programa, deverá ver a mesma saída de antes. Depois de executar seu programa, você também pode chamar sua função interativamente digitando isto:

$ python3 -i pcost.py

Isso permitirá que você chame sua função do modo interativo.

>>> portfolio_cost('portfolio.csv')
44671.15
>>>

Poder experimentar seu código interativamente é útil para testes e depuração.

Exercício 1.31: Tratamento de erros

O que acontece se você tentar sua função em um arquivo com alguns campos ausentes?

>>> portfolio_cost('missing.csv')
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "pcost.py", line 11, in portfolio_cost
    nshares    = int(fields[1])
ValueError: invalid literal for int() with base 10: ''
>>>

Neste ponto, você se depara com uma decisão. Para fazer o programa funcionar, você pode ou sanitizar o arquivo de entrada original, eliminando as linhas ruins, ou pode modificar seu código para lidar com as linhas ruins de alguma forma.

Modifique o programa pcost.py para capturar a exceção, imprimir uma mensagem de aviso e continuar processando o restante do arquivo.

Exercício 1.32: Usando uma função de biblioteca

Python vem com uma grande biblioteca padrão de funções úteis. Uma biblioteca que pode ser útil aqui é o módulo csv. Você deve usá-lo sempre que precisar trabalhar com arquivos de dados CSV. Aqui está um exemplo de como ele funciona:

>>> import csv
>>> f = open('portfolio.csv')
>>> rows = csv.reader(f)
>>> headers = next(rows)
>>> headers
['name', 'shares', 'price']
>>> for row in rows:
        print(row)

['AA', '100', '32.20']
['IBM', '50', '91.10']
['CAT', '150', '83.44']
['MSFT', '200', '51.23']
['GE', '95', '40.37']
['MSFT', '50', '65.10']
['IBM', '100', '70.44']
>>> f.close()
>>>

Uma coisa boa sobre o módulo csv é que ele lida com uma variedade de detalhes de baixo nível, como citação e divisão adequada por vírgulas. Na saída acima, você notará que ele removeu as aspas duplas dos nomes na primeira coluna.

Modifique seu programa pcost.py para que ele use o módulo csv para análise (parsing) e tente executar os exemplos anteriores.

Exercício 1.33: Lendo da linha de comando

No programa pcost.py, o nome do arquivo de entrada foi codificado no código:

## pcost.py

def portfolio_cost(filename):
    ...
    ## Your code here
    ...

cost = portfolio_cost('portfolio.csv')
print('Total cost:', cost)

Isso é bom para aprendizado e testes, mas em um programa real você provavelmente não faria isso.

Em vez disso, você pode passar o nome do arquivo como um argumento para um script. Tente alterar a parte inferior do programa da seguinte forma:

## pcost_1.33.py

import csv


def portfolio_cost(filename):
    """
    Computes the total cost (shares*price) of a portfolio file
    """
    total_cost = 0.0

    with open(filename, "rt") as f:
        rows = csv.reader(f)
        headers = next(rows)  ## Skip header row
        for row in rows:
            if len(row) < 3:
                print("Skipping invalid row:", row)
                continue
            try:
                nshares = int(row[1])
                price = float(row[2])
                total_cost += nshares * price
            except (IndexError, ValueError):
                print("Skipping invalid row:", row)

    return total_cost

import sys


if len(sys.argv) == 2:
    filename = sys.argv[1]
else:
    filename = 'portfolio.csv'

cost = portfolio_cost(filename)
print('Total cost:', cost)

sys.argv é uma lista que contém os argumentos passados na linha de comando (se houver).

Para executar seu programa, você precisará executar o Python a partir do terminal.

Por exemplo, no bash no Unix:

$ python3 pcost.py portfolio.csv
Total cost: 44671.15
bash %

Resumo

Parabéns! Você concluiu o laboratório de Funções. Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.