Programação em Python (2.ª Ed. Atualizada) - (9789727229406)

Page 1


SOBRE O LIVRO

And now for something completely different... Monty Python

Esta obra aborda o uso de computadores para resolver problemas com recurso a programas escritos numa linguagem de programação de alto nível, neste caso, o Python.

A elaboração deste livro teve dois objetivos principais. Em primeiro lugar, introduzir os conceitos centrais, os blocos construtores presentes genericamente em todas as linguagens de programação. Em segundo lugar, explicitar boas práticas de programação, entendidas como os princípios que nos guiam do problema à sua solução informática.

Mas, em que tipo de problemas estamos interessados? Todos sabemos que os computadores estão presentes numa grande parte das atividades humanas. De um telemóvel ao controlo de tráfego aéreo, passando pela definição de escalas de tripulações de comboios, os computadores estão em todo o lado. De um modo mais direto, os computadores estão presentes na nossa vida diária pois fazemos uso deles para enviar e receber correio, trocar mensagens curtas, jogar, escrever documentos ou navegar na Internet. Como utilizadores comuns, apreciamos o facto de não termos de nos preocupar com a forma como os programas que usamos para essas atividades foram desenvolvidos ou como funcionam. Podemos dizer que alguém (um programador ou um grupo de programadores) tornou simples o que é complexo, escondendo os detalhes. Utilizamos esses programas através de uma interface que disponibiliza um conjunto de funções e um modo de interação, que usamos com mais ou menos à vontade.

Neste manual pretendemos iniciar o leitor1 nesta atividade conhecida por programação, uma mistura de arte e de ciência, de intuição e de princípios sólidos de projeto. Tratando-se de um texto introdutório, os problemas que nos interessam são necessariamente pequenos, mas não forçosamente simples. Caminhamos do elementar para o mais elaborado, introduzindo as características da linguagem escolhida à medida que seja necessário. Muitos dos conceitos são retomados mais do que uma vez, em contextos diversos, uma decisão pedagógica que a experiência tem validado.

OPÇÕES

Discute-se, muitas vezes, se o primeiro curso de programação se deve basear numa abordagem procedimental, orientada aos objetos ou outra. A nossa opção foi clara, privilegiando a programação procedimental. As razões são múltiplas, mas, essencialmente, a nossa decisão radica no facto de pretendermos focar-nos, em primeiro lugar, nos aspetos mais básicos da programação e fazê-lo com pequenos exemplos. Um outro ponto de controvérsia é se se deve optar entre uma abordagem em largura ou em profundidade. Se a escolha recair numa abordagem em largura, podem-se cobrir muitos tópicos, pagando o preço da superficialidade. Optando pela profundidade, estaremos na situação inversa. No nosso

1 Para efeitos de simplificação, o género masculino foi utilizado neste livro para se referir a pessoas de todos os géneros. Esta escolha não implica qualquer discriminação e reafirmamos o compromisso com a inclusão e igualdade de género.

caso, decidimos ir por um caminho híbrido. Assim, no primeiro capítulo damos uma visão geral do essencial da programação, minimizando a dependência da linguagem concreta que iremos usar. De seguida (Capítulos 2 a 8), aprofundamos esses conceitos básicos da programação no contexto de linguagem Python. Mais à frente, Capítulo 9, discutiremos um tema central da programação, a recursividade. No Capítulo 10, serão abordados aspetos mais avançados da linguagem Python, enquanto que no Capítulo 11 serão tratados aspetos relevantes de metodologia da programação. Apesar de termos optado por introduzir a programação procedimental em primeiro lugar, a programação orientada aos objetos (POO) não foi esquecida. Assim, a segunda parte do livro é dedicada a uma introdução breve da POO, para que o leitor interessado possa avançar na sua formação. Num capítulo (Capítulo 12) discutimos os aspetos de sintaxe da POO, baseando-nos no facto de, em Python, os tipos, conceito já longamente discutido nos capítulos anteriores, estarem implementados como classes. Aproveitamos ainda para falar um pouco sobre estruturas de dados e tipos de dados abstratos. O Capítulo 13 discute os conceitos essenciais da POO, isto é: encapsulamento, herança e polimorfismo. Também são introduzidas noções básicas de desenho de soluções e de diagramas de classe. Finalmente, no Capítulo 14, afloramos a questão da programação guiada por eventos e discutimos a construção de aplicações suportadas por uma interface gráfica. Programar significa resolver problemas concretos escrevendo programas. Muitos dos exemplos que aparecem ao longo do texto são exemplos clássicos que o leitor pode encontrar em qualquer outro livro sobre programação. Outros exemplos foram por nós desenhados, com o objetivo de alargar o leque do material de estudo.

