quinta-feira, 29 de outubro de 2009

Entradas e Saídas

Um programa, qualquer programa, é um manipulador de objectos. Ao programador compete tomar várias decisões. A primeira, é determinar quais são e como vão ser comunicados ao programa, os objectos a manipular e, ainda, como é que este devolve o resultado. A segunda, claro está, é saber como transforma os dados no resultado.


Suponhamos o seguinte exemplo: desenvolva um programa que, dado o comprimento dos dois lados de um triângulo rectângulo que formam um ângulo de 90 graus (os catetos), determina o comprimento do terceiro lado, a hipotenusa. Neste exemplo, os objectos de entrada (os dados) são o comprimento dos dois lados e, o objecto à saída (o resultado) é o comprimento da hipotenusa. Em relação à primeira questão acima referida, em geral, nós temos três possibilidades para introduzir os dados e outras três para os por cá fora. A figura ilustra a situação.



Para a entrada temos as seguintes três hipóteses:


  • através dos parâmetros de entrada: def hipotenusa(lado_1,lado_2): ...

  • recorrendo à instrução de entrada no interior do programa: lado_1=input('lado 1 sff: ')

  • ler, a partir do interior do programa, de um ficheiro externo:fich=open('lados.txt','r')



Para a saída, mais três hipóteses:


  • através da instrução de fim do programa: return h

  • recorrendo à instrução de impressão para o canal de saída: print h

  • escrever, a partir do interior do programa, num ficheiro externo, que foi aberto para escrita:fich.write(h)



Todas estas possibilidades de entrada saída, podem ser combinadas entre si! A decisão sobre o que escolher depende da natureza do problema e dos dados, e do local onde estes podem ser obtidos. Esqueçamos por agora os ficheiros (a tratar em breve nas aulas teoricas), e concentre-mo-nos nas outras quatro alternativas. Do lado da entrada a opção deve ser guiada pela existência ou não de interactividade entre o programa e o utilizador. Do lado da saída, a decisão depende de saber quem vai precisar do resultado. Se tivermos liberdade nestas matérias a regra a seguir é a de optar pelo que caso mais geral e menos dependente do utilizador. Se o meu programa puder obter os dados de outro programa e se imprimir o resultado não for o objectivo, então o par parâmetros de entrada / return deve ser a nossa opção.

Em função do que foi dito o seu programa terá a seguinte assinatura:


def hipotenusa(lado_1,lado_2):
--- código aqui
return hipo


Passemos agora à segunda questão que foi mencionada no início: como transformar os dados no resultado. E isto é o domínio privilegiado da área de resolução de problemas. Neste caso simples é fácil identificar os dados, a incógnita e o modo como se relacionam através do Teorema de Pitágoras: o quadrado da hipotenusa é igual à soma do quadrado dos catetos.



h^2 = \sqrt{l_1^2 + l_2^2)



Logo a nossa solução é baseada nesse pressuposto. Mas antes de apresentarmos a solução pensemos mais um pouco na frase raiz quadrada da soma do quadrado dos catetos. Ela diz-nos que precisamos de operações auxiliares. Em programação, isso leva normalmente ao uso de operações pré-definidas na linguagem ou à utilização (ou definição) de programas auxiliares. Posto tudo isto, aqui vai então a nossa solução:


import math

def quadrado(n):
return n**2

def soma(n1,n2):
n = n1 + n2
return n

def hipotenusa(x,y):
hipo = math.sqrt(soma(quadrado(x), quadrado(y)))
return hipo

def main():
lado_1 = input('lado 1: ')
lado_2 = input('lado 2: ')
print 'Hipotenusa: ',hipotenusa(lado_1, lado_2)

if __name__ =='__main__':
main()


Que comentários breves se nos oferece fazer? As definições explícitas para as operações quadrado e soma podem ser reutilizadas noutros contextos. No caso de devolverem o resultado por impressão e não por return, essa possibilidade seria perdida! Usamos o método pré-definido sqrt do módulo math, o que obriga à sua importação. Finalmente, construímos um programa principal, de nome main que isola e faz de interface com o potencial utilizador. É aqui que optamos, neste caso, por introduzir os dados e imprimir o resultado. Estamos assim perante um modelo de programação geral!

O que devemos evitar?


import math

def hipotenusa():
lado_1 = input('lado 1: ')
lado_2 = input('lado 2: ')
print math.sqrt(lado_1 **2 + lado_2 **2)

hipotenusa()

Nesta solução temos interactividade na entrada dos dados. Isso impede o nosso programa de receber as suas entradas de outro programa. Ao usarmos a instrução de impressão também não podemos auxiliar outros programas que precisam deste cálculo. Perdemos ainda modularidade ao não usar programas independentes para o cálculo da soma e do quadrado. Mas não ganhamos nada? Sim , ganhamos! Associámos um nome a três instruções. Assim, cada vez que for preciso basta usar o nome e não precisamos escrever as ditas instruções. Atenção no entanto. Isto é apenas um exemplo ilustrativo do conceito. Cada problema é um caso e deve ser ponderado sempre a melhor maneira de introduzir e devolver os objectos.

O que não devemos usar! De todo!


import math

lado_1 = input('lado 1: ')
lado_2 = input('lado 2: ')
print math.sqrt(lado_1 **2 + lado_2 **2)


O que ganhamos nesta abordagem? Nada.

Sem comentários:

Enviar um comentário