Reconsiderar Decisão de Design

Beginner

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

Introdução

Nesta seção, reconsideramos uma decisão de design tomada anteriormente.

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

Nomes de Arquivos versus Iteráveis

Compare estes dois programas que retornam a mesma saída.

## Provide a filename
def read_data(filename):
    records = []
    with open(filename) as f:
        for line in f:
            ...
            records.append(r)
    return records

d = read_data('file.csv')
## Provide lines
def read_data(lines):
    records = []
    for line in lines:
        ...
        records.append(r)
    return records

with open('file.csv') as f:
    d = read_data(f)
  • Qual dessas funções você prefere? Por quê?
  • Qual dessas funções é mais flexível?

Ideia Profunda: "Duck Typing"

Duck Typing é um conceito de programação de computadores para determinar se um objeto pode ser usado para um propósito específico. É uma aplicação do teste do pato.

Se parece com um pato, nada como um pato e grasna como um pato, então provavelmente é um pato.

Na segunda versão de read_data() acima, a função espera qualquer objeto iterável. Não apenas as linhas de um arquivo.

def read_data(lines):
    records = []
    for line in lines:
        ...
        records.append(r)
    return records

Isso significa que podemos usá-la com outras linhas.

## A CSV file
lines = open('data.csv')
data = read_data(lines)

## A zipped file
lines = gzip.open('data.csv.gz','rt')
data = read_data(lines)

## The Standard Input
lines = sys.stdin
data = read_data(lines)

## A list of strings
lines = ['ACME,50,91.1','IBM,75,123.45', ... ]
data = read_data(lines)

Há considerável flexibilidade com este design.

Pergunta: Devemos abraçar ou lutar contra essa flexibilidade?

Melhores Práticas de Design de Bibliotecas

Bibliotecas de código são frequentemente melhor servidas ao abraçar a flexibilidade. Não restrinja suas opções. Com grande flexibilidade vem grande poder.

Exercício 3.17: De nomes de arquivos para objetos semelhantes a arquivos

Você agora criou um arquivo fileparse.py que contém uma função parse_csv(). A função funcionava assim:

>>> import fileparse
>>> portfolio = fileparse.parse_csv('portfolio.csv', types=[str,int,float])
>>>

No momento, a função espera receber um nome de arquivo. No entanto, você pode tornar o código mais flexível. Modifique a função para que ela funcione com qualquer objeto semelhante a arquivo/iterável. Por exemplo:

>>> import fileparse
>>> import gzip
>>> with gzip.open('portfolio.csv.gz', 'rt') as file:
...      port = fileparse.parse_csv(file, types=[str,int,float])
...
>>> lines = ['name,shares,price', 'AA,100,34.23', 'IBM,50,91.1', 'HPE,75,45.1']
>>> port = fileparse.parse_csv(lines, types=[str,int,float])
>>>

Neste novo código, o que acontece se você passar um nome de arquivo como antes?

>>> port = fileparse.parse_csv('portfolio.csv', types=[str,int,float])
>>> port
... look at output (it should be crazy) ...
>>>

Sim, você precisará ter cuidado. Você poderia adicionar uma verificação de segurança para evitar isso?

Exercício 3.18: Corrigindo funções existentes

Corrija as funções read_portfolio() e read_prices() no arquivo report.py para que funcionem com a versão modificada de parse_csv(). Isso deve envolver apenas uma pequena modificação. Depois, seus programas report.py e pcost.py devem funcionar da mesma forma que sempre funcionaram.

Resumo

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