PÚBLICO-ALVO

O modo como o livro está organizado faz-nos acreditar que pode ser usado por diferentes tipos de leitores. Desde logo, os capítulos sobre programação procedimental adequam-se ao ambiente académico, em disciplinas de nível inicial sobre programação. Pode ainda ser útil a disciplinas de nível intermédio de programação, que envolvam a análise e desenvolvimento de programas, estruturas de dados elementares e uma introdução à programação orientada aos objetos.

Optámos por logo no início do livro dar uma panorâmica geral da linguagem Python, deixando para os capítulos posteriores o aprofundamento dos conceitos e os aspetos complementares, mais avançados, da linguagem. Isto torna possível que o leitor, apenas com um esforço mínimo, consiga escrever os seus próprios programas. Por outro lado, foi nossa opção deliberada apresentar muitos exemplos práticos detalhados, incluindo, nos casos em que se justifica, diferentes soluções.

A conjugação de todos estes aspetos leva-nos a afirmar que o livro pode ser utilizado também de modo vantajoso por profissionais que se dediquem ao desenvolvimento de aplicações nesta linguagem de programação moderna, que um número crescente de empresas de relevo tem vindo a adotar. Para quem já programa, pode servir para tomar conhecimento com a linguagem Python, que oferece um conjunto muito significativo de vantagens, a menor das quais não é seguramente ter uma sintaxe simples que facilita a aprendizagem. A forma como a obra está organizada e escrita torna ainda este texto adaptado a situações

de autoestudo e/ou de autoaprendizagem, quer se trate de um público estudantil ou profissional.

UTILIZAÇÃO

O texto foi pensado para uma leitura sequencial, podendo, no entanto, em função dos conhecimentos prévios do leitor, ter um percurso diferente. Caso a sua utilização seja feita em ambiente académico, a nossa experiência diz-nos que pode ser usado, sem problemas, num curso introdutório de programação procedimental, de duração semestral, usando os Capítulos 1 a 8. Se os alunos tiverem já conhecimentos de programação procedimental noutra linguagem, pode-se passar muito rapidamente pelos capítulos iniciais e basear o curso nos Capítulos 9 a 14. Ao longo do documento aparecem caixas como a que se apresenta a seguir.

EXEMPLO DE CAIXA

Estas caixas contêm informação complementar.

Numa primeira leitura, estas caixas podem ser ignoradas sem perda de continuidade. Algumas destas caixas têm uma natureza informativa, enquanto outras apresentam conceitos mais avançados.

EXERCÍCIOS E MATERIAL COMPLEMENTAR

Acreditamos que se aprende a programar programando, mas também olhando para as soluções de outros programadores. Por isso, o livro apresenta muitos exemplos já resolvidos, e propõe muitos mais no final de cada capítulo. Associados aos exercícios propostos vai encontrar siglas que dão uma indicação do grau de dificuldade dos problemas. Assim, usamos a seguinte forma de notação:

■ MF para problemas triviais;

■ F para fáceis;

■ M para problemas de dificuldade média;

■ D para problemas que exigem reflexão e tempo;

■ MD para problemas de elevada complexidade.

O grau de dificuldade que indicamos não é absoluto, sendo antes relativo ao nível de conhecimentos que é suposto o leitor ter no momento em que resolve os exercícios. Igualmente, caso o problema envolva o uso de um módulo especial, o nome do mesmo será indicado, através do seguinte grafismo: Módulo nome .

Se visitar o blogue http://programacaocompython.blogspot.com, encontra muita informação adicional, incluindo muitos mais exemplos resolvidos e discussão de alguns problemas da programação e a forma de os resolver. Este blogue tem sido construído a partir da minha experiência de ensino na cadeira de Introdução à Programação e Resolução de Problemas da Universidade de Coimbra.

O leitor pode também consultar a página do livro em www.fca.pt, onde encontrará as soluções dos exercícios e exemplos de exames.

VERSÃO DE PYTHON

Ao longo dos anos, a linguagem Python foi sendo modificada. Até à versão 2.7.5, os novos desenvolvimentos eram compatíveis com as versões anteriores. Com o aparecimento da versão 3, essa compatibilidade deixou de existir, tornando difícil a atualização em tempo útil e a adaptação de módulos da linguagem necessários em muitas aplicações. Por isso, esta versão demorou algum tempo a ser adotada pela generalidade da comunidade. Hoje, esse problema está ultrapassado e, no final do livro, no Anexo A, explicamos como pode descarregar e instalar um ambiente que lhe permite ter à sua disposição o interpretador e todos os módulos de referência. Esta nossa preferência pela versão 3 radica também nas alterações francamente positivas que foram introduzidas na linguagem. Ao leitor que já programa em Python e tem as suas aplicações escritas na versão 2, aconselhamos a usar a aplicação de conversão para a versão 3 que vem com as novas distribuições.

IMAGENS

Todas as imagens deste livro são um importante suporte ilustrativo de apoio à doutrina e metodologia apresentadas pelo autor, através das quais se procura que o leitor perceba melhor os conteúdos apresentados. Para um melhor entendimento das mesmas em termos de cor, algumas imagens são acompanhadas de códigos QR que remetem o leitor para as suas versões a cores.

Como fazer a leitura de um código QR no meu iPhone, iPad ou dispositivo Android?

A maioria dos smartphones já têm leitores de QR integrados nas suas câmaras, mas alguns dispositivos mais antigos podem exigir uma aplicação especial para fazer a leitura dos códigos QR, que podem ser facilmente encontradas na Apple App Store e no Google Play. Para fazer a leitura do código QR:

1. Abra a câmara de seu smartphone ou a aplicação do leitor de código QR.

2. Aponte-o para o código QR. Independentemente do ângulo da câmara, deve conseguir receber as informações necessárias e os dados serão instantaneamente mostrados no visor.

NOTA DO AUTOR À 2.ª EDIÇÃO

Existem variadas razões que podem levar a uma nova edição de um livro. De entre estas, duas sobressaem:

1. Corrigir eventuais erros;

2. Atualizar o conteúdo face a novos desenvolvimentos.

Foi isso que fizemos. Assim o livro que tem diante de si foi expurgado dos poucos erros tipográficos que existiam, fundamentalmente erros derivados do mau alinhamento do código em algumas listagens, característica essencial na linguagem Python. Para além disso, e sobretudo, atualizámos o texto para ter em conta as novas funcionalidades das versões recentes da linguagem, em particular:

■ Passou a existir um novo modo de associar um nome ao valor de uma expressão em novos contextos (conhecido pelo operador de Walrus, Capítulo 4);

■ Foi introduzida uma nova forma de cadeias de carateres, as cadeias f, que permitem formatar saídas de modo mais elegante (Capítulo 4);

■ A existência de casamento estrutural de padrões através da construção match/case (Capítulo 5);

■ Os dicionários passaram a preservar a ordem de inserção dos elementos (Capítulo 6);

■ É agora possível anotar o código, indicando explicitamente o tipo dos objetos e usar analisadores sintáticos para verificação de correção dos programas (Capítulo 11).

O modo de desenvolver código em Python tem também sido, ao longo do tempo, enriquecido com novas ferramentas, em particular as que facilitam o desenvolvimento de aplicações em Inteligência Artificial e Aprendizagem Máquina. Embora o processo que sugerimos para instalar o interpretador se mantenha o mesmo, usando a distribuição Anaconda para desenvolvimento e partilha rápidos, o aparecimento das Júpiter Notebooks passou a ser um modo preferencial para muitos programadores, complementando o uso de ambientes integrados de desenvolvimento. Estas novas funcionalidades serão tratadas no Anexo A.

Finalmente, foram feitas algumas melhorias no estilo e clarificadas algumas partes do texto como resultado de comentários feitos pelos leitores.

Caro leitor, esperamos que esta nova versão do livro lhe proporcione excelentes momentos de leitura e de prática e continuamos disponíveis para o ajudar na sua aprendizagem, bastando para tal enviar uma mensagem para ernesto@dei.uc.pt.

Coimbra, 1 de setembro de 2024

1

INTRODUÇÃO

Qualquer começo é difícil – Tal é válido em qualquer ciência. Karl Marx

OBJETIVOS

■ Identificar as principais componentes de um computador baseado na arquitetura de Von Neumann.

■ Perceber o modo como um computador funciona.

■ Introduzir ideias básicas sobre linguagens e paradigmas de programação.

■ Introduzir, usando exemplos simples, aspetos básicos da linguagem Python.

1.1 COMPUTADORES

Um computador não é mais do que a associação de uma máquina com um conjunto de programas que permitem a construção e a execução de outros programas escritos numa dada linguagem de programação. O fim último é a resolução de problemas. O computador tanto pode estar instalado comodamente na nossa secretária, como estar embebido noutros equipamentos, desde uma máquina de lavar roupa a um controlador de uma central nuclear, passando pelo nosso telemóvel. Nas secções seguintes vamos abordar de modo muito sumário estes aspetos.

1.1.1 ARQUITETURA

O ser humano tem uma característica fundamental: é um construtor de artefactos. Ao longo dos séculos, foi inventando objetos que ampliaram as suas capacidades mecânicas (e. g., um martelo) ou os seus sentidos (e. g., um telescópio). Com o aparecimento do computador, o desafio passou a ser maior, traduzindo-se por criar uma extensão às suas capacidades mentais.1 Será esse o papel dos computadores! O debate sobre a possibilidade de identificar o ser humano com as máquinas tem contornos filosóficos e é anterior mesmo à construção do primeiro computador.2 Há quem defenda (e. g., Herbert Simon) que o ser

1 O sociólogo Daniel Bell chama ao computador uma “tecnologia intelectual”. Um relógio ou um mapa são outros exemplos.

2 Basta pensar em Leonardo Da Vinci, Charles Babbage ou Alan Turing.

humano e os computadores são apenas duas instâncias de algo mais abstrato a que chamaram sistema físico de símbolos. Outros (e. g., Rodney Brooks) falam de algo mais ousado, que designam por Robot Sapiens, um novo ser simbiótico que resulta da associação homem-máquina. Independentemente deste debate, é certo que, a um determinado nível de abstração, podemos associar a arquitetura funcional de um computador dos nosso dias a algumas das nossas capacidades. Muito superficialmente, o ser humano possui órgãos de captura de informação (e.g., os olhos), órgãos de atuação (e. g., os braços) e órgãos de processamento e de armazenamento da informação (e. g., o cérebro).

Esta decomposição, quando transposta para o computador, dá lugar à arquitetura simplificada (por exemplo, não incluímos as componentes de rede, essenciais nos computadores de hoje) de um computador, que podemos observar na Figura 1.1.

Dispositivos

Dispositivos

Do ponto de vista da sua dinâmica, um computador executa programas que foram previamente armazenados na sua memória externa (e. g., um disco duro). Esses programas são formados por instruções, que são transferidas para a memória interna (e. g., RAM) e executadas pela máquina graças à unidade central de processamento (CPU). Eventualmente, pode haver recurso à entrada de dados através de dispositivos apropriados (e. g., teclado) e visualização de resultados graças aos dispositivos de saída (e. g., o monitor). Esta é a arquitetura dita de Von Neumann, que ainda hoje é predominante.3

1.1.2 FUNCIONAMENTO

Quando recebemos o nosso novo computador, ele vem equipado com um programa fundamental, o sistema operativo (SO)4. Tanto pode ser Windows, como Linux, Mac OS, ou outro qualquer. Um sistema operativo é constituído por um núcleo mais um conjunto de programas que permitem, entre outros aspetos, uma interação amigável com o utilizador (e. g., um sistema de janelas, controlo por meio de um rato, etc.5). Os programas são

3 A entrada em cena de vários processadores, cada um com vários núcleos, veio alterar um pouco a visão simples da arquitetura convencional, embora as diferenças tenham mais que ver com o modo como o programa é executado do que com a filosofia subjacente à arquitetura descrita.

4 Se fomos nós a fabricar o computador, vamos ter de resolver a questão de instalar o SO adequado ao hardware escolhido. Pode ser uma tarefa divertida!

5 Atualmente, existem os ecrãs sensíveis ao toque que faz das mãos de novo um instrumento central na interação do ser humano com o computador.

externa
FIGURA 1.1 – ARQUITETURA DE UM COMPUTADOR

6

OBJETOS (II)

Criatividade é fazer algo novo mas que também faz aparecer uma nova categoria, um novo género, ou um novo tipo de coisa. Rich Gold

OBJETIVOS

■ Introduzir os objetos estruturados lista, dicionário e conjunto.

■ Mostrar por meio de exemplos simples a sua utilidade.

6.1 INTRODUÇÃO

Umas das práticas mais comuns em programação consiste em associar um nome a um objeto, para mais tarde podermos referenciar o objeto por esse nome. A instrução que nos permite fazer isso, já o sabemos, é a instrução de atribuição. Mas o que acontece se quisermos associar vários objetos a um único nome, sendo que, entre esses vários objetos, existe uma dada relação? Por exemplo, uma lista ordenada com os nomes e a classificação de uma prova desportiva, ou uma pequena base de dados com os nomes, as moradas, as idades, as datas de aniversário e os telefones dos nossos colegas de turma. As listas e os dicionários são dois dos objetos estruturados mais importantes em programação. Existem em Python e o sistema fornece um conjunto de operações elementares sobre objetos desse tipo. Com o seu uso, passamos a ter capacidades de armazenamento (memória) acrescidas e, por isso, podemos aspirar a resolver de modo simples problemas mais delicados. É disso que trataremos neste capítulo.

6.2 LISTAS

Suponhamos que queremos calcular a nota de uma prova em que as perguntas são de escolha múltipla. Uma questão que se nos coloca é como representar a solução correta e a resposta do aluno. Com aquilo que já sabemos, podemos pensar em usar cadeias de carateres. Daí decorre a solução apresentada na Listagem 6.1, sendo que a nota é dada pela proporção de respostas certas.

def nota(exame):

"""Calcula a nota de um exame num teste de escolha múltipla. """ solucao = 'ABBEADDB' conta = 0 for i in range(len(solucao)): if exame[i] == solucao[i]: conta = conta + 1 return conta/len(solucao)

LISTAGEM 6.1 – NOTA

Parece uma solução aceitável. Mas o que acontece se:

■ As perguntas tiverem pesos diferentes?

■ Usarmos números e não letras nas respostas?

■ Misturarmos letras e números nas respostas?

Não são questões sem solução, mas não parece claro que esta opção seja a melhor. Imaginemos outro problema. Agora pretendemos observar, ao longo de um conjunto de dias, o número de baleias que aparecem num certo local. Com base nas nossas observações, queremos poder tirar conclusões, como seja o número médio de baleias que aparecem por dia. Temos, por isso, de guardar os dados recolhidos. Podemos fazê-lo num ficheiro externo1, mas nem sempre a informação que necessitamos de guardar precisa de ser mantida permanentemente. É neste contexto que aparecem as listas. As listas são objetos (em Python tudo são objetos!), logo, têm identidade, valor e tipo. Os elementos das listas são separados por vírgulas. A marca sintática das listas são os parênteses retos (ver exemplos na Listagem 6.2).

>>> baleias = [5,4,7,3,2,3,2,6,4,2,1,7,1,3]

>>> baleias

[5, 4, 7, 3, 2, 3, 2, 6, 4, 2, 1, 7, 1, 3]

>>> id(baleias)

11797688

>>> type(baleias)

<class 'list'>

>>>

LISTAGEM 6.2 – BALEIAS

O Quadro 6.1 mostra os literais usados na construção de diferentes listas.

1 Os ficheiros serão tratados no Capítulo 7.

programa que, dada uma imagem, produza o seu negativo, isto é, uma nova imagem em que o branco passa a preto e o preto a branco.

6.8. MD Uma imagem a preto e branco pode ser guardada como uma lista de listas. Cada elemento representa uma linha da imagem. O preto é representado por 1 e o branco por 0. Por exemplo, [[0,1,0],[1,1,1],[0,1,0]] representa uma cruz. Escreva um programa que, dada uma imagem, a rode 90 graus no sentido dos ponteiros do relógio.

6.9. M Suponha que está perdido no meio de uma cidade e não tem GPS para se orientar. Pergunta a um transeunte como pode chegar ao seu destino. Como a cidade é geométrica, a resposta é fácil. Recebemos uma sequência de indicações do tipo: vira à esquerda (E), depois avança (A), depois roda à direita (D), depois avança (A), depois avança de novo (A), depois recua (R), … Usando o módulo turtle, desenvolva um programa que quando executado, faça a tartaruga simular os seus movimentos ao executar os commandos recebidos. A Figura 6.13 mostra o que acontece quando manda correr o programa geral main_tarta(). Por conveniência de visualização, marcámos o início e o fim do percurso com pontos, preto e cinza, respetivamente.

O seu programa chama-se, no código abaixo, navega

def main_tarta(n): tartaruga = turtle.Turtle() comandos = gera_comandos(n) navega(comandos, tartaruga) turtle.exitonclick()

Vai ter de implementar, para além de navega, a função gera_comandos(n), que gera uma sequência válida de comandos de tamanho n

6.10. F Crie o seguinte dicionário de linguagens de programação e respetivos autores: autor = {“php”:”Rasmus Lerdorf”,”perl”:”Larry Wall”,”tcl”:”John Ousterhout”, “awk”:”Brian Kernighan”,”java”:”James Gosling”,”parrot”:”Simon Cozens”, “python”:”GuidovanRossum”,”xpto”:”zxcv”}.

1. Acrescente um elemento ao dicionário.

2. Altere o autor do Python para “Guido van Rossum”.

FIGURA 6.13 – PASSEANDO NA CIDADE

3. Remova o elemento com chave “xpto”.

4. Quantos elementos tem o dicionário?

5. Existe uma entrada para “c++”?

6.11. F Suponha que tem uma pequena loja de vender fruta e que construiu uma pequena base de dados para fazer a gestão do stock da fruta. Para cada tipo de fruta tem a indicação da quantidade, em quilos, que tem para venda. Admita que, inicialmente, tem esses elementos em duas listas. Uma com o nome das frutas e outra com as quantidades. A partir desses dados crie o respetivo dicionário.

6.12. M Suponha que quer tornar a sua gestão da loja de fruta mais eficiente. Para tal, para cada tipo de fruta associa a informação da quantidade que comprou, do preço de compra por quilo, da quantidade que tem em stock e do preço de venda por quilo. Como guardaria esta informação? Escreva programas para cada uma destas questões:

1. Qual o lucro já obtido?

2. Qual a fruta mais cara?

6.13. M Vamos querer implementar um conversor de datas. Para tal, vamos supor que temos guardada num dicionário a relação entre números e dias da semana, dias_ semana={1:'Domingo', 2:'Segunda-feira', 3:'Terça-feira', ..., 7:'Sábado'}, e noutro os meses do ano, meses_ano = {1: 'Janeiro', 2:'Fevereiro', ..., 12: 'Dezembro'}. O formato DS/DM/M/A é um dos que é possível utilizar para representar uma data. Neste formato, DS corresponde ao valor inteiro do dia da semana (0 a 7), DM corresponde ao valor inteiro do mês e A corresponde ao ano. Faça uma função que receba os dois dicionários criados anteriormente e uma cadeia de carateres com a data no formato DS/DM/M/A. Apresente essa data por extenso.

Exemplo:

Para a data: “4/5/6/2006”

Segunda-feira, 5 de junho de 2006

6.14. M Escreva uma função que receba um dicionário –, em que cada elemento é formado pela chave, o número de identificação de uma pessoa, e o valor contém informação sobre o género, a idade, a altura e o peso –, e devolva um novo dicionário com os rácios de metabolismo basal dessas pessoas. Tenha em conta que o rácio de metabolismo basal é dado por: 66 + (6.3 * peso) + (12.9 * altura) – (6.8 * idade) no caso de ser homem, e 655 + (4.3 * peso) + (4.7 * altura) – (4.7 * idade); no caso de ser mulher.

6.15. M Escreva uma função que receba um dicionário em que cada elemento associa o número de identificação de uma pessoa (chave), a informação sobre a sua altura e o seu peso e devolva o mesmo dicionário, ao qual foi acrescentado o índice de massa corporal de cada pessoa. O índice de massa corporal de uma pessoa é calculado dividindo o seu peso pelo quadrado da sua altura.

DESENVOLVIMENTO

Um programador é também um arquiteto, um compositor ou um escritor. São pessoas criativas que começam com ideias nas suas cabeças e folhas de papel em branco. Mathias Felleisen

OBJETIVOS

■ Rever diferentes aspetos da linguagem Python.

■ Introduzir noções básicas de complexidade algorítmica.

■ Discutir diferentes maneiras de abordar o problema da correção dos programas.

■ Apresentar princípios de construção de programas.

11.1 INTRODUÇÃO

A atividade de programação está a meio caminho entre a ciência e a arte. Ciência, porque exige disciplina e rigor; arte, porque motiva para (e potencia) a atividade criativa. Para uns, um programador é como um escultor que, passo a passo, transforma uma pedra numa estátua esbelta. Para outros, o programador é alguém que brinca com blocos de diferentes formas e funcionalidades como se fossem peças de Lego®. Realmente, programar não é fácil. Temos de aplicar simultaneamente conhecimentos sobre o domínio do problema, a linguagem de programação a usar e o processo de construção da solução. Mas toda esta complexidade pode ser dominada. Neste capítulo vamos estar concentrados na forma como se pode usar este conhecimento diverso para desenvolver programas com qualidade, que pode ser medida através da verificação de um conjunto preciso de características. No final do processo de desenvolvimento de um programa queremos que estes estejam corretos, sejam de fácil leitura, fáceis de manter perante a mudança, simples e que exijam poucos recursos (espaço de memória, tempo de computação). Grande parte das vezes, estes objetivos são contraditórios entre si. Por exemplo, acontece com frequência que a legibilidade do código tenha de ser sacrificada em detrimento da eficiência. A única coisa de que não se pode abdicar é da… correção. Iremos ilustrar boas práticas de programação partindo de um ponto de vista pragmático, ou seja, através de exemplos. Começaremos por questões de análise, primeiro de complexidade e depois de correção, para de seguida nos preocuparmos com os aspetos de síntese dos programas, tendo em vista a clareza, a simplicidade e aspetos de manutenção.

11.2 COMPLEXIDADE

Todos sabemos que os computadores estão cada vez mais potentes, no número de processadores que utilizam, no número de núcleos por processador, na velocidade dos processadores, no recurso às placas gráficas, na memória externa disponível. Mas se isso é verdade, também é verdade que continuam a existir problemas que não têm solução algorítmica, ou seja, para os quais não existe um programa de computador que forneça sempre a resposta correta para todas as entradas possíveis, mesmo quando pode utilizar tempo e espaço potencialmente infinitos. Um exemplo clássico de um problema dito não computável é conhecido pelo problema da paragem de uma máquina de Turing. Uma máquina de Turing é um modelo abstrato de computador que serviu para definir o conjunto das funções computáveis, isto é, em termos práticos, serve para identificar os problemas que podem ser resolvidos por um computador. O problema referido consiste em saber se, dada uma máquina de Turing arbitrária e uma entrada, também ela arbitrária, a máquina para para essa entrada. Existem também problemas que, sendo em teoria computáveis, na prática, no entanto, não o são. Os programas que hoje existem para jogar xadrez baseados em técnicas de inteligência artificial baseiam-se na ideia de construir uma árvore de decisão em que em cada nó está uma configuração do tabuleiro num dado momento do jogo. Como em cada instante o número de jogadas alternativas é finito, em teoria, é possível conceber um programa perfeito para jogar xadrez.1 No entanto, esse programa demoraria milhares de anos a tomar a sua primeira decisão. Mesmo quando nos concentramos em problemas cuja solução algorítmica pode ser implementada através de programas que usam recursos aceitáveis e respondem em tempo razoável, importa saber qual é o melhor. Vejamos um exemplo muito simples. O problema consiste em determinar se numa lista de inteiros positivos existe, pelo menos, um deles que aparece repetido. Apresentamos de seguida duas soluções alternativas.

def duplicados_1(lista): """

Procura a existência de pelo menos um par de números duplicados numa lista de inteiros positivos. """

tamanho = len(lista) for i in range(tamanho-1): for j in range(i+1,tamanho): if lista[i] == lista[j]:

return True

return False

def duplicados_2(lista): """

Procura a existência de pelo menos um par de números duplicados (cont.)

1 Lembre-se de que na definição de computável se admite que o programa dispõe de tempo e de espaço potencialmente infinitos.

PROGRAMAÇÃO ORIENTADA AOS OBJETOS

A partir do momento em que vemos a relação entre estrutura e comportamento, começamos a perceber como os sistemas funcionam, o que os faz produzir resultados pobres e como deslocá-los para melhores padrões de comportamento.

Donella H. Meadows

OBJETIVOS

■ Reforçar os conceitos de classe, atributos e métodos.

■ Introduzir os conceitos de métodos estáticos e métodos de classe.

■ Introduzir o conceito de classe abstrata.

■ Introduzir os conceitos de encapsulamento, herança e polimorfismo.

■ Apresentar exemplos simples de classes e sua relação.

■ Introduzir noções básicas de UML.

13.1 INTRODUÇÃO

Até tempos muito recentes, a ciência moderna construiu-se com base no pensamento de cientistas e filósofos como Descartes ou Newton. Como eles, habituámo-nos a decompor problemas em subproblemas, cuja solução parcial compomos para chegar à solução do problema inicial. Como eles, procuramos as leis que regem o comportamento dos sistemas que nos rodeiam e que nos permitem compreender os diferentes fenómenos numa lógica de causa-efeito. Se morro de febre hemorrágica (o efeito), a culpa é do vírus ébola (a causa). Uma ação externa sobre um sistema provoca a sua resposta, define o seu comportamento. Esta visão reducionista e de causalidade olha para os objetos através de ações externas que os modificam ao longo de um tempo, tempo esse que flui numa única direção. O paradigma de programação que temos vindo a explorar nos capítulos anteriores, a programação procedimental, é herdeiro desta visão: decompomos o nosso problema em subproblemas mais simples e procuramos soluções computacionais para cada um deles através de abstrações (i. e., funções) que atuam sobre entidades computacionais (e. g., números, listas, ficheiros).

Hoje ganha força uma outra maneira de entender a realidade, holística, que olha para os sistemas como um todo e procura no seu interior a explicação para o que acontece. Se morro de febre hemorrágica, a culpa não é tanto do vírus ébola, mas mais dos mecanismos internos de defesa do meu organismo. Este modo de ver também está presente numa maneira diferente de programar, conhecida por programação orientada aos objetos (POO). Programar passa pela definição de objetos, em termos de estrutura e de comportamento, e pela definição do modo como os objetos interagem entre si. Já sabemos há muito que, em Python, tudo são objetos e que esses objetos têm um atributo fundamental, o seu tipo. O conhecimento do tipo determina as operações que podemos fazer com ele, ou, numa linguagem diferente, limita o comportamento dos objetos do tipo. Com naturalidade, em Python os tipos são implementados como classes. Estas características fazem de Python uma linguagem multiparadigma, em que programar orientado aos objetos pode ser feito de modo simples, elegante e eficiente.

Ao longo do tempo, este novo paradigma de programação também fez surgir princípios metodológicos importantes. Assim, antes mesmo de programar uma solução informática, por exemplo, um sistema para lidar com objetos geométricos num espaço 2D, como pontos e linhas, é necessário proceder à análise do problema, procurando identificar os diferentes objetos e suas interações. É a altura em que estamos preocupados com a clarificação de o quê. Retomando o exemplo dos objetos geométricos, é óbvio que pontos e linhas são objetos da nossa aplicação. No caso dos pontos, podemos pretender um comportamento como mover-se de uma localização para outra, saber a distância de um ponto a outro. No caso das linhas, podemos pretender que se possa alterar o seu tamanho. Podíamos pensar que, identificados os objetos (estrutura e comportamento) e as respetivas interações, a etapa seguinte seria a da programação. Mas não é assim, pois existe uma etapa intermédia, dita de desenho, na qual se procura transformar a análise numa especificação de implementação, isto é, na qual nos preocupamos com o como A descrição da solução é abstrata e pode socorrer-se de ferramentas visuais como os diagramas de classes em Unified Modeling Language (UML). A Figura 13.1 mostra um exemplo de diagrama com duas classes, Estudante e Pessoa. Mostra-nos que um estudante é um caso particular de pessoa ou, o que é o mesmo, pessoa é uma generalização de estudante.

Generalização

Pessoa

Estudante

FIGURA 13.1 – UM DIAGRAMA DE CLASSES BÁSICO

Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.