Prática de Escrita de Scripts Python

Intermediate

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

Introdução

Nesta parte, analisamos mais de perto a prática de escrever scripts Python.

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 56%. Recebeu uma taxa de avaliações positivas de 100% dos estudantes.

O que é um Script?

Um script é um programa que executa uma série de instruções e para.

## program.py

statement1
statement2
statement3
...

Temos escrito principalmente scripts até este ponto.

Um Problema

Se você escrever um script útil, ele crescerá em recursos e funcionalidades. Você pode querer aplicá-lo a outros problemas relacionados. Com o tempo, ele pode se tornar uma aplicação crítica. E se você não tomar cuidado, ele pode se transformar em uma grande bagunça emaranhada. Então, vamos nos organizar.

Definindo Coisas

Nomes devem sempre ser definidos antes de serem usados posteriormente.

def square(x):
    return x*x

a = 42
b = a + 2     ## Requires that `a` is defined

z = square(b) ## Requires `square` and `b` to be defined

A ordem é importante. Quase sempre você coloca as definições de variáveis e funções perto do topo.

Definindo Funções

É uma boa ideia colocar todo o código relacionado a uma única tarefa em um só lugar. Use uma função.

def read_prices(filename):
    prices = {}
    with open(filename) as f:
        f_csv = csv.reader(f)
        for row in f_csv:
            prices[row[0]] = float(row[1])
    return prices

Uma função também simplifica operações repetidas.

oldprices = read_prices('oldprices.csv')
newprices = read_prices('newprices.csv')

O que é uma Função?

Uma função é uma sequência de instruções com um nome.

def funcname(args):
  statement
  statement
  ...
  return result

Qualquer instrução Python pode ser usada dentro.

def foo():
    import math
    print(math.sqrt(2))
    help(math)

Não existem instruções especiais em Python (o que torna fácil de lembrar).

Definição de Função

Funções podem ser definidas em qualquer ordem.

def foo(x):
    bar(x)

def bar(x):
    statements

## OR
def bar(x):
    statements

def foo(x):
    bar(x)

As funções só devem ser definidas antes de serem realmente usadas (ou chamadas) durante a execução do programa.

foo(3)        ## foo must be defined already

Estilisticamente, é provavelmente mais comum ver funções definidas de forma bottom-up (de baixo para cima).

Estilo Bottom-up

Funções são tratadas como blocos de construção. Os blocos menores/mais simples vêm primeiro.

## myprogram.py
def foo(x):
    ...

def bar(x):
    ...
    foo(x)          ## Defined above
    ...

def spam(x):
    ...
    bar(x)          ## Defined above
    ...

spam(42)            ## Code that uses the functions appears at the end

Funções posteriores constroem-se sobre funções anteriores. Novamente, este é apenas um ponto de estilo. A única coisa que importa no programa acima é que a chamada para spam(42) venha por último.

Design de Funções

Idealmente, as funções devem ser uma caixa preta (black box). Elas devem operar apenas nos inputs passados e evitar variáveis globais e efeitos colaterais misteriosos. Seus principais objetivos: Modularidade e Previsibilidade.

Doc Strings (Strings de Documentação)

É uma boa prática incluir documentação na forma de uma doc-string (string de documentação). Doc-strings são strings escritas imediatamente após o nome da função. Elas alimentam help(), IDEs e outras ferramentas.

def read_prices(filename):
    '''
    Read prices from a CSV file of name,price data
    '''
    prices = {}
    with open(filename) as f:
        f_csv = csv.reader(f)
        for row in f_csv:
            prices[row[0]] = float(row[1])
    return prices

Uma boa prática para doc strings é escrever um resumo curto de uma frase sobre o que a função faz. Se mais informações forem necessárias, inclua um exemplo curto de uso, juntamente com uma descrição mais detalhada dos argumentos.

Anotações de Tipo (Type Annotations)

Você também pode adicionar dicas de tipo opcionais às definições de função.

def read_prices(filename: str) -> dict:
    '''
    Read prices from a CSV file of name,price data
    '''
    prices = {}
    with open(filename) as f:
        f_csv = csv.reader(f)
        for row in f_csv:
            prices[row[0]] = float(row[1])
    return prices

As dicas não fazem nada operacionalmente. Elas são puramente informativas. No entanto, podem ser usadas por IDEs, verificadores de código e outras ferramentas para fazer mais.

Na seção 2, você escreveu um programa chamado report.py que imprimia um relatório mostrando o desempenho de uma carteira de ações. Este programa consistia em algumas funções. Por exemplo:

## report.py
import csv

def read_portfolio(filename):
    '''
    Read a stock portfolio file into a list of dictionaries with keys
    name, shares, and price.
    '''
    portfolio = []
    with open(filename) as f:
        rows = csv.reader(f)
        headers = next(rows)

        for row in rows:
            record = dict(zip(headers, row))
            stock = {
                'name' : record['name'],
                'shares' : int(record['shares']),
                'price' : float(record['price'])
            }
            portfolio.append(stock)
    return portfolio
...

No entanto, também havia partes do programa que apenas executavam uma série de cálculos roteirizados. Este código aparecia perto do final do programa. Por exemplo:

...

## Output the report

headers = ('Name', 'Shares', 'Price', 'Change')
print('%10s %10s %10s %10s'  % headers)
print(('-' * 10 + ' ') * len(headers))
for row in report:
    print('%10s %10d %10.2f %10.2f' % row)
...

Neste exercício, vamos pegar este programa e organizá-lo um pouco mais fortemente em torno do uso de funções.

Exercício 3.1: Estruturando um programa como uma coleção de funções

Modifique seu programa report.py para que todas as operações principais, incluindo cálculos e saída, sejam realizadas por uma coleção de funções. Especificamente:

  • Crie uma função print_report(report) que imprima o relatório.
  • Mude a última parte do programa para que não seja nada mais do que uma série de chamadas de função e nenhuma outra computação.

Exercício 3.2: Criando uma função de nível superior para a execução do programa

Pegue a última parte do seu programa e empacote-a em uma única função portfolio_report(portfolio_filename, prices_filename). Faça com que a função funcione de modo que a seguinte chamada de função crie o relatório como antes:

portfolio_report('/home/labex/project/portfolio.csv', '/home/labex/project/prices.csv')

Nesta versão final, seu programa não será nada mais do que uma série de definições de função, seguida por uma única chamada de função para portfolio_report() no final (que executa todas as etapas envolvidas no programa).

Ao transformar seu programa em uma única função, torna-se fácil executá-lo com diferentes entradas. Por exemplo, experimente estas instruções interativamente após executar seu programa:

>>> portfolio_report('/home/labex/project/portfolio2.csv', '/home/labex/project/prices.csv')
... veja a saída ...
>>> files = ['/home/labex/project/portfolio.csv', '/home/labex/project/portfolio2.csv']
>>> for name in files:
        print(f'{name:-^43s}')
        portfolio_report(name, '/home/labex/project/prices.csv')
        print()

... veja a saída ...
>>>

Comentário

Python torna muito fácil escrever código de script relativamente não estruturado, onde você apenas tem um arquivo com uma sequência de instruções nele. Em termos gerais, é quase sempre melhor utilizar funções sempre que possível. Em algum momento, esse script vai crescer e você desejará ter um pouco mais de organização. Além disso, um fato pouco conhecido é que o Python roda um pouco mais rápido se você usar funções.

Resumo

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