0% acharam este documento útil (0 voto)
5 visualizações

Intro Duca o Program a Cao Python

O documento é um material didático sobre Introdução à Programação com Python, destinado a estudantes da disciplina INF 100 da UFV. Ele abrange conceitos fundamentais de programação, algoritmos, variáveis, operadores, comandos de entrada e saída, estruturas condicionais e repetitivas, arranjos e funções. O texto visa fornecer um suporte detalhado para o aprendizado da linguagem Python, enfatizando a importância da prática e do raciocínio lógico na programação.

Enviado por

Amanda Pessanha
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
5 visualizações

Intro Duca o Program a Cao Python

O documento é um material didático sobre Introdução à Programação com Python, destinado a estudantes da disciplina INF 100 da UFV. Ele abrange conceitos fundamentais de programação, algoritmos, variáveis, operadores, comandos de entrada e saída, estruturas condicionais e repetitivas, arranjos e funções. O texto visa fornecer um suporte detalhado para o aprendizado da linguagem Python, enfatizando a importância da prática e do raciocínio lógico na programação.

Enviado por

Amanda Pessanha
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 196

Introdução à Programação com Python

(Versão 2.0 - Revisada para uso no Semestre 2024-1. O texto não passou por nenhuma
revisão profissional.
Assim, correções serão muito bem vindas!!!

Envie as correções/sugestões para: goulart@ufv.br

Meus agradecimentos antecipados!!!)

Carlos de Castro Goulart


Departamento de Informática
Universidade Federal de Viçosa
2023
Introdução à Programação com Python

Licença de uso: este texto pode ser copiado e distribuído livremente para uso não
comercial, mantendo sempre a informação sobre a autoria.

1
Introdução à Programação com Python

Introdução à Programação com Python 0

Prefácio 4

Capítulo 1 - Introdução 6
1.1. Motivação - por que aprender programação? 6
1.2. Arquitetura do computador e o Sistema Operacional 7
1.3. Algoritmos e linguagens de programação 11
1.4. O ambiente de programação no LBI 15
1.4.1 - Home Python 23
1.5. Exercícios 24

Capítulo 2 - Algoritmos 26
2.1 Definição de Algoritmo 26
2.2 Algoritmo computacional e não computacional 26
2.3. Propriedades de um algoritmo 27
2.4. Refinamento sucessivo e estruturas de programação 28
2.4.1 Eliminando ambiguidades 29
2.4.2. Refinamento do Algoritmo 30
2.5 - Estrutura de comando condicional 32
2.6 - Estrutura de comando repetitivo 34
2.7. Comandos aninhados e rastreio do algoritmo 37
2.8. Viva a diferença 42
2.9. Exercícios 43

Capítulo 3 - Variáveis e Operadores 45


3.1 - Variáveis 45
3.1.1. Comando de Atribuição 48
3.1.2. Tipos de Variáveis 50
3.2 Operadores e Expressões 54
3.2.1. Operadores e Expressões aritméticas 54
3.2.2. Operadores e Expressões Lógicos 58
3.2.2.1 - Operador não (not) 58
3.2.2.2 - Operador e (and) 59
3.2.2.3 - Operador ou (or) 59
3.2.2.4 - Expressões lógicas 60
3.2.2.5 Equivalência de Expressões Lógicas 62
3.3. Exercícios 65

Capítulo 4 - Comandos de Entrada e Saída 68


4.1 - Comando de Saída 68
4.1.1 - Forma básica do comando de saída 68
4.1.2. Comando print() com separador e terminador 70
4.1.3. Comando print() com apenas um parâmetro de texto 72

2
Introdução à Programação com Python

4.1.4. Formatação de dados no comando print() 74


4.2 - Comando de Entrada 77
4.3 - Usando os comandos de entrada e saída em programas simples 79
4.3.1. Cálculo da área de um triângulo 79
4.3.2. Cálculo das raízes de uma equação do segundo grau 82
4.4. Exercícios 83

Capítulo 5 - Comandos Condicionais 89


5.1. Comando if 89
5.2 Comando if-else 92
5.3 Comando if-elif-else 94
5.4 Cálculo de raízes de uma equação do 2⁰ grau 98
5.5. Exercícios 100

Capítulo 6 - Comandos Repetitivos 105


6.1. Comando while 105
6.1.1. Cuidado com o loop infinito 107
6.1.2. Número determinado de repetições com o while 109
6.1.3. Usando while-True 111
6.2. Comando for 112
6.2.1. Comando for 113
6.2.2. Comando for com incremento não unitário 114
6.2.3. Comando for-break 117
6.3. Alguns exemplos de uso de comandos repetitivos 118
6.3.1. Cálculo de média 118
6.3.2. Números Primos 122
6.3.3. Cálculo de raiz quadrada 124
6.4. Exercícios 126

Capítulo 7 - Arranjos 132


7.1. Arranjo unidimensional 133
7.1.1 Arranjos em Python 135
7.1.2 Percorrendo Arranjos 137
7.1.3. Alguns Exemplos 139
7.1.3.1. Cálculo do desvio-padrão 139
7.1.3.2. Relação entre vizinho 141
7.2. Arranjos multidimensionais 143
7.2.1. Definição de arranjos bidimensionais em Python 145
7.2.2. Exemplos usando matrizes 146
7.2.2.1. Pesquisa em matriz 146
7.2.2.2. Verificação de propriedades de uma matriz 149
7.2.3. Arranjos e Processamento de Imagens 153
7.3. Exercícios 158

3
Introdução à Programação com Python

Capítulo 8 - Funções 164


8.1. Motivação 164
8.2. Funções em Python 165
8.2.1. Identificando candidato a virar função 166
8.2.2. Função que retorna dois (ou mais) parâmetros 169
8.3. Escopo de Variáveis 170
8.4. Passagem de arranjos como parâmetro 173
8.5. De volta aos algoritmos 173
8.6. Exercícios 176

4
Introdução à Programação com Python

Prefácio
Este material tem o objetivo de servir de apoio para os estudantes matriculados na
disciplina de Introdução à Programação I, oferecida pelo Departamento de Informática da
UFV, e sua primeira versão foi gerada nos primeiros meses de interrupção das aulas, em
função da pandemia da Covid-19, no ano de 2020. A ideia de elaboração deste material
surgiu a partir da constatação de haver pouquíssimos livros sobre a linguagem de
programação Python em nossas bibliotecas.

De fato, com a grande quantidade de material sobre a linguagem de programação


Python disponível na Internet, talvez a melhor opção seja não gastar recursos públicos para
a aquisição de livros. Porém, os estudantes muitas vezes tem dificuldade de “pinçar” a parte
que interessa, por estar sendo apresentada na disciplina. Muitos livros e materiais
disponíveis na Internet partem do pressuposto de que o leitor já possui noções de
programação. Ou apresentam de início assuntos mais avançados que serão abordados
apenas na disciplina INF 101 - Introdução à Programação II, como a estrutura de dados de
listas.

Assim, este material foi elaborado para seguir exatamente a sequência de assuntos
apresentados em sala de aula. Por isso, este material terá uma versão eletrônica
disponibilizada no PVANet no espaço reservado para a disciplina INF 100 - Introdução à
Programação I, sem custos para os estudantes da UFV. O objetivo é ter um material de
apoio com texto mais detalhado do que o dos slides exibidos em sala de aula.

O texto está organizado da seguinte forma: o capítulo 1 apresenta uma breve


introdução sobre a programação de computadores e motivação para o seu aprendizado,
uma vez que a programação está cada vez mais presente na vida profissional; no capítulo 2
é apresentado o conceito de algoritmo e alguns exemplos não computacionais, para,
posteriormente, ser apresentado em pseudo-linguagem já com o intuito de tradução para a
linguagem de programação Python; o conceito de variável e os principais operadores da
linguagem Python são apresentados no capítulo 3; o capítulo 4 apresenta os comandos de
entrada e saída; a estrutura dos comandos condicionais é apresentada no capítulo 5; o
capítulo 6 apresenta as primeiras estruturas de comandos repetitivos; no capítulo 7 a
estrutura de dados de arranjos unidimensionais e arranjos bidimensionais (matrizes) com
ênfase em algoritmos para manipulação de imagens; como últimos tópicos abordados na
disciplina, as funções e escopo de variáveis são apresentados no capítulo 8.

Para ajudar no aprendizado de qualquer linguagem é fundamental a prática pois


muitos erros são identificados de forma automática pela ferramenta de programação, como
é o caso do interpretador da linguagem Python. Além disso, a implementação de uma
solução usando uma ferramenta permitirá a visualização da solução, permitindo conferir sua
correção e, eventualmente, sua eficiência. Fica como sugestão uma visita à página do
projeto Python Brasil (https://python.org.br) onde você poderá encontrar informações sobre
diferentes ambientes de programação para a linguagem Python. Para os alunos
matriculados na disciplina INF 100 - Introdução à Programação I, haverá links para

5
Introdução à Programação com Python

materiais de apoio como interpretadores Python para instalar em seu computador, páginas
de programação onde você pode enviar e testar seus códigos Python, etc.

Estudar e conhecer os fundamentos teóricos é muito importante. Principalmente


para saber se adaptar às mudanças muito comuns na área de programação. Mudar de
Python para Java, C++ ou Matlab para quem sabe os fundamentos de programação é uma
tarefa relativamente tranquila.

Mas, deve ser lembrado que a prática é fundamental para o aprendizado de


qualquer linguagem de programação. Assim como para ser considerado um piloto é
necessário ter horas de voo, para se tornar um bom programador vai ser preciso muitas
horas de programação.

Então, mãos à obra!

6
Introdução à Programação com Python

Capítulo 1 - Introdução

1.1. Motivação - por que aprender programação?

Uma pergunta comum dos estudantes é: onde este assunto da disciplina vai ser
importante na minha vida pós universidade? No caso do assunto de noções de
programação para estudantes de cursos da área de Ciências Exatas é possível afirmar, sem
medo de errar, que o tema tem se tornado cada vez mais importante.

Vivemos a chamada era da informação, na sociedade da informação, onde a


criação, distribuição, uso, integração e manipulação da informação é uma atividade
econômica, política e cultural cada vez mais significativa. A evolução das tecnologias
digitais de informação e comunicação propiciaram um crescimento exponencial das
informações e estão mudando profundamente todos os aspectos da organização social,
incluindo a economia, educação, saúde, guerra, governo e democracia.

A cada dia, mais e mais produtos são lançados com capacidade de conexão às
redes de computadores. Desde as já consagradas Smart TVs até eletrodomésticos como
geladeiras e fornos de microondas, passando pelos automóveis com computadores e
softwares cada vez mais sofisticados, incluindo os protótipos de carros autônomos, que
dispensam o motorista.

Associados a cada tipo de dispositivo com capacidade de se conectar à Internet,


novas aplicações e serviços vão sendo disponibilizados. Hoje estamos entrando na fase em
que a Internet ganha um “sobrenome” e passa a ser chamada de Internet das Coisas (IoT -
Internet of Things), onde a principal característica é que o usuário precisa conhecer cada
vez menos a tecnologia que está cada vez mais presente nas aplicações do dia-a-dia.

Supermercados inteligentes nos quais o usuário coloca os produtos em seu carrinho


de compras e não precisa passar pelo caixa antes de ir para o estacionamento estão se
popularizando em alguns países. Todo o processamento é feito por softwares de
identificação facial ou leitura de dados de um cartão inteligente (smart card) para identificar
o comprador e sistema de identificação por rádio frequência (RFId) nas etiquetas de cada
produto e sensores RFId espalhados pelo supermercado.

Aplicações nas mais diversas áreas tais como agricultura de precisão, controle de
frota de veículos, monitoramento ambiental, rastreabilidade de produtos para a segurança
alimentar, controle de tráfego em tempo real, controle de distanciamento social em tempos
de pandemia e muitas outras que vão demandar profissionais com diferentes formações,

7
Introdução à Programação com Python

mas que irão precisar de uma característica comum: saber analisar um problema e propor
uma solução descrita utilizando um raciocínio lógico.

E mesmo para quem não irá trabalhar com soluções computacionais, pode
economizar um dinheirinho usando raciocínio lógico. Foi o que aconteceu com o João da
Silva, que na infância era chamado de Joãozinho, quando ligou, no final da tarde, para
cancelar uma consulta médica agendada para as 14h do dia seguinte. A secretária disse:
- Sr. João Silva, infelizmente para cancelamento com menos de 24 horas, no seu
plano de saúde há uma taxa de 80% do valor da consulta. Se o Sr. tivesse ligado antes das
14h não haveria custo para cancelar… Mas o senhor pode optar por reagendá-la.
- Pois não. Então a senhora, por favor, remarque a consulta para a próxima semana,
no mesmo horário.
- Pronto. Consulta reagendada. Deseja mais alguma coisa Sr. João?
- Sim. Eu quero cancelar a consulta da semana que vem.

1.2. Arquitetura do computador e o Sistema Operacional

A arquitetura básica de um computador é apresentada na figura 1.1. A execução das


instruções ocorre no processador, também chamado de Unidade Central de Processamento
(CPU - Central Processing Unit). O processador possui registradores internos (não
detalhados na figura) onde armazena temporariamente os operandos de uma determinada
instrução. Os operandos geralmente são as variáveis definidas no código do programa de
alto nível, conforme veremos em breve. Todas as variáveis e demais objetos definidos no
programa ficam armazenados na Memória (também chamada de memória principal ou
memória RAM) durante a execução do programa. Pode-se dizer, então, que todo o trabalho
de execução de um programa simples envolve apenas o processador e a memória principal
além, é claro, do barramento interno que os conecta e compõem a chamada Arquitetura
Interna do computador (destacada na parte esquerda da figura 1.1).

Figura 1.1 - Arquitetura básica de um computador

8
Introdução à Programação com Python

Entretanto, para comandar a execução de um programa e visualizar os resultados


gerados é necessário a utilização de Dispositivos de E/S (Entrada e Saída), mostrados no
lado direito da figura 1.1. Dentre os dispositivos mais comuns podem ser citados: teclado,
mouse e microfone como dispositivos de entrada; monitor de vídeo, impressora e caixa de
som como dispositivos de saída; e disco rígido, pendrive e tela sensível ao toque como
dispositivos de entrada e saída.

O Disco Rígido é o dispositivo de E/S mais utilizado pois ela armazena de forma
permanente todos os programas instalados no computador e os arquivos que criamos ao
editar o código fonte de um programa escrito em uma linguagem de alto-nível. Ao salvar um
arquivo, o seu conteúdo é gravado no Disco Rígido, sendo possível reutilizá-lo
posteriormente. Ao criar um novo arquivo usando um editor de textos e após adicionar, por
exemplo, 200 linhas de código do programa, caso o computador seja desligado todo o
trabalho será perdido. Isto ocorre porque o arquivo não foi salvo (gravado no disco rígido)
nem uma vez. A memória principal é volátil, ou seja, seu conteúdo é perdido quando o
circuito é desenergizado. Por isso, é importante salvar periodicamente seu arquivo de
trabalho.

A forma de utilização do disco rígido e dos demais dispositivos de entrada e saída


passa despercebida porque o Sistema Operacional esconde de propósito detalhes que não
são importantes para os seres humanos. O Sistema Operacional é um programa que inicia
seu funcionamento ao ligar o computador e tem como uma de suas principais tarefas a
identificação da quantidade de memória disponível que ele poderá utilizar e a quantidade
que ficará disponível para executar os programas dos usuários, além da identificação de
todos os dispositivos de E/S conectados ao computador. Ou seja, o sistema operacional
identifica e controla todas as partes físicas (o hardware) do computador.

A outra tarefa principal dos sistemas operacionais é oferecer uma forma amigável e
fácil de utilizar o computador para o operador humano, chamada de interface
homem-máquina ou, simplesmente, interface. Os primeiros sistemas operacionais
modernos possuíam apenas uma interface de texto, conforme mostrado na figura 1.2.

9
Introdução à Programação com Python

Figura 1.2 - Interface de texto do Ubuntu Linux

Neste ambiente, o usuário precisava memorizar os comandos e digitá-los sem erro


para que fossem executados. Na figura aparecem dois comandos: o primeiro foi digitado
corretamente (ls) e lista os diretórios (ou pastas) e arquivos existentes para o usuário
goulart na máquina de nome lubuntu-goulart; o segundo com um erro de digitação (lx) para
o qual o sistema operacional responde com uma mensagem de erro (lx: comando não
encontrado). Essa simples necessidade de memorizar e digitar comandos tornava o uso de
computadores pouco atraente. Além disso, não havia, na época, programas aplicativos de
uso geral voltados para o cidadão comum e, por isso, o uso de computador ficava restrito às
grandes empresas de tecnologia, a algumas universidades e aos grandes centros de
pesquisa. Este tipo de interface foi utilizado nos computadores de grande porte
(mainframes) e nos primeiros computadores pessoais, até o início da década de 1990. Os
principais sistemas operacionais utilizados eram o UNIX e o DOS.

A partir do início da década de 1990 começaram a surgir as interfaces gráficas


baseadas em janelas, menus e ícones. A Figura 1.3 mostra a interface gráfica de um
sistema operacional Ubuntu Linux, utilizado no Laboratório de Informática onde acontecem
as aulas práticas da disciplina de Introdução à Programação I.

10
Introdução à Programação com Python

Figura 1.3 - Interface Gráfica do Ubuntu Linux

A figura 1.3 mostra alguns ícones que foram colocados na área de trabalho:
Gerenciador de Arquivos (Pasta pessoal), Navegador Web Firefox, IDLE, Code Blocks IDE
e Google Chrome. O usuário pode personalizar a sua área de trabalho, incluindo ou
excluindo ícones de programas. A partir desta interface gráfica é possível procurar todos os
programas aplicativos instalados no sistema, clicando no ícone com 9 quadradinhos, no
canto inferior esquerdo da tela. Um desses aplicativos é o Terminal, que é um programa que
executa a interface de texto sobre a interface gráfica. Isso é útil para usuários mais
experientes que conseguem realizar tarefas de forma mais rápida usando os comandos
desta interface de texto.

As interfaces gráficas de diferentes sistemas operacionais possuem bastante


similaridade conceitual pois são baseadas nos mesmos elementos: ícones, janelas e
menus. Em princípio, o usuário precisa saber qual ícone está associado ao programa que
ele deseja utilizar. Desta forma, espera-se que os usuários do sistema operacional Windows
não encontrem maiores dificuldades de utilizar o sistema operacional Ubuntu que é uma das
versões do sistema operacional Linux.

Figura 1.4 - Interfaces Gráficas: Windows, Ubuntu e Mac OS X

A escolha do Ubuntu Linux para uso no Laboratório de Informática (LBI) se deve ao


fato dele ser um software livre. Isso significa que é possível obter o sistema operacional e

11
Introdução à Programação com Python

um grande número de programas aplicativos sem pedir permissão ou autorização de


nenhuma empresa. Também é possível modificar, atualizar e/ou instalar qualquer programa
que esteja na base de dados do Ubuntu Linux, em algum repositório da internet. Além disso,
os problemas com vírus e outras pragas virtuais são muito menores do que os do sistema
Windows. Tudo isso facilita a manutenção dos sistemas do LBI.

Outra vantagem dos sistemas baseados no Linux é que eles são gratuitos. Para uma
instituição pública como a UFV que é mantida com recursos públicos, impostos oriundos de
todos os contribuintes, esta única razão já seria suficiente para usar o Ubuntu no LBI.

É provável que muitos estudantes matriculados na disciplina INF 100 - Introdução à


Programação I tenham smartphone com o sistema operacional Android, que é o sistema
mais usado no mundo neste mercado. O Android e o Ubuntu são exemplos de sistemas
operacionais construídos sobre o núcleo (kernel) do sistema operacional Linux.

1.3. Algoritmos e linguagens de programação

O uso de computador para resolver problemas reais tem sido cada vez mais
frequentes. Se no início da utilização de computadores os problemas estavam relacionados
apenas à área científica, hoje existem aplicativos das mais variadas áreas desenvolvidas
para o cidadão comum. Aplicativos de redes sociais como Facebook e Instagram são
bastante conhecidos, totalizando mais de 6 bilhões de downloads (Fonte: Play Store,
27/03/2020). Dentre outros aplicativos menos conhecidos do público geral, mas que podem
ser úteis para estudantes da UFV, podem ser citados o UFV Eventos e o Cardápio UFV com
mais de 11 mil downloads (Fonte: Play Store, 27/03/2020). Ambos foram desenvolvidos com
participação de estudantes da UFV.

Como desenvolver um aplicativo? A Figura 1.5 mostra de maneira esquemática as


fases de desenvolvimento de uma solução computacional para um problema do mundo real.

12
Introdução à Programação com Python

Figura 1.5 - Fases de desenvolvimento de um programa

Primeiramente é necessário conhecer qual é o problema que se deseja resolver.


Definido o problema, a fase de análise visa obter um conhecimento completo do problema,
de forma a permitir a definição das tarefas que devem ser realizadas para resolvê-lo. O
passo seguinte é fazer uma descrição sistematizada das tarefas (solução descritiva) que
devem ser executadas, atentando para a correta ordem de execução.

A solução descritiva geralmente é feita usando a linguagem natural (ex: Português)


que pode conter ambiguidade, ou seja, duas pessoas podem interpretar de forma diferente
o que uma tarefa faz. Apenas para exemplificar a ambiguidade do Português pode-se
utilizar um exemplo não computacional. Na frase “Vejo um homem no alto da montanha
usando binóculos”, quem está usando binóculos? A pessoa que disse a frase pode ter
usado binóculos para ver o homem na montanha ou ela pode ter visto que o homem na
montanha estava portanto binóculos.
Qualquer potencial ambiguidade deve ser eliminada ao transformar a solução
descritiva para a forma de algoritmo. Um algoritmo pode ser definido como uma sequência
finita de instruções bem definidas e não ambíguas. Este conceito será explorado com mais
profundidade no Capítulo 2. No contexto computacional, cada instrução do algoritmo deve
estar tão simples e detalhada de forma que poderá ser traduzida para um comando da
linguagem de programação.

O passo seguinte consiste na tradução de cada instrução do algoritmo para uma


instrução da linguagem de alto nível escolhida para a implementação do programa. O

13
Introdução à Programação com Python

resultado desta fase será o chamado código fonte que deve seguir rigorosamente a forma
permitida de escrita da linguagem de alto nível, a chamada sintaxe. O código ou programa
fonte vai ficar gravado em um arquivo para ser executado quando demandado pelo
programador.

Com o programa fonte armazenado em um arquivo, o passo seguinte é fazer a


tradução para a linguagem que o computador entende que é a linguagem de máquina, onde
tudo é codificado como uma sequência de bits 0’s e 1’s. A esta forma dá-se o nome de
código executável. Esta tradução pode ser feita diretamente, sem gerar um outro arquivo ou
indiretamente, quando é gerado um arquivo executável. No primeiro caso temos as
linguagens interpretadas, como é o caso da linguagem Python, na qual o programa é
executado diretamente a partir do programa fonte. No caso de outras linguagens, como por
exemplo C, é utilizado um compilador que transforma o código fonte em código executável
que poderá, então, ser executado.

Independente da forma de transformação do código fonte em código executável


(interpretada ou compilada), ela sempre é feita por um programa (interpretador ou
compilador). De posse do código executável será possível utilizá-lo para verificar se a
solução computacional atende aos requisitos especificados na fase de análise do problema.
Raramente se conseguirá seguir o diagrama da Figura 1.5 passando uma única vez por
cada uma de suas fases.

Muitas vezes é no momento da execução do programa que se torna possível


verificar os erros da implementação da solução. A correção de um erro vai demandar,
necessariamente, a volta a uma das fases anteriores à verificação da solução (execução do
programa). Na disciplina INF 100, a grande maioria dos problemas é bem simples e a
correção dos problemas, geralmente, não demandará uma volta à especificação do
problema.

O tipo mais comum de erro são erros de sintaxe, que ocorrem quando um ou mais
comandos são escritos de forma incorreta. Este tipo de erro também é o mais fácil de
verificar, pois é apontado pelo interpretador ou compilador. No caso da linguagem Python o
interpretador para a execução do programa ao encontrar um erro de sintaxe e uma
mensagem de erro é exibida com informações para a correção. A correção demanda a volta
ao passo de edição do código fonte.

Outro tipo de erro é o de semântica que muitas vezes não é identificado pelo
interpretador Python. Semântica está relacionada com o sentido ou significado de um
comando. Um caso muito comum, em Python, é a troca do operador de comparação “==”
com o operador de atribuição “=”. Ou seja, o usuário pretendia atribuir para a variável a, o
valor da variável b, cujo comando correto seria o comando de atribuição “a = b“, mas acaba
escrevendo “a == b”, usando o comparador de igualdade (==) invés do comando de
atribuição (=). O programa executa normalmente, o comando resultará em um valor True ou
False, que não será armazenado pelo programa, mas a variável a continuará com o mesmo
valor. Para este tipo de erro também é necessário voltar à fase de edição do programa
fonte. Mas pode haver erros de semântica associados à solução descritiva (que geralmente

14
Introdução à Programação com Python

será feita em Português), o que poderia demandar uma volta à fase de análise do problema
e, consequentemente, correção de todas as fases posteriores.

Da mesma forma, os erros de lógica também podem aparecer em diferentes fases


do desenvolvimento do programa. Um erro de lógica em uma condição de parada de um
comando repetitivo poderia colocar o programa em uma execução sem fim (loop infinito) e
este erro, eventualmente, pode se dever apenas a um erro na digitação. Neste caso a
correção costuma ser simples com a correção na edição do código fonte. Ou o erro de
lógica pode ocorrer na fase de análise com a inversão de duas tarefas que tem que ser
feitas em uma ordem pré-determinada. Neste outro caso, a volta seria para a fase de
análise do problema.

Neste ponto, é importante ressaltar que quando um programa mais complexo vai ser
resolvido, cada tarefa identificada na fase de análise pode dar origem a um módulo de
programa. No final desta disciplina será apresentado o conceito de função que é uma forma
de estruturar o programa e promover a reutilização de código. O desenvolvimento de um
módulo ou uma parte ou uma função de um programa complexo vai seguir os mesmos
passos do diagrama da Figura 1.5.

Para finalizar esta seção, é importante apresentar uma diferença fundamental entre
as linguagens interpretadas e compiladas. No caso da linguagem interpretada, o código
fonte pode ser levado para outro computador que tenha um interpretador da mesma
linguagem que ele será executado. Já o código executável gerado em um computador só
poderá ser executado em um outro computador que tenha um processador com o mesmo
conjunto de instruções do primeiro.

Por isso, costuma-se dizer que uma linguagem interpretada é mais portátil do que
uma linguagem compilada. Isso ocorre porque, na linguagem interpretada, a tradução da
linguagem de alto nível para a linguagem de máquina é feita em tempo de execução. Todo
interpretador Python conhece a linguagem Python, obviamente. Um interpretador Python
feito para um processador precisa conhecer apenas a linguagem de máquina deste
processador. E as linguagens de máquina são diferentes para processadores diferentes. Até
mesmo a linguagem de montagem (Assembly) que é um nível intermediário entre a
linguagem de alto nível e a linguagem de máquina, é diferente para processadores
diferentes.

Considere uma operação de adição que na linguagem Python utiliza o operador “+”
para realizar a soma de duas variáveis (“a” e “b”). A expressão em Python seria algo como
“a + b”. Esta expressão deveria ser completada de alguma forma para formar um comando
válido da linguagem Python, mas para o momento este fato não é importante. Conforme foi
dito, em relação à figura 1.1, o processador executa todas as suas operações usando seus
registradores internos. Assim, para que a operação de soma da linguagem de alto nĩvel
aconteça são necessárias 3 operações: 1) transferir o conteúdo da variável “a” para um
registrador R1; 2) transferir o conteúdo da variável “b” para um outro registrador R2; 3)
executar a operação de soma usando os registradores R1 e R2 como operandos.

15
Introdução à Programação com Python

Embora as operações a serem executadas sejam as mesmas, independente do


processador, o código Assembly será muito diferente. Para exemplificar serão considerados
os processadores x86 (Intel/AMD) e RISC, com os respectivos códigos Assembly mostrados
na tabela 1.1. Note que as instruções podem ter nomes diferentes como no caso da
movimentação de dados da memória para registrador (mov/lw) e, eventualmente, quando
tem mesmo nome como no caso da soma (add) a forma de especificar os operandos são
diferentes: uma linguagem permite especificar apenas 2 registradores enquanto que a outra
permite definir 3 registradores. Mas em ambas, o primeiro registrador armazenará o
resultado da operação de soma.

Tabela 1.1 - Códigos Assembly de uma soma de duas variáveis.


Assembly do Assembly do Significado para x86 (RISC)
Processador x86 Processador RISC

mov ax, a lw $t0, a carrega variável a no registrador ax (t0)


mov bx, b lw $t1, b carrega variável b no registrador bx (t1)
add ax, bx add $t3, $t0, $t1 soma registradores ax e bx (t0 e t1), com
resultado no registrador ax (t3)

Felizmente, para todos nós, esta deve ser a última vez que será falado sobre
linguagem de Assembly e linguagem de máquina. De agora em diante, será utilizada
apenas a linguagem de alto nível Python. E, o mais importante, é que usando a linguagem
Python o seu programa vai executar em uma máquina com processador x86 ou RISC sem
nenhum problema, assumindo que exista um interpretador Python instalado nesta máquina.

1.4. O ambiente de programação no LBI

Como suporte para as aulas práticas da disciplina INF 100 - Introdução à


Programação I, o Departamento de Informática da UFV possui o Laboratório de Informática
(LBI) localizado no segundo pavimento do prédio da Caixa Econômica Federal. O LBI
funciona durante o semestre letivo de segunda a sexta-feira, de 7h às 18h30,
excetuando-se os feriados e recessos previstos no calendário escolar da UFV. A sala 4
(sala de Monitoria) pode ser acessada para praticar a programação Python.

Mas é fortemente recomendado que o estudante matriculado em INF 100 instale o


ambiente com o editor de programas e interpretador Python (IDLE) em seu computador,
seguindo as instruções da seção 1.4.1 - Home Python.

O LBI possui quatro salas para as aulas práticas sendo duas salas com 24
computadores e 2 salas com 20 computadores. O acesso a uma das quatro salas só é
permitido no horário da aula prática. Há ainda uma sala de monitoria com 12 computadores
e uma bancada sem computadores na qual o estudante poderá utilizar seu próprio
computador portátil, se preferir. O(s) monitor(es) da disciplina INF 100 fazem atendimento

16
Introdução à Programação com Python

em horários que são divulgados na recepção do LBI, no início de cada semestre letivo.
Todos os computadores do LBI possuem o Sistema Operacional Linux, distribuição Ubuntu.

Para a execução das atividades nas salas do LBI, o estudante matriculado na


disciplina INF 100 utilizará o navegador de Internet Firefox (ou Google Chrome), o servidor
do LBI, um leitor de arquivos PDF (Portable Document Format), o ambiente de
desenvolvimento IDLE e o gerenciador de arquivos. O estudante utiliza uma conta padrão
cujo nome de usuário é “Aluno” e a senha é informada na primeira aula prática.

A Figura 1.6 apresenta a tela com a área de trabalho da conta do usuário Alunos,
com a identificação dos ícones relacionados aos programas citados no parágrafo anterior.
Esta conta está programada para apagar todos os arquivos ao final da sessão. Assim, todo
estudante que utilizar esta mesma conta sempre encontrará a sua pasta padrão vazia.

Figura 1.6 - Área de trabalho do usuário Alunos no LBI

Toda aula prática possui um roteiro e, eventualmente, um ou mais arquivos


adicionais que ficam armazenados no servidor do LBI. Um leitor de arquivos PDF é
necessário, pois todos os roteiros de aulas práticas são disponibilizados em formato PDF.
Existem diversos leitores de PDF gratuitos disponíveis na Internet. Todos os computadores
do LBI possuem leitor de PDF. Em geral, a configuração permite abrir o arquivo PDF em
uma nova aba do navegador de internet. Mas também é possível que seja aberta uma
janela nova com a imagem do arquivo PDF.

Nas máquinas do LBI, para facilitar a vida do estudante, existe um ícone que está
associado ao navegador de internet Firefox já configurado com a página inicial sendo o
servidor do LBI. Desta forma, basta clicar no referido ícone para abrir a tela de acesso ao
servidor do LBI. Para acessar o servidor do LBI o estudante usa seu número de matrícula
como nome de usuário e sua senha definida na primeira aula prática.

17
Introdução à Programação com Python

Os dias e horários que um estudante pode acessar o servidor do LBI é programado


de acordo com o seu horário de aula prática na disciplina INF 100 e com o tipo de atividade:
presencial ou a distância. Quando o estudante optar por realizar a atividade a distância, ele
poderá usar o navegador de internet de sua preferência fornecendo o endereço completo do
servidor do LBI: http://linux-server.lbi.ufv.br. Os procedimentos para obter o material (roteiro
e arquivos adicionais) para a realização da aula prática e a entrega do trabalho são os
mesmos para quem está no LBI ou para quem está em casa ou outro lugar qualquer.

O ambiente de desenvolvimento IDLE possui duas partes principais: uma interface


para execução de comandos (shell) e um editor de programas Python integrado. Ao clicar
no ícone do IDLE será aberta uma janela como a mostrada na Figura 1.7(a). Para que seja
aberta a janela do editor de programas (Figura 1.7(b)) é necessário selecionar, na janela do
Shell, no menu de arquivo (File) a opção de criar um novo arquivo (File -> New File) ou abrir
um arquivo já existente (File -> Open).

(a) Shell (b) Editor de Programas

Figura 1.7 - Ambiente de desenvolvimento IDLE

Embora as janelas sejam parecidas, o propósito delas é bem diferente. Mas tem
diferenças perceptíveis também. A primeira é que o programa associado ao ícone IDLE na
área de trabalho é o Shell.

Outra diferença é que no topo janela do Shell aparece a informação de que se trata
do Shell da linguagem Python versão 3.5.2 (Python 3.5.2 Shell), enquanto que na janela do
editor de programas aparece Untitled (Sem Título) porque foi usada a opção para criar um
novo arquivo (File -> New File) que ainda não teve seu nome definido (a definição do nome
se dá quando o arquivo for salvo pela primeira vez). Uma outra diferença é que a janela do
editor de programas está vazia (sem texto) à espera de que o usuário comece a escrever o

18
Introdução à Programação com Python

seu programa Python. Já na janela do Shell são exibidas informações sobre o interpretador
Python e, depois, é exibido o prompt de comandos representados pelos caracteres >>>.

Este prompt de comandos (>>>) indica que o Shell está esperando que algum
comando seja digitado e que seja dada a ordem para sua execução, através da digitação da
tecla “Enter”. Considere um exemplo simples onde se deseja atribuir para um objeto de
nome C, a soma de dois outros objetos A e B. A Figura 1.8 apresenta a utilização do Shell
para executar tal tarefa.

Após cada comando, no exemplo da Figura 1.8, foi colocado um comentário (#) na
mesma linha. Tudo o que vem após o caractere “#” é ignorado pelo interpretador Python, ou
seja, não faz parte do comando. Por isso é chamado de comentário. Como será visto, o
comentário é muito útil para que outros programadores possam entender com mais
facilidade o que o código faz e, até mesmo para que o próprio programador se lembre do
que o código faz, se ele ficar muito tempo sem mexer naquele programa. A seguir será
detalhado o significado de cada comando e cada resposta gerada pelo interpretador Python.

Figura 1.8 - Exemplo de comandos no Shell do IDLE

Os dois primeiros comandos são para criar os objetos (ou variáveis) A e B, com
valores 2 e 5, respectivamente. Para estes comandos o interpretador Python não gera
nenhuma saída, dando a impressão de que nada ocorreu. O terceiro comando foi o nome
do primeiro objeto (A) e como resposta o Shell exibiu o seu valor 2. Note que na linha de
resposta ao comando não aparece o prompt (>>>), além de exibir a resposta em outra cor
(azul). O quarto comando foi similar ao terceiro, só que para o objeto B.

O comando seguinte gera como resposta uma mensagem de erro, já que o nome do
objeto C, do qual se pretendia exibir o valor armazenado, ainda não havia aparecido e,
portanto, era desconhecido do interpretador Python. A resposta a este comando “inválido” é

19
Introdução à Programação com Python

uma mensagem de erro que informa ter havido um erro de nome, mais explicitamente que o
nome C não está definido: “NameError: name 'C' is not defined”. O comando seguinte (C =
A + B) corrige o erro, definindo o objeto C com valor inicial igual a soma dos valores atuais
de A e B. Agora, na sequência, o comando C exibe o valor 7.

Toda a informação digitada no Shell é perdida quando sua janela é fechada ou se o


computador for desligado, como no caso de uma queda de energia durante a aula prática.
Por isso, o Shell deve ser usado somente para efetuar pequenos testes. E, nas aulas
práticas, o Shell deverá ser usado apenas para abrir (ou criar) o arquivo com o programa
que será desenvolvido para ser entregue no final do prazo determinado e para visualizar o
resultado da execução do programa, conforme será mostrado a seguir.

Para que não se perca o trabalho, os comandos do programa Python deverão ser
digitados na janela do editor de programas e deverão ser gravados em um arquivo. Por
convenção, todos os arquivos com programa escrito na linguagem Python devem ter
terminação .py, como por exemplo p01.py, teste.py ou SerieFibonacci.py. Para exemplificar
será usado um pequeno programa com comandos equivalentes aos comandos do Shell
usados na Figura 1.8. Uma diferença é que para exibir o valor de um objeto na linguagem
Python deve-se usar o comando print() fornecendo como parâmetro o nome do objeto a ter
seu valor exibido. Ao invés de escrever simplesmente “A” como foi o comando no Shell, no
programa deve-se escrever o comando “print(A)”. A Figura 1.9 mostra a janela do editor de
programas.

Figura 1.9 - Programa com erro

Antes de executar um programa que foi escrito na janela do editor do programa é


preciso salvá-lo. Isso pode ser feito utilizando a opção do menu “File -> Save” ou digitando
as teclas “Ctrl+S” (significa: manter pressionada a tecla Ctrl e pressionar a tecla S). Porém,
se você tentar executar o programa sem salvá-lo, o IDLE exibirá uma mensagem para que
você o salve. A ideia é que a versão a ser executada deve ser exatamente a que você está
vendo na tela. Note que o arquivo da Figura 1.9 já havia sido salvo (gravado no disco rígido)
quando a tela foi capturada, conforme o nome do arquivo que aparece no topo da janela
(primeiro.py).

Para executar o programa deve-se usar a opção do menu “Run -> Run Module” ou a
tecla de atalho F5 que fica na parte superior do teclado. A saída ou resultado da execução

20
Introdução à Programação com Python

do programa será exibida na janela do Shell. No código, o comando para exibir o conteúdo
do objeto (variável) C está antes da sua criação e definição do valor. Por isso, a saída
exibida conterá uma mensagem de erro, conforme mostrado na Figura 1.10.

Figura 1.10 - Janela do Shell com a saída do programa da Figura 1.9

Note que o interpretador Python lê o programa e vai executando os comandos


sequencialmente. A primeira linha é ignorada pois é apenas um comentário. As duas linhas
seguintes criam e definem o valor inicial dos objetos A e B, porém não produzem nenhuma
saída para o Shell. Na sequência, existem dois comandos de impressão (print()) que geram
saídas para o Shell com a exibição dos valores 2 e 3, dos objetos A e B, respectivamente.

O terceiro comando de impressão contém um erro pois usa o nome de um objeto


que ainda não foi definido. A definição do objeto C está na linha seguinte (linha 7), mas o
interpretador não enxerga isso, pois ele tenta executar os comandos na sequência em que
eles foram escritos pelo programador. Este erro ocasiona a mensagem de erro na janela do
Shell (vide Figura 1.10). Note que, além de indicar o tipo de erro (NameError: name ‘C’ is
not defined) o interpretador também informa a localização do erro no dentro do código,
neste caso na linha 6 (File "/home/goulart/primeiro.py", line 6, in <module>). Também é
informado o nome do arquivo porque programas mais complexos podem ser compostos por
mais de um arquivo.

A correção, neste caso, consiste em trocar de posição a linha 6 com a linha 7,


colocando a definição do objeto C (C = A + B) antes de sua impressão (print(C)). Após
qualquer modificação no texto do programa, a janela do editor exibe o nome do arquivo
entre ‘*’ para indicar que a versão vista na janela é diferente da gravada no disco rígido,
como pode ser visto na Figura realizar tal modificação

21
Introdução à Programação com Python

Figura 1.11 - Programa sem erros

Após a correção, usando a tecla de atalho F5, o IDLE pedirá novamente que o
arquivo do programa (primeiro.py) seja salvo e, após confirmação, executará novamente o
programa com a correção feita, gerando a saída exibida na Figura 1.12. Nesta figura
aparecem as saídas da primeira e segunda execuções. Entre cada execução, o
interpretador informa que houve um reinício (Restart) da execução, informando também o
nome do arquivo (primeiro.py) que teve a execução iniciada, com sua localização no
computador (/home/goulart) na mensagem destacada pela sequència de caracteres “=”:
“=================== RESTART: /home/goulart/primeiro.py ====================”.
Como o programa foi corrigido e está sem nenhum erro, a segunda saída apresenta apenas
os três valores impressos pelos três comandos print(), imprimindo na sequência os valores
de A, B e C, respectivamente 2, 5 e 7.

Figura 1.12 - Janela do Shell com as duas execuções do programa primeiro.py

Caso alguma informação apresentada aqui sobre o programa não tenha ficado clara
não se preocupe, pois o conceito de variável e o comando print() serão apresentados de
maneira detalhada nos próximos capítulos. O mais importante desta seção é a informação
de que, nas aulas práticas ou quando for usar o ambiente de desenvolvimento IDLE, o Shell
é usado apenas para abrir ou criar seu(s) arquivo(s) de trabalho e depois disso, verificar as
saídas geradas pelo programa. Os arquivos de trabalho devem ser editados na janela do
editor de programas.

22
Introdução à Programação com Python

Outro programa que pode ser útil é o gerenciador de arquivos que serve para que o
usuário organize seus arquivos e diretórios (ou pastas). Esta organização é muito
importante para permitir a localização rápida de um arquivo no computador. No caso do
sistema instalado no LBI, que é uma versão do Linux, o diretório ou pasta do usuário fica no
diretório de nome “home”. E cada pasta de usuário possui algumas pastas (diretórios)
previamente definidas. A figura 1.13 mostra o gerenciador de arquivos aberto pelo usuário
“goulart” na máquina onde este documento estava sendo editado. Note que na barra de
navegação é mostrada a informação completa do caminho da localização atual
“/home/goulart” que é o diretório padrão do usuário. No caso da conta usada no LBI o
caminho será “/home/alunos”. Na área de visualização são exibidas os ícones associados
às pastas criadas pelo sistema para o usuário (“Área de Trabalho”, “Documentos”,
“Downloads”, “Imagens”, “Modelos”, “Música”, “Público” e “Vídeos”) além do ícone vinculado
ao arquivo Python “primeiro.py”.

Figura 1.13 - Gerenciador de Arquivos mostrando a pasta do usuário “goulart”.

Usando o gerenciador de arquivos, o usuário pode criar novas pastas para organizar
seus arquivos da maneira que ele considerar a mais adequada. Entretanto, nas máquinas
do LBI, o usuário não poderá criar suas pastas e deixar seus arquivos guardados lá, pois ao
final de cada sessão todos os arquivos do usuário Alunos são apagados, restaurando as
pastas e arquivos padrão. Assim, no LBI o gerenciador será usado mais frequentemente
para localizar os arquivos baixados do servidor, em geral, o roteiro da aula prática e,
eventualmente, um ou mais arquivos python. Suponha, por exemplo, que após baixar
(realizar o download) o arquivo “p01.pdf” com o roteiro da aula prática 1, ele não tenha
aparecido ao lado do arquivo “primeiro.py” na área da pasta padrão do usuário. O que
fazer?

23
Introdução à Programação com Python

Figura 1.14 - Gerenciador de Arquivos mostrando o conteúdo da pasta “Downloads”

Neste caso o gerenciador de arquivos deve ser usado como um navegador para
percorrer as pastas em busca do arquivo desejado. O mais comum é o arquivo ser baixado
para a pasta “Downloads” que é uma das pastas existentes na área do usuário. Para
acessá-la, basta clicar no ícone da pasta “Downloads” que o gerenciador passará a exibir,
então, o conteúdo da pasta “Downloads”, como mostrado na Figura 1.14. Dentre os
diversos arquivos que o usuário “goulart” já havia baixado se encontra o arquivo “p01.pdf”.
Agora, bastaria clicar sobre o ícone do arquivo “p01.pdf” para abri-lo com o leitor de PDF
padrão do sistema operacional e verificar o seu conteúdo.

Caso o arquivo não estivesse na pasta “Downloads” o processo poderia ser repetido
com qualquer outra pasta, usando os ícones de navegação (< ^ >) na parte superior
esquerda da janela ou clicando diretamente no nome da pasta desejada que aparece na
lista na área esquerda da janela (“Pasta Pessoal”, “Área de Trabalho”, “Documentos”,
“Música”, “Imagens”, “Vídeos” e “Downloads”). Note que na lista, a pasta que está em uso
aparece com o fundo cinza: “Downloads” na Figura 1.14 e “Pasta Pessoal” na Figura 1.13.
“Pasta Pessoal” corresponde à pasta principal de cada usuário: “/home/goulart” no exemplo
usado neste material e “/home/alunos” no caso da conta usada pelos alunos no LBI.

1.4.1 - Home Python

Para realizar as atividades práticas de programação será necessário a instalação do


ambiente de desenvolvimento IDLE-Python e bibliotecas numérica e gráfica em um
computador pessoal. Existem versões do IDLE-Python para diversos sistemas operacionais.
A seguir são apresentadas as instruções para instalação nos sistemas operacionais Linux e
Windows.

Para instalação no sistema operacional Linux é necessário estar conectado à


Internet, pois os arquivos são buscados em repositórios da versão do sistema operacional

24
Introdução à Programação com Python

instalado no computador. Após certificar-se que a conexão está operacional, basta seguir a
seguinte sequência de passos:

1) Acesse a página da disciplina INF 100 no PVANet e pegue o arquivo instalaIDLE.


2) Abrir um terminal e entrar no diretório onde o arquivo instalaIDLE foi salvo.
3) Executar no terminal o comando “sudo su” (sem as aspas) e fornecer a senha de
administrador. Os comandos a seguir devem ser executados pelo usuário
administrador do sistema, ou seja, após a execução do comando deste passo 2.
4) Executar o comando “chmod +x instalaIDLE” (sem as aspas) para incluir a
permissão de execução para o arquivo instalaIDLE, que é um arquivo executável
(script).
5) Executar o comando “./instalaIDLE” para executar o script que fará o resto do
trabalho.

O processo de instalação costuma demorar alguns minutos, em função da


velocidade de acesso à Internet e carga do servidor onde está localizado o repositório dos
arquivos que serão baixados para seu computador. Fique atento para eventuais mensagens
de erro, que indicam eventual falha no processo de instalação. Mensagens de advertência
(warning) indicam que um problema foi detectado, mas contornado e a instalação terá sido
bem sucedida se houver apenas mensagens de advertência.

Para quem não está matriculado na disciplina INF 100 e, portanto, não tem acesso
ao PVANet, a instalação pode ser feita com a seguinte sequência de 7 comandos, como
superusuário:
> apt-get update
> apt-get install --upgrade python3-pip -y
> pip3 install --upgrade pip -y
> apt-get install --upgrade libfreetype6-dev build-essential g++ libjpeg8-dev pkg-config
python3-cairocffi libjpeg-dev zlib1g-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev
python-tk -y
> pip3 install --upgrade matplotlib Pillow
> apt-get install --upgrade python3-scipy python3-tk -y
> apt-get install --upgrade idle3

Há ainda um vídeo com tutorial mostrando a instalação no Linux, que pode ser visualizado
neste endereço: https://youtu.be/YmI3vQIRMHQ.

Para instalação no sistema operacional Windows, é recomendado tentar primeiro a


instalação pela loja da Microsoft, que funciona muito bem para as versões 10 e 11 do
Windows. Lembre-se que para fazer a instalação é necessário que o seu computador esteja
conectado à Internet. Abra o terminal de comandos do Windows, digitando CMD na busca
(ícone da lupa) da interface gráfica. Após abrir o terminal de textos digite o comando
“python” seguido da tecla Enter. Caso o Python não esteja instalado, o contato com a loja da
Microsoft será feito e os programas necessários serão baixados e instalados de forma
automática. O Python é gratuito, não sendo cobrada nenhuma taxa para a sua instalação.

25
Introdução à Programação com Python

Caso este primeiro método não funciona, a instalação pde ser feita manualmente do pacote
disponível no endereço https://www.python.org/downloads/windows/. Você deve baixar a
release mais recente do Python 3, para a versão do seu Windows. Após fazer o download
do instalador e iniciar a instalação do Python é IMPORTANTE selecionar a opção para
incluir o Python na lista de caminhos (PATH) do Windows. Esta opção é apresentada em
uma das janelas exibidas no processo de instalação e deve ser marcada.

Se isso for feito não haverá problemas na execução dos seus códigos. Porém, se
esta opção não for marcada, é possível que o IDLE não seja executado, ou ainda, que ele
não encontre as bibliotecas gráfica, numérica, etc., e como consequência, alguns
programas podem não funcionar porque não conseguiram encontrar as bibliotecas nos
comandos de importação (import).

Este instalador não instala as bibliotecas numpy e PIL (bibliotecas de manipulação


de arranjos e de processamento de imagens, respectivamente), que serão necessárias para
algumas implementações. Assim, os passos seguintes deverão ser feitos mesmo para
quem já tem o Python-IDLE instalado. A instalação das bibliotecas citadas pode ser feitas
usando o Shell do Windows (Command ou cmd) com comandos específicos. Para instalar a
biblioteca gráfica PIL um dos 3 comandos a seguir resolverá o problema:
python -m pip install Pillow
Dependendo de como o Python foi nomeado no seu sistema (python, python3 ou py) um
dos dois comandos alternativos a seguir podem funcionar: python3 -m pip install Pillow ou
py -m pip install Pillow.

Analogamente, para a instalação da biblioteca numérica numpy existem os


comandos possíveis poderiam se um dos 3 a seguir:
python -m pip install numpy :
python3 -m pip install numpy
py - m pip install numpy

A instalação é feita buscando arquivos na Internet. Logo, o computador deverá estar


conectado à rede para a instalação do Anaconda e/ou das bibliotecas. Na página da
disciplina INF 100 – Introdução à Programação I no PVANet, há um vídeo que mostra de
forma detalhada a instalação do Anaconda. Para quem não está matriculado na disciplina
INF 100 e, portanto, sem acesso ao PVANet, o vídeo com tutorial mostrando a instalação no
Windows, pode ser visualizado neste endereço: https://youtu.be/MFWTQxUauTw
(atualizado em janeiro de 2021).

1.5. Exercícios

1) O vídeo https://www.youtube.com/watch?v=nKIu9yen5nc apresenta depoimentos de


figuras como Mark Zuckerberg (Facebbok), Jack Dorsey (Twitter), Bill Gates
(Microsoft), Chris Bosh (Jogador de Basquete da NBA), dentre outros, sobre suas

26
Introdução à Programação com Python

primeiras experiências com programação. Após assistir ao vídeo responda as


perguntas a seguir. Quem disse as seguintes frases (tradução livre):

a. “you don’t have to be a genious to know how to code. You have to be determined.”
(você não precisa ser um gênio para saber como programar. Você deve ser
determinado.)
b. “the programmers of tomorrow are the wizards of the future.” (programadores de
amanhã são os magos do futuro).
c. “Coding is something that can be learned and… I know it can be intimidating… a
lot of things can be intimidating, but, you know, what isn’t.” (Programar é algo que
pode ser aprendido e… eu sei que pode ser intimidador… muitas coisas podem ser
intimidadoras, mas, você sabe, o que não é?.
d. “I think the first program I wrote asked things like, what’s your favourite colour? Or,
how old are you?”. (Eu acho que o primeiro programa que escrevi perguntava coisas
como, qual sua cor favorita? Ou, quantos anos você tem?).
e. “(programming) it’s the closest thing we have to a super power.” ((Programação) é
a coisa mais próxima que temos de super poder).

2) No vídeo https://www.youtube.com/watch?v=6XvmhE1J9PY, o então presidente dos


EUA, Barack Obama, fala sobre a importância estratégica do ensino de
programação nas escolas. Você concorda com a visão dele. Escreva um parágrafo
com sua opinião sobre a importância estratégica da programação na sua área de
atuação como futuro profissional.

3) O vídeo https://www.youtube.com/watch?v=Fkd9TWUtFm0 apresenta um


“experiente” desenvolvedor de aplicativos falando de como iniciou sua precoce
carreira. Quais foram as linguagens de programação que ele citou já ter utilizado?

4) Identifique no seu computador a quantidade de memória RAM, a velocidade do


processador e o tamanho do disco rígido.

5) Suponha que um computador gaste, em média, 8 ciclos de processador para


executar cada instrução aritmética de ponto flutuante. Um programa de simulação
executa 10 bilhões de instruções de ponto flutuante. Quanto tempo um computador
do início da década de 1980 com processador de ciclo de 1 MHz demoraria para
executar este programa?

6) Quanto tempo o seu computador demoraria para executar o mesmo programa do


exercício 5?

7) Instale o interpretador IDLE-Python em seu computador. Certifique-se de que as


bibliotecas numérica (numpy) e gráfica (PIL) estejam instaladas (Execute o
programa abaixo, para testar a importação das referidas bibliotecas). Ao final da
execução a mensagem “Olá mundo…” (sem as aspas) deverá ser exibida na janela
do Shell.

27
Introdução à Programação com Python

import numpy
import PIL
print(‘Olá mundo...’)

28
Introdução à Programação com Python

Capítulo 2 - Algoritmos
No capítulo 1 foi apresentada a figura 1.5 com as fases de desenvolvimento de um
programa, que se inicia com a análise do problema para se obter uma solução descritiva e,
a seguir, descrever a solução em forma de um algoritmo. Mas o que vem a ser um
algoritmo? É o que será descrito neste capítulo.

2.1 Definição de Algoritmo

Alguns dicionários informam que um algoritmo pode ser definido de forma simples
como uma sequência de ações executáveis. Esta definição genérica abarca a maioria das
situações do cotidiano como será visto nos exemplos a seguir. No contexto computacional
um algoritmo pode ser definido como “um conjunto de regras e procedimentos lógicos
perfeitamente definidos que levam à solução de um problema em um número finito de
etapas” (Fonte: https://www.google.com/search?q=algoritmo).

No nosso dia a dia temos como exemplos de algoritmos uma receita culinária de pão
de queijo, um manual de montagem de um brinquedo ou de equipamento, uma rota definida
por um aplicativo de mapas para se chegar a um destino, etc. Em cada um dos três casos
citados, se as ações definidas forem seguidas à risca, ao final o resultado deveria ser
algumas unidades de pão de queijo para serem degustadas, um brinquedo ou equipamento
montado e a chegada ao destino, respectivamente.

2.2 Algoritmo computacional e não computacional

Daqui para frente será utilizado o exemplo da receita, ou do algoritmo, para produzir
pão de queijo mostrando as similaridades e diferenças para um algoritmo computacional. A
tabela 2.1 apresenta uma receita de pão de queijo detalhando em uma coluna a lista de
ingredientes e na outra coluna as instruções para fazer os pães de queijo.

Uma receita, em geral, como mostrado na tabela 2.1, possui duas partes: o conjunto
de ingredientes e o modo de preparo. O conjunto de ingredientes corresponderia ao
conjunto de dados do algoritmo computacional, que compreende as informações que
precisam ser processadas para se chegar ao resultado desejado. Exatamente como se faz
com os ingredientes da receita. No caso computacional, como será visto a partir do Capítulo
3, o programador pode construir novos dados mais complexos (estruturas de dados) usando
os tipos de dados primitivos da linguagem de programação.

29
Introdução à Programação com Python

Tabela 2.1 - Receita de Pão de Queijo


Ingredientes Modo de preparo

- 4 copos (americano) de polvilho 1. Coloque o polvilho em uma tigela grande.


doce (500 g); 2. À parte, aqueça o sal, o leite e o óleo.
- 1 colher (sopa) tempero ou sal a 3. Quando ferver, escalde o polvilho com essa
gosto mistura, mexa muito bem para desfazer
- 2 copos (americano) de leite (300 ml) pelotinhas.
- 1 copo (americano) de óleo (150 ml) 4. Deixe esfriar.
- 2 ovos grandes ou 3 pequenos 5. Acrescente os ovos, um a um, alternando com
- 4 copos (americano) de queijo minas o queijo e sovando bem, até a massa ficar
meia cura ralado homogênea, após cada adição.
- óleo para untar 6. Unte as mãos com óleo, se necessário.
7. Enrole bolinhos de 2 cm de diâmetro e
coloque-os em uma assadeira untada.
8. Leve ao forno médio (180º C), preaquecido.
9. Asse até ficarem douradinhos.

O modo de preparo da receita culinária corresponde ao algoritmo propriamente dito,


pois ele descreve as ações que devem ser executadas para, usando os ingredientes, se
produzir o resultado desejado. Entretanto, as ações que o computador consegue executar
são ações muito simples e devem ser definidas de forma que não haja nenhuma dúvida
sobre o que se está querendo executar. Da mesma forma, os dados a serem processados
pelo computador tem que ser exatos, não podendo ter nenhum tipo de ambiguidade.

2.3. Propriedades de um algoritmo

Voltando à definição de algoritmo apresentada é possível destacar algumas das


propriedades que todo algoritmo deve ter. Algoritmo é “um conjunto de regras e
procedimentos lógicos perfeitamente definidos que levam à solução de um problema em um
número finito de etapas”. As propriedades dos algoritmos foram definidas por Donald Knuth
(https://pt.wikipedia.org/wiki/Donald_Knuth):
• Finitude: um algoritmo deve sempre terminar após um número finito de ações;
• Definição: cada passo de um algoritmo deve ser definido com precisão; as ações a
serem executadas deverão ser especificadas rigorosamente e sem ambiguidades;
• Entrada: são os valores que são fornecidos ao algoritmo. Essas entradas são
tomadas a partir de conjuntos de objetos especificados;
• Saída: são os valores resultantes das ações do algoritmo relacionadas com as
entradas especificadas;
• Eficácia: são todas as operações a serem realizadas no algoritmo devem ser
suficientemente básicas e podem, em princípio, ser feitas com precisão e em um
período de tempo finito por um homem usando papel e lápis.

30
Introdução à Programação com Python

A primeira propriedade (finitude) está relacionada com o tempo esperado para se


obter o resultado. Em um tempo finito os pães de queijo tem que sair do forno e ninguém
pode morrer de fome enquanto espera. Para alguns problemas computacionais mais
complexos é necessário verificar se o problema pode ser resolvido, usando o computador
que se tem disponível. Por exemplo, uma previsão de tempo baseada em imagens de
satélite para o dia seguinte não pode levar mais do que poucas horas. Se demorar, por
exemplo, dois dias o resultado seria a previsão do tempo de ontem… No caso da disciplina
INF 100 todos os problemas apresentados são relativamente simples e não será feita este
tipo de análise.

A propriedade de definição está relacionada com a parte do conceito de algoritmo


que diz “... e procedimentos lógicos perfeitamente definidos que levam à solução…”. Isto
significa que não pode haver ambiguidade (dúvida) sobre o que está escrito no algoritmo,
tanto na definição dos ingredientes (conjunto de dados) quanto nas ações ou comandos do
modo de preparo ou do algoritmo.

A propriedade de entrada está associada com o conjunto de informações


necessárias (os ingredientes) para serem processadas e/ou transformadas para se chegar
ao resultado esperado. E a propriedade de saída corresponde exatamente ao resultado
esperado, quando se pode comprovar a correção do algoritmo. Estão saindo pães de queijo
do forno? Ou está saindo um bolo?

Finalmente, a propriedade de eficácia está relacionada com o grau de simplicidade


de cada ação definida no algoritmo tem. A ação está suficientemente detalhada e simples?
É realmente uma única ação? Caso estes requisitos não sejam atendidos é necessário
refinar a ação, ainda complexa, quebrando-a em duas ou mais ações. Esta tarefa que pode
ser executada repetidas vezes é chamada de refinamentos sucessivos. É importante
lembrar que a versão final de um algoritmo computacional deve ser tal que, cada ação
represente um único comando da linguagem de programação que será usada. Na próxima
seção, cada ação do algoritmo para fazer pães de queijo deverá ser especificada de forma
a representar uma única ação simples.

2.4. Refinamento sucessivo e estruturas de programação

Nesta seção serão apresentadas versões sucessivas e refinadas do algoritmo para


fazer pães de queijo para exemplificar a eliminação de ambiguidades e a apresentação das
três estruturas básicas de programação: sequencial, condicional e repetitiva. Estas três
estruturas são suficientes para escrever qualquer programa computacional. Por isso, é
importante, desde já, entender tais estruturas mesmo quando aplicadas a um exemplo não
computacional.

A primeira estrutura é a sequencial. Todo algoritmo (e programa) é composto por


uma sequência de ações relacionadas com o que é necessário para poder. Observe que na

31
Introdução à Programação com Python

Tabela 2.1, as ações do modo de preparo estão numeradas, indicando a ordem (sequência)
em que as ações devem ser executadas. Esta ordem é importante para a correção da
solução. As estruturas condicional e repetitiva serão apresentadas durante o processo de
refinamento do algoritmo.

Será suposto que existe um conjunto de equipamentos para permitir a execução das
ações que aparecerão nas próximas versões do algoritmo em seus refinamentos sucessivos
tais como: panela e tabuleiro (colocar), mixer (misturar), batedeira (bater), fogão (aquecer,
ferver), forno (ligar, regular temperatura, assar), lixeira (descartar), balança (pesar), jarra de
1 litro com gradação de 10 em 10 ml (medir), ralador de queijo (ralar), tigela grande e tigela
pequena (colocar).

2.4.1 Eliminando ambiguidades

Imagine que a receita será feita por um computador ou um robô ou mesmo por um
ser humano que nunca fez nenhuma receita em toda sua vida e muito menos pão de queijo.
O primeiro tipo de ambiguidade aparece na lista de ingredientes. Uma informação que pode
ser muito clara para um cozinheiro experiente pode ser de difícil entendimento para alguém
sem experiência na cozinha.

Ao ler na lista de ingredientes “1 colher (sopa) tempero ou sal a gosto” poderão


surgir diversas algumas dúvidas: usar tempero ou sal? Qual tempero, pimenta? Qual é a
colher de sopa? Qual quantidade corresponde ao “a gosto”? Uma colher de sopa rasa,
cheia? Para não haver estas ambiguidades o ingrediente deveria ser algo como “10g de
sal”. O que significa um ovo grande? Pode ser ovo de pata? O que significa “meia cura”?

Os ingredientes serão redefinidos pensando que a receita será feita por um ser
humano sem nenhuma experiência culinária. A ideia é que não haja nenhuma dúvida
sobre o que deverá ser utilizado em cada ação do algoritmo. Para tornar mais claro, foi
inserido um comentário (texto que aparece após o caractere #) para cada ingrediente,
indicando se precisaria ser pesado ou medido, considerando a forma de comercialização.
Por exemplo, será considerado que o queijo meia cura foi comprado já ralado e que o
pacote de polvilho doce é de 500g. Mas o sal teria de ser pesado e o leite e óleo teriam de
ser medidos para .

Tabela 2.2 - Ingredientes não ambíguos da Receita de Pão de Queijo


Ingredientes Comentário

- 500g de polvilho doce; # pacote de 500g


- 10g sal; # Quantidade extraída de pacote de 1 kg
- 300 ml de leite # Quantidade extraída de saco de 1l.
- 200 ml de óleo # Quantidade extraída de garrafa de 1l.
- 2 ovos de galinha # Quantidade extraída de caixa com 12
- 400g de queijo ralado # Quantidade comprada a granel (minas meia cura)

32
Introdução à Programação com Python

Observe que não está sendo dada mais a opção de usar sal ou tempero. A receita
usa apenas sal e em quantidade específica (10g). Se esta quantidade de sal deixará os
pães de queijo sem sal ou muito salgados, o autor não faz ideia. Mas, não tem mais a
ambiguidade de botar sal a gosto. Ou usar outro tempero no lugar do sal. Sempre que
forem usados estes ingredientes não ambíguos, a sensação de salgado do resultado será a
mesma, para uma mesma pessoa.

Outro detalhe é que em um algoritmo, assim como nas linguagens de programação,


é possível adicionar comentários, que não fazem parte do algoritmo em si, mas ajudam a
documentá-lo. Na tabela 2.2, o caractere # foi usado para identificar o início de um
comentário: tudo o que vem após o #, na mesma linha, não faz parte da lista de
ingredientes, mas auxilia um cozinheiro inexperiente a saber como adquirir ou como usar
aquele ingrediente. Os comentários são muito úteis como parte da documentação dos
algoritmos (e programas), facilitando o entendimento por outras pessoas que tiverem
acesso ao algoritmo (código) e ajudando ao próprio autor do algoritmo (código) a lembrar
detalhes de sua criação.

2.4.2. Refinamento do Algoritmo

Algumas ações também possuem ambiguidades ou não estão definidas com o grau
de detalhamento para permitir que a receita seja feita sem nenhum problema. Considere,
por exemplo, a ação número 5 “Acrescente os ovos, um a um, alternando com o queijo e
sovando bem, até a massa ficar homogênea, após cada adição”. Claramente existem mais
de uma ação neste passo 5, a saber: acrescentar ovo, acrescentar queijo, sovar e verificar
se a massa está homogênea.

Uma possível ambiguidade estaria no verbo “sovar” que, eventualmente, não seria
entendida por algumas pessoas sem a consulta a um dicionário. No algoritmo será feita a
substituição do verbo “sovar” pelo verbo “bater” explicitando que esta ação deve ser
realizada na batedeira. Esta explicitação poderá ser feita com a colocação de comentários
no algoritmo. Um comentário será sempre precedido do caractere “#”, para indicar que não
se trata de um comando.

O detalhamento de uma operação para eliminação de ambiguidade ou para


quebrá-la em duas ou mais ações é chamado de refinamento. A técnica de refinamento
deve ser aplicada tantas vezes quantas forem necessárias, para que, ao final, o algoritmo
contenha apenas operações triviais. Esta técnica é conhecida como refinamento sucessivo
do algoritmo.

A Figura 2.1 apresenta uma segunda versão, primeiro refinamento do algoritmo


(modo de preparo) considerando os ingredientes já definidos na Tabela 2.2, com o
detalhamento das operações ou ações, em particular, da ação 5 da versão 1, que descreve

33
Introdução à Programação com Python

que deve os ovos devem ser acrescentados um a um e alternado com o queijo. Como na
receita são dois ovos, o acréscimo de queijo ralado será feito em duas partes de 200g.

Modo de Preparo
1. Coloque 500g de polvilho em uma tigela grande.
2.1 Misture em uma panela 10g de sal, 300ml de leite e 150ml de óleo.
2.2. Aqueça a mistura até ferver
3.1. Jogue a mistura fervendo sobre o polvilho
3.2. Mexa até desfazer as pelotinhas.
4. Deixe esfriar por 20 minutos.
5.1. Acrescente um ovo
5.2. Acrescente 200g de queijo ralado
5.3. Bata até a mistura ficar homogênea
5.4. Acrescente um ovo
5.5. Acrescente 200g de queijo ralado
5.6. Bata até a mistura ficar homogênea
6. Unte as mãos com óleo, se necessário.
7. Enrole bolinhos de 2 cm de diâmetro e coloque-os em uma assadeira untada.
8. Leve ao forno médio (180º C), preaquecido.
9. Asse até ficarem douradinhos.
Figura 2.1 - Algoritmo versão 2

Note que a versão 2 já está mais detalhada com o refinamento das ações 2, 3 e 5 e,
como consequência, o número de ações quase dobrou. Entretanto, algumas ações ainda
não estão definidas como ações únicas, o que dificultaria a execução do algoritmo por parte
de um robô. Por exemplo, a ação 2 que já foi desmembrada nas ações 2.1 e 2.2 poderia ser
mais refinada ainda, nas seguintes ações mostradas na Figura 2.2.

2.1.1. Coloque 300ml de leite na panela


2.1.2. Acrescente 150ml de óleo na panela.
2.1.3. Acrescente 10g de sal
2.1.4.. Misture os ingredientes na panela
2.2.1. Acenda uma das trempes do fogão
2.2.2. Coloque a panela com a mistura na trempe acesa
2.2.3. Aqueça a mistura até ferver
Figura 2.2 - Algoritmo versão 2

A versão 3 do algoritmo apresenta todas as ações refinadas, explicitando ações que


antes estavam implícitas, como acender uma das trempes no passo 2 e ligar o forno para
que ele esteja pré-aquecido no momento de executar a ação 8. Está sendo suposto que o
tempo de pré-aquecimento é o tempo que se gastaria para enrolar os pães de queijo e
colocá-los no tabuleiro. Acender o forno para o pré-aquecimento foi inserida como a

34
Introdução à Programação com Python

operação de número 6 e, consequentemente, forçou a renumeração das ações seguintes. A


Figura 2.3 apresenta a versão 3 do algoritmo.

Modo de Preparo
1. Coloque 500g de polvilho em uma tigela grande.
2.1.1. Coloque 300ml na panela
2.1.2. Acrescente 150ml de óleo na panela.
2.1.3. Acrescente 10g de sal
2.1.4.. Misture os ingredientes na panela
2.2.1. Acenda uma das trempes do fogão
2.2.2. Coloque a panela com a mistura na trempe acesa
2.2.3. Aqueça a mistura até ferver
3.1. Jogue a mistura fervendo sobre o polvilho
3.2. Mexa até desfazer as pelotinhas.
4. Deixe esfriar por 20 minutos.
5.1. Acrescente um ovo
5.2. Acrescente 200g de queijo ralado
5.3. Bata até a mistura ficar homogênea
5.4. Acrescente um ovo
5.5. Acrescente 200g de queijo ralado
5.6. Bata até a mistura ficar homogênea
6. Acenda o forno para pré-aquecimento
7. Unte as mãos com óleo, se necessário.
8.1 Untar uma assadeira
8.2 Enrole bolinhos de 2 cm de diâmetro
8.3 Coloque-os em uma assadeira untada.
9. Leve a assadeira ao forno médio (180º C).
10. Asse até ficarem douradinhos.
Figura 2.3 - Algoritmo versão 3

Embora esteja sendo usada a numeração, ela é dispensável. Como se está


tratando de estrutura de comandos sequenciais, é suposto que os comandos serão
executados na sequência em que eles foram escritos, linha após linha, uma linha de cada
vez. Porém, será mantida a numeração por mais algum tempo.

2.5 - Estrutura de comando condicional

A versão 3 do algoritmo apresentado na Figura 2.3 possui apenas comandos


sequenciais. Entretanto, existe pelo menos um comando que implicitamente é uma estrutura
condicional: “7. Unte as mãos com óleo, se necessário”. Note que existe uma condição para
que o operador humano unte as mãos. A pessoa só deve untar as mãos se necessário.
Note que na lista de ingredientes, a quantidade de óleo é de 200ml e para a mistura são
necessários 150 ml. Desta forma, os 50 ml restantes poderiam ser usados para untar as

35
Introdução à Programação com Python

mãos. Mas somente, se necessário. Portanto, é preciso ter uma estrutura que permita
executar condicionalmente uma ação.

Um comando condicional é uma estrutura das linguagens de programação na qual


existe um teste de uma condição que é feito antes de executar o comando. O comando
somente será executado no caso da condição testada ser verdadeira. A forma geral de um
comando condicional é a mostrada na Figura 2.4.

se <condição>
<Comando>
Figura 2.4 - Estrutura do comando condicional

A <condição> representa a condição a ser verificada ou o teste a ser feito. O


resultado do teste da condição só pode ter dois valores: verdadeiro ou falso. <Comando>
representa o comando que será executado somente no caso do resultado do teste ter sido
verdadeiro. Note que <Comando> está deslocado para a direita indicando que sua
execução está vinculada à cláusula “se”, que corresponde ao caso da condição testada ser
verdadeira. Este deslocamento é chamado de indentação.

O <Comando> pode ser, na verdade, um bloco com um ou mais comandos, onde


todos os comandos do bloco seriam executados somente quando o teste for verdadeiro.

De acordo com a regra de indentação, o próximo comando, após o comando


condicional, deve ser escrito alinhado com o “se”. Isso indica a sequência de execução do
programa. Desta forma, um comando condicional nada mais seria do que um comando
sequencial, mas que só será executado quando a condição avaliada for verdadeira. Em
outras palavras, a condição sempre é testada (característica de comando sequencial), mas
o bloco de comandos condicionais será executado apenas quando o resultado do teste for
verdadeiro.

No caso do algoritmo em discussão, o teste a ser feito é verificar se a massa do pão


de queijo ficou grudenta (ou não). Se a massa estiver grudenta (resultado verdadeiro), é
necessário que a mão seja untada de óleo para a massa não ficar agarrando na palma da
mão, enquanto cada pão de queijo vai sendo enrolado. No caso do teste ser falso (massa
não ficou grudenta), a ação de untar a mão não será executada, pois não é necessária. A
Figura 2.4 mostra como ficaria o comando 7 da versão 3 do algoritmo.

7. se “massa está grudenta”:


7.1. Unte as mãos com óleo
Figura 2.5 - Exemplo de comando condicional

Em alguns casos é desejado executar uma ação no caso da condição ser verdadeira
ou uma ação diferente no caso da ação ser falsa. Isto não é possível com a estrutura da

36
Introdução à Programação com Python

Figura 2.3 onde existe apenas um comando (ou bloco de comandos) que só é executado no
caso do teste ser verdadeiro. Quando o teste é falso, passa-se para a execução do próximo
comando sequencial (comando 8, no caso do algoritmo da Figura 2.3).

A Figura 2.6 apresenta a estrutura do comando condicional que também permite a


especificação de um comando (ou bloco de comandos) associados ao resultado negativo do
teste.
se <condição>
<comando1>
senão
<comando2>
Figura 2.6 - Estrutura de comando condicional com cláusula “senão”

Para este tipo de comando condicional, se a condição for verdadeira apenas o


<comando1> será executado e se a condição for falsa apenas o <comando2> será
executado. Como o resultado do teste só pode assumir estes dois valores (verdadeiro ou
falso), <comando1> e <comando2> nunca serão executados juntos. Ou <comando1> será
executado (se condição for verdadeira) ou <comando2> será executado (caso contrário ou
se condição for falsa).

A cláusula “senão” deixa explícito que o <comando2> está associado ao caso da


condição ser falsa. Note que tanto o comando (ou bloco de comandos) vinculados ao caso
do teste verdadeiro (cláusula “se”), como o comando (ou bloco de comandos) do teste falso
(cláusula “senão”) ficam deslocados para a direita, indicando a vinculação ao respectivo
resultado do teste (verdadeiro ou falso).

Este deslocamento (indentação) aparecerá também nos comandos repetitivos que


serão vistos na próxima seção. A indentação é importante para deixar claro quais são os
comandos que pertencem a cada bloco. Algumas linguagens de programação são mais
exigentes com a indentação, como é o caso da linguagem Python, conforme será visto a
partir do capítulo 3.

No algoritmo versão 3 ainda há uma ambiguidade que será resolvida para


exemplificar o uso da estrutura de comando condicional da Figura 2.6. A ação “5.1. Adicione
um ovo” para ser executada por um robô não estaria suficientemente detalhada e poderia
resultar em uma massa com fragmentos de casca de ovo. Além disso, para quem costuma
fazer ovo frito ou omelete, já pode ter passado pela experiência de quebrar um ovo choco.
Desta forma um refinamento necessário seria incluir uma condição para testar se o ovo
pode ser usado ou não, como mostrado na Figura 2.7.

No exemplo da Figura 2.7, se o teste for verdadeiro o bloco de dois comandos


(“Jogue o ovo na lixeira” e “Lave a tigela pequena”) será executado. Se o teste for falso,
apenas o comando “Adicione o ovo da tigela pequena” será executado. Note que a
numeração do primeiro comando de cada bloco é a mesma (5.1.3.1.), exatamente porque
um dos dois será executado logo após o teste feito (5.1.3). Cada teste realizado na cláusula

37
Introdução à Programação com Python

“se”, na verdade, é uma execução de operação feita pelo processador, quando se trata de
um programa.

5.1.1. Quebre um ovo em uma tigela pequena


5.1.2. Jogue a casca do ovo na lixeira
5.1.3. se “ovo está choco”
5.1.3.1. Jogue o ovo na lixeira
5.1.3.2. Lave a tigela pequena
senão
5.1.3.1. Adicione o ovo da tigela pequena
Figura 2.7 - Exemplo de comando condicional com cláusula “senão”

Importante chamar a atenção, mais uma vez, que a sequência de ações sempre é
importante para se chegar à solução correta do problema. Quebrar o ovo na tigela e jogar a
casca fora são tarefas que sempre tem que ser feitas. Portanto são comandos sequenciais.
E devem ser executadas na ordem em que foram escritas! Se inverter a ordem… a massa
não terá ovos.

Também é importante distinguir tarefas (ou ações) que são sequenciais das tarefas
condicionais. Escrever uma mesma ação no bloco “se” e também no bloco “senão” é um
erro do ponto de vista lógico. Considere, por exemplo, que o trecho de algoritmo mostrado
na figura 2.7 fosse reescrito assim:

5.1.1. Quebre um ovo em uma tigela pequena


5.1.2. se “ovo está choco”
5.1.2.1. Jogue a casca do ovo na lixeira
5.1.2.2. Jogue o ovo na lixeira
5.1.2.2. Lave a tigela pequena
senão
5.1.2.1 Jogue a casca do ovo na lixeira
5.1.2.2. Adicione o ovo da tigela pequena
Figura 2.8 - Erro de uso de ação sequencial em comando condicional

A ação “Jogue a casca do ovo na lixeira” será executada sempre, independente do


resultado da condição testada. E, de fato, a casca do ovo sempre deve ser descartada.
Logo, é uma ação sequencial e não deve estar em um comando condicional. Muitos
programadores inexperientes costumam cometer este tipo de erro, replicando blocos de
comandos, às vezes enormes, nas duas cláusulas (se/senão) de um comando condicional.

As estruturas de comando condicional podem ser mais poderosas, permitindo a


inclusão de outras cláusulas de teste. Porém, para solucionar o problema de gerar um
algoritmo para a receita de pão de queijo, as duas estruturas apresentadas são suficientes.
Algumas linguagens de programação implementam essas estruturas de comando

38
Introdução à Programação com Python

condicional compostas, como é o caso da linguagem Python. Essas estruturas serão


apresentadas no Capítulo 5.

2.6 - Estrutura de comando repetitivo

No algoritmo, versões 2 e 3 existe uma sequência de 3 ações que é repetida duas


vezes, relacionada com a adição do ovo na receita: “Acrescente um ovo”; “Acrescente 200g
de queijo ralado”; e “Bata até a mistura ficar homogênea”. Imagine se a receita precisasse
de 10 ovos ao invés de 2 ovos. Ou, em outro problema, em que uma tarefa tivesse que ser
executada 1.000 vezes. O algoritmo ficaria imenso.

Para resolver este problema utiliza-se a estrutura do comando repetitivo Enquanto,


mostrada na Figura 2.9. Apesar de ter sido utilizada uma marcação de final do comando
repetitivo, o <comando> deve ser deslocado à direita, seguindo a regra de indentação de
blocos.

Enquanto <condição>
<comando>
Fim_Enquanto
Figura 2.9 - Estrutura de comando repetitivo Enquanto

A <condição> é avaliada antes da execução do comando e, assim como no caso do


comando condicional, o resultado da avaliação só pode ser verdadeiro ou falso. No caso do
resultado ser verdadeiro, o <comando> (ou bloco de comandos) é executado uma vez.
Após a execução, chegando ao fim do comando repetitivo (marcado pelo “Fim_Enquanto),
volta-se ao teste da condição que é feito novamente. No caso do resultado do teste ser
verdadeiro, novamente, o comando repetitivo será executado pela segunda vez. Esta
execução se repetirá enquanto a condição testada continuar dando resultado verdadeiro.

Quando o resultado da condição testada é falso, o comando repetitivo termina,


passando para a execução do próximo comando sequencial. Caso o teste da condição dê
resultado falso na primeira vez, o comando repetitivo não será executado. Portanto, esta
estrutura fará com que o comando repetitivo seja executado zero ou mais vezes.

Muitas vezes é necessário definir (ou inicializar) uma informação de controle para
forçar a entrada no comando repetitivo e, dentro do bloco de comandos repetitivos modificar
a condição de controle para que o número de repetições do comando seja o desejado.

Considerando as 3 ações (“Acrescente um ovo”; “Acrescente 200g de queijo ralado”;


e “Bata até a mistura ficar homogênea”) que tem que ser executadas 2 vezes, a informação
de controle será o número de ovos adicionados na receita. Inicialmente, o número de ovos
na receita é igual a zero e a cada vez que um ovo for acrescentado, o número de ovos da

39
Introdução à Programação com Python

receita deve ser incrementado. A Figura 2.10 mostra um exemplo com um comando
repetitivo para o caso do algoritmo do pão de queijo.

NumeroDeOvosNaReceita = 0
Enquanto NumeroDeOvosNaReceita < 2
Acrescente um ovo
Acrescente 200g de queijo ralado
Bata até a mistura ficar homogênea
Incremente(NumeroDeOvosNaReceita)
Fim_Enquanto
Figura 2.10 - Exemplo de uso do comando repetitivo Enquanto

Note que a operação “NumeroDeOvosNaReceita = 0” define um valor que garante


que o teste “NumeroDeOvosNaReceita < 2” será verdadeiro na primeira vez que for testada.
Com isso o bloco de comandos repetitivos será executado pelo menos uma vez. E o último
comando do bloco repetitivo “Incremente(NumeroDeOvosNaReceita)” leva a informação de
controle “NumeroDeOvosNaReceita” para o valor 1. Este novo valor ainda fará com que o
teste “NumeroDeOvosNaReceita < 2” continue sendo verdadeiro. Logo, o bloco de
comandos dentro do comando repetitivo será executado pela segunda vez, com o valor da
informação de controle sendo incrementado, novamente, pelo último comando do bloco e
assumindo o valor 2. Com este valor, agora o teste “NumeroDeOvosNaReceita < 2” será
falso. Portanto, o comando repetitivo será executado 2 vezes.

Um cuidado com este tipo de estrutura repetitiva é exatamente com a inicialização


do valor da informação de controle que deve ocorrer sempre antes do comando repetitivo. E
também com a atualização do valor da informação de controle dentro do bloco de
comandos repetitivos. Suponha, por exemplo, que na Figura 2.9 seja retirado o comando
““Incremente(NumeroDeOvosNaReceita)”. O que aconteceria?

O comando repetitivo seria executado para sempre, pois o valor inicial da variável de
controle “NumeroDeOvosNaReceita”, não sendo mais incrementado, se manteria sempre
em 0. Desta forma, o teste da condição seria sempre verdadeiro também, o que implicaria
na execução do bloco repetitivo para sempre. No caso da receita, um operador humano
poderia perceber que há algo errado, pois foram reservados apenas 2 ovos e 400g (ou 2
porções de 200g) de queijo ralado. Logo, não existiriam ingredientes para executar as
ações, a partir da terceira execução. Porém, no caso de um programa, às vezes é difícil de
perceber que o programa entrou neste ciclo infinito.

Existe uma outra estrutura de comando repetitivo voltada para situações onde já se
sabe a priori o número de execuções que se pretende. Esta estrutura é mostrada na Figura
2.11. Nesta estrutura o valor de controle faz parte do comando, com definição do valor
inicial e do valor final no cabeçalho do comando. Além disso, o incremento da informação
de controle é automático. A estrutura deste novo tipo de comando repetitivo é apresentado
na Figura 2.11, mostrada a seguir.

40
Introdução à Programação com Python

para controle = <valor inicial> até <valor final>


<comando>
fim_para
Figura 2.11 - Estrutura de comando repetitivo para

Para o exemplo do algoritmo do pão de queijo, o comando repetitivo da Figura 2.10


pode ser reescrito usando a estrutura do comando repetitivo “para”.

para NumeroDeOvosNaReceita = 0 até 2


Acrescente um ovo
Acrescente 200g de queijo ralado
Bata até a mistura ficar homogênea
fim_para
Figura 2.12 - Exemplo de uso do comando repetitivo para

Neste tipo de estrutura o valor inicial da variável de controle “NumeroDeOvosNa


Receita” terá valor inicial igual a zero e será incrementado automaticamente ao final do
bloco de comandos repetitivos. Quanto o valor chegar a 2, o comando repetitivo termina.
Nesta notação se supõe que para o valor final, o comando não será executado. Assim, o
comando será repetido 2 vezes, para os valores da variável de controle iguais a 0 e 1.
Dependendo da linguagem de programação, esta suposição pode não ser válida.
Entretanto, para a linguagem Python que será usada nos capítulos seguintes, o significado
do comando repetitivo no estilo “para” é exatamente a descrita aqui.

2.7. Comandos aninhados e rastreio do algoritmo

Conforme foi dito anteriormente, as três estruturas de comando vistas nas seções
anteriores (sequencial, condicional e repetitiva) são suficientes para escrever qualquer
programa. Em geral, uma descrição de alto nível (ou primeira versão) do algoritmo poderia
conter apenas comandos sequenciais. Entretanto, ao detalhar a solução, alguns comandos
que pareciam ser sequenciais são quebrados em dois ou mais comandos e, eventualmente,
em comandos condicionais ou comandos repetitivos.

Neste ponto, é importante ressaltar que é possível utilizar comandos condicionais e


repetitivos aninhados, ou seja, um dentro do outro. Para exemplificar esta utilização,
considere a estrutura definida na Figura 2.10 que utilizou a forma do comando repetitivo
“Enquanto”. Note que a operação de acrescentar um ovo não considera a possibilidade de
ter um ovo choco, como o refinamento apresentado na Figura 2.7. Note que para este caso,
a estrutura do comando repetitivo “Enquanto” é mais adequada do que a estrutura do
comando repetitivo “para”, pois não se sabe a priori se há algum ovo choco.

41
Introdução à Programação com Python

Há também, na Figura 2.10, um comando repetitivo implícito, ou que não foi refinado
ainda: “Bata até a mistura ficar homogêneo”. A operação que é possível executar é bater a
massa usando uma batedeira, enquanto que o “até a mistura ficar homogênea” nada mais é
do que um teste visual para aferir se a operação bater deve prosseguir ou não. A Figura
2.13 apresenta o trecho do algoritmo com os refinamentos discutidos nesta seção.

NumeroDeOvosNaReceita = 0
Enquanto NumeroDeOvosNaReceita < 2
Quebre um ovo em uma tigela pequena
Jogue a casca do ovo na lixeira
se “ovo está choco”
Jogue o ovo na lixeira
Lave a tigela pequena
senão
Adicione o ovo da tigela pequena
Incremente(NumeroDeOvosNaReceita)
Acrescente 200g de queijo ralado
Enquanto “mistura não estiver homogênea”
Bata a mistura
Fim_Enquanto
Fim_Enquanto
Figura 2.13 - Refinamento de parte do algoritmo com comandos aninhados

Note que dentro do comando repetitivo principal existem dois comandos sequenciais
(“Quebre um ovo em uma tigela pequena” e “Jogue a casca do ovo na lixeira”) que são
executados sempre que se entra no comando repetitivo. O que é razoável, pois todo ovo
precisa ser quebrado na tigela pequena e ter sua casca descartada na lixeira.

O terceiro comando é um comando condicional no qual será verificado se o ovo está


choco (impróprio para ser usado na receita). Se o teste for verdadeiro, apenas o bloco
associado à cláusula verdadeira será executado: jogar o ovo choco na lixeira e lavar a tigela
pequena. Caso contrário (senão), ou seja, caso o teste seja falso (ovo não choco) o bloco
de comandos associados à cláusula “senão” será executado: adicionar o ovo, incrementar a
variável de controle, acrescentar queijo e bater a mistura até ficar homogênea.

A Figura 2.14 destaca as duas possibilidades de fluxo de execução do trecho do


algoritmo da Figura 2.13. Do lado esquerdo, o fluxo de execução quando o teste da
condição “ovo choco” é verdadeiro. As ações (ou instruções) que não serão executadas
foram colocadas em cor cinza. Do lado direito o fluxo de ações executadas no caso do teste
“ovo choco” ser falso. Novamente, as instruções que não serão executadas foram pintadas
de cinza. Esta análise da estrutura do algoritmo e seus possíveis fluxos de execução dos
comandos é fundamental para executar a tarefa de rastreio do algoritmo.

42
Introdução à Programação com Python

NumeroDeOvosNaReceita = 0 NumeroDeOvosNaReceita = 0
Enquanto NumeroDeOvosNaReceita < 2 Enquanto NumeroDeOvosNaReceita < 2
Quebre um ovo em uma tigela pequena Quebre um ovo em uma tigela pequena
Jogue a casca do ovo na lixeira Jogue a casca do ovo na lixeira
se “ovo está choco” se “ovo está choco”
Jogue o ovo na lixeira Jogue o ovo na lixeira
Lave a tigela pequena Lave a tigela pequena
senão senão
Adicione o ovo da tigela pequena Adicione o ovo da tigela pequena
Incremente(NumeroDeOvosNaReceita) Incremente(NumeroDeOvosNaReceita)
Acrescente 200g de queijo ralado Acrescente 200g de queijo ralado
Enquanto “mistura não homogênea” Enquanto “mistura não homogênea”
Bata a mistura Bata a mistura
Fim_Enquanto Fim_Enquanto
Fim_Enquanto Fim_Enquanto

a) “ovo choco” é verdadeiro b) “ovo choco” é falso.

Figura 2.14 - Possíveis fluxos de execução dependendo da condição “ovo está choco”

Para verificar se o algoritmo está correto ou apresentando o comportamento


esperado podemos simular a sua execução. Para tanto, será necessário supor o
fornecimento de valores de entrada para a execução de cada operação do algoritmo e a
verificação das eventuais modificações no estado de cada objeto do algoritmo. A esta
simulação da execução é dado o nome de rastreio. O rastreio pode ser aplicado para um
algoritmo ou para um programa.

Suponha que no momento de adicionar os ovos na receita, o primeiro ovo estará


bom, mas o segundo estará choco. Isso demandará um terceiro ovo que, em nossa
simulação, estará bom. Além dos ovos, as porções de queijo ralado estarão também à
disposição. Os ovos e as porções de queijo são as entradas necessárias para a execução
do trecho do algoritmo da figura 2.13. Para realizar o rastreio vamos analisar a sequência
de comandos que serão executados para os nossos dados de entrada.

Observe que o primeiro comando (NumeroDeOvosNaReceita = 0) será sempre


executado pois trata-se de um comando sequencial e atribui o valor zero para o número de
ovos já adicionados à receita.

O segundo comando é um comando repetitivo que será executado enquanto o


número de ovos na receita for menor do que 2. No estado atual, no qual o número de ovos
na receita é zero, o bloco de comandos repetitivos será executado.

Os dois primeiros comandos, dentro do bloco repetitivo, são sequenciais. Portanto,


eles sempre serão executados, para quebrar o ovo e colocá-lo em uma tigela para testá-lo,
no comando seguinte.

43
Introdução à Programação com Python

Na nossa simulação o primeiro ovo está bom (não choco) e o bloco a ser executado
no comando condicional é o bloco “senão”, no qual o ovo será adicionado juntamente com
uma porção de queijo ralado e misturados até que a mistura fique homogênea, conforme
detalhado na Figura 2.14.b. Porém, o comando mais importante do ponto de vista do
rastreio é o que faz o incremento do número de ovos na receita que passará de 0 (zero)
para 1. Este comando é o que poderá, em algum momento, tornar a condição do comando
repetitivo principal (NumeroDeOvosNaReceita < 2) falsa. E quando terminar o comando de
tornar a mistura homogênea, o fluxo de execuções voltará para realizar um novo teste da
condição do comando repetitivo.

Neste momento será verificado que o número de ovos na receita ainda é menor do
que 2 e, neste caso, a condição continua verdadeira e o bloco de comandos repetitivos será
executado mais uma vez.

Agora, na nossa simulação, o segundo ovo está choco. Neste caso, o fluxo de
execução dos comandos será aquele mostrado na Figura 2.14.a. Novamente, os 2
primeiros comandos serão executados para quebrar o ovo e colocá-lo em uma tigela e
testá-lo, no próximo comando. Para este segundo ovo, que está choco, a condição “ovo
está choco” será verdadeira, ocasionando a execução do bloco “se”, que fará com que o
ovo choco seja jogado na lixeira e a tigela lavada para receber um próximo ovo.

O terceiro ovo, em nossa simulação, está bom (não choco), o que levará à execução
do bloco “senão” do comando condicional, com a adição de mais um ovo e outra porção de
queijo, para serem misturados até que a massa fique homogênea novamente. E,
novamente, o NumeroDeOvosNaReceita será incrementado e passará de 1 para 2.

Terminada a execução do bloco de comandos repetitivos, o teste do comando


repetitivo principal será executado mais uma vez, agora com NumeroDeOvosNaReceita
com valor igual a 2. Agora, a condição “NumeroDeOvosNaReceita < 2” será falsa, fazendo
com que o comando repetitivo termine e, consequentemente, terminando o nosso rastreio..

O rastreio de algoritmos e programas é uma atividade muito recomendada para o


aprendizado de programação. Através desta técnica o programador pode verificar a
correção do programa ou de um trecho específico de seu programa. Até mesmo
programadores experientes utilizam esta técnica.

Com o passar do tempo, será notado que a análise dos possíveis fluxos de
execução não precisa ser tão detalhada. Por exemplo, os comandos que alteram o estado
de uma variável de controle são muito mais importantes do que alguns comandos
sequenciais. Por exemplo, se o comando “Jogue a casca do ovo na lixeira” fosse omitido do
rastreio não faria a menor diferença para o entendimento da solução. Mas o valor inicial e
os incrementos da variável “NumeroDeOvosNaReceita” usada na condição do comando
repetitivo e a própria expressão da condição do comando repetitivo são os itens mais
importantes para entender quando o comando repetitivo iria terminar.

44
Introdução à Programação com Python

Suponha que na condição do comando repetitivo o programador trocasse o sinal de


menor (<) pelo sinal de maior (>), ficando “Enquanto NumeroDeOvosNaReceita > 2”, o que
aconteceria com a execução do algoritmo? Neste caso, como a condição seria falsa já no
primeiro teste, o bloco de comandos repetitivos não seria executado e teríamos uma receita
sem os 2 ovos e sem queijo.

E o que aconteceria para o caso da condição estar correta, como na figura 2.14,
mas o programador se esquecesse do comando “Incremente(NumeroDeOvosNaReceita)”
no bloco “senão” do comando condicional? Neste segundo caso, o valor da variável
“NumeroDeOvosNaReceita” ficaria sempre com o valor 0 (zero) e o comando repetitivo não
terminaria (loop infinito). Teríamos que ter infinitos ovos e uma quantidade infinita de queijo.

Considere, ainda, uma terceira situação na qual o programador pensasse em contar


todos os ovos, tirando o comando “Incremente(NumeroDeOvosNaReceita)” do bloco
“senão” do comando condicional e o colocasse no bloco de comandos sequenciais, antes
do comando condicional, conforme detalhado no exercício 5 deste capítulo. O que poderia
acontecer com o algoritmo? Faça as suas considerações resolvendo o exercício proposto.

2.8. Viva a diferença

Um aspecto final a ser ressaltado é que há maneiras diferentes de se analisar o


problema que leva a algoritmos diferentes, mas que não estão necessariamente errados.
Aliás, uma das belezas da programação é permitir diferentes soluções para um mesmo
problema.

Para NumeroDeOvosNaReceita = 0 até 2


Quebre um ovo em uma tigela pequena
Jogue a casca do ovo na lixeira
Enquanto “ovo estiver choco”
Jogue o ovo na lixeira
Lave a tigela pequena
Quebre um ovo em uma tigela pequena
Jogue a casca do ovo na lixeira
Fim_Enquanto
Adicione o ovo da tigela pequena
Acrescente 200g de queijo ralado
Enquanto “mistura não estiver homogênea”
Bata a mistura
Fim_Enquanto
Fim_Para
Figura 2.15 - Outra versão para o algoritmo com comandos aninhados

45
Introdução à Programação com Python

Neste formato, o comando principal é um comando repetitivo no estilo “para” que


será executado 2 vezes, de acordo com os valores inicial e final da variável de controle
“NumeroDeOvosNaReceita”. Porém, no primeiro comando repetitivo “enquanto”, aninhado
no comando “para”, seu teste verifica se o ovo está choco.

No caso do resultado do teste ser positivo, os dois primeiros comandos do bloco


repetitivo tratam do descarte do ovo choco (“Jogue o ovo na lixeira” e “Lave a tigela
pequena”) e os dois seguintes repetem a ação de pegar um novo ovo (“Quebre um ovo em
uma tigela pequena” e “Jogue a casca do ovo na lixeira”), que foi executada antes de entrar
no comando repetitivo “enquanto”. Ao terminar o bloco de comando repetitivo, volta-se ao
teste da condição (Enquanto “ovo estiver choco”). Ou seja, enquanto não for obtido um ovo
bom, o algoritmo continuará executando o bloco de comandos repetitivos, descartando o
ovo choco e pegando outro ovo.

2.9. Uma ferramenta de rastreio de programas

A tarefa de rastreio é tão importante que alguns ambientes de desenvolvimento de


código trazem opções para ajudar a realizar esta tarefa. Como na disciplina INF 100 o
nosso ambiente de programação é muito simples, recomendamos o uso de uma ferramenta
que ajuda a verificar a execução de código Python.

A página do “Python Tutor” disponível em https://pythontutor.com/ permite escrever


(ou copiar) um código Python e simular a sua execução passo a passo. Na verdade, é
possível trabalhar com diferentes linguagens de programação, dentre elas a linguagem
Python. O uso do Python Tutor é bem intuitivo para quem já aprendeu os primeiros
comandos da linguagem Python.

2.10. Exercícios

1. Identifique os comandos no Algoritmo do pão de queijo que ainda não estão refinados e
refine-os.

2. Escreva o algoritmo completo e refinado para fazer pão de queijo.

3. Escreva um algoritmo para trocar um pneu de um carro.

4. Escreva um algoritmo para escolher entre três opções possíveis qual o melhor
apartamento para ser alugado para uma república de 5 pessoas, considerando as
características descritas a seguir.

46
Introdução à Programação com Python

Características Apartamento 1 Apartamento 2 Apartamento 3

Quartos (incluindo as suítes) 3 3 4

Suites 1 1 2

Vaga Garagem 1 0 1

Andar 1 4 8

Banheiros (incluindo os da suíte) 2 2 3

Elevador Não Sim Sim

Frente p/ rua Sim Não Não

Valor aluguel (R$) 1.200,00 1.350,00 1.700,00

Valor Condomínio (R$) 400,00 590,00 550,00

5. Considere o trecho de algoritmo mostrado a seguir, correspondendo à modificação


proposta no último parágrafo deste capítulo:

NumeroDeOvosNaReceita = 0
Enquanto NumeroDeOvosNaReceita < 2
Quebre um ovo em uma tigela pequena
Jogue a casca do ovo na lixeira
Incremente(NumeroDeOvosNaReceita)
se “ovo está choco”
Jogue o ovo na lixeira
Lave a tigela pequena
senão
Adicione o ovo da tigela pequena
Acrescente 200g de queijo ralado
Enquanto “mistura não homogênea”
Bata a mistura
Fim_Enquanto
Fim_Enquanto

Sabendo que a receita precisa sempre de 2 ovos bons (não chocos), descreva o que
aconteceria nas seguintes situações, considerando cada uma delas de maneira isolada:
a) Os dois primeiros ovos estão bons.
b) O primeiro ovo está choco e o segundo e terceiro ovos estão bons.
c) O primeiro ovo está bom, o segundo ovo está choco e o terceiro ovo está bom.
d) Os dois primeiros ovos estão bons e o terceiro e quarto ovos estão bons.

47
Introdução à Programação com Python

Capítulo 3 - Variáveis e Operadores

3.1 - Variáveis

As variáveis, em Python, são nomes ou identificadores usados dentro dos


programas para nos referirmos aos objetos necessários para a realização do
processamento. Conforme visto no algoritmo não computacional no Capítulo 2, as variáveis
seriam os nossos ingredientes da receita para realizar a implementação do algoritmo e
chegar ao resultado desejado (pães de queijo).

Para cada nome ou identificador definido no programa Python, algum espaço da


memória principal (memória RAM) será reservado para armazenar seu valor. A memória de
um computador pode ser representada por uma estrutura uni ou bidimensional de bytes. Um
byte é composto de 8 bits e cada bit pode assumir apenas os valores 0 ou 1, chamados de
valores binários. O nome BIT vem do termo em inglês (BInary digiT). Internamente, o
computador trabalha com a representação binária por ser uma forma mais fácil de
representar. Por exemplo, na codificação elétrica uma tensão alta (+5 Volts) representaria o
bit 1 e a uma tensão baixa (0 Volts) representaria o bit 0. Da mesma forma, um material
magnético com polarização negativa e positiva pode ser usado para representar 0 ou 1,
respectivamente, como é feito em discos rígidos.

Figura 3.1 - Representação de variáveis na memória RAM

Na Figura 3.1 a memória principal está representada como uma estrutura


bidimensional de bytes e são representadas duas variáveis: idade e nome cujos valores são
respectivamente 40 e ‘Maria’. Idade é uma variável numérica que ocupa 4 bytes e nome é
uma variável do tipo texto (string) que ocupa 5 bytes, um byte para cada caractere.

48
Introdução à Programação com Python

Internamente a variável idade poderia ter o seu valor 00000000 00000000 00000000
00101000 que corresponde ao valor 40 escrito na notação binária (base 2). Por que lemos
40 como quarenta? Exatamente porque consideramos implicitamente que o número está
representado na base 10, onde os dígitos são 0, 1, 2, 3, 4, 5, 6, 7, 8 e 9. Usando a base 10,
o número 40 pode ser desmembrado como:
4𝑥10¹ + 0𝑥10⁰ = 4𝑥10 + 0𝑥1 = 40 + 0 = 40

Da mesma forma, na notação binária podemos escrever o número 101000


desmembrado. Porém, por se tratar de número binário os únicos dígitos possíveis são 0 e 1.
Os 26 zeros à esquerda do primeiro bit 1 (na posição mais significativa) foram desprezados.
Usando, então, a base 2 para desmembrar o número 101000 obteríamos:

1𝑥2⁵ + 0𝑥2⁴ + 1𝑥2³ + 0𝑥2² + 0𝑥2¹ + 0𝑥2⁰ =


= 1𝑥32 + 0𝑥16 + 1𝑥8 + 0𝑥4 + 0𝑥2 + 0𝑥1 = 32 + 8 = 40

Já a representação interna do valor (‘MARIA’) da variável nome poderia ser algo


como: 01001101 01000001 01010010 01001001 01000001. Cada letra está com o valor
extraído da tabela ASCII (American Standard Code for Information Interchange) que é um
padrão internacional de codificação de caracteres. Na Tabela 3.1 são apresentados os
valores para os caracteres do nome ‘MARIA’ nas notações decimal (0..9), octal (0..7),
hexadecimal (0..9,a..f) e binária (0..1).

Tabela 3.1 - Caracteres ASCII da strin ‘MARIA’ (Fonte: https://pt.wikipedia.org/wiki/ASCII)


Caractere Decimal Octal Hexadecimal Binário

A 65 0101 0x41 01000001

I 73 0111 0x49 01001001

M 77 0115 0x4d 01001101

R 82 0122 0x52 01010010

Considere, como exemplo, o caractere ‘A’ que tem valor decimal 65. Este valor está
escrito nas demais bases, conforme pode ser observado nos desmembramentos abaixo:

Octal: 0101 = 1𝑥8² + 1𝑥8⁰ = 64 + 1 = 65


Hexadecimal: 041 = 4𝑥16¹ + 1𝑥16⁰ = 64 + 1 = 65
Binário: 01000001 = 1𝑥2⁶ + 1𝑥2⁰ = 64 + 1 = 65

A linguagem Python utiliza tipagem dinâmica, ou seja, o tipo de uma variável é


definido pelo interpretador em tempo de execução. Quando uma variável é criada através
de atribuição, o interpretador define um tipo para a variável, de acordo com o valor que está
sendo atribuído e o espaço adequado para armazenar valores daquele tipo. O tipo da
variável também vai definir os tipos de operações que poderão ser aplicadas a ela.

49
Introdução à Programação com Python

Algumas linguagens de programação possuem o conceito de constante que, a


grosso modo, pode ser vista como uma variável que não pode ter seu valor alterado.
Entretanto, na linguagem Python não há este tipo de definição diferenciada. O que definirá
que uma variável representa uma constante será o contexto do problema. Por exemplo,
uma variável para representar o valor de π deveria receber o valor 3.1415 e manter este
valor durante toda a execução do programa.

O uso das variáveis lembram um pouco dos conceitos matemáticos, mas possuem
também algumas diferenças bastante significativas, conforme serão expostas na sequência.
Suponha, por exemplo, uma equação do segundo grau: 𝑎𝑥² + 𝑏𝑥 + 𝑐 = 0. Na
matemática a equação possui apenas uma variável: x. E os valores a, b e c não são vistos
como variáveis, mas sim como parâmetros ou coeficientes quaisquer de uma equação de
segundo grau.

Na programação de computadores, x, a, b e c são vistos como variáveis, pois podem


representar um valor numérico que pode variar dependendo da equação que se deseja
resolver. Como regra, é sempre desejável que o programa resolva não apenas um problema
mas uma classe de problemas similares. Por exemplo, se for feito um programa para
encontrar as raízes de equação de segundo grau, uma boa solução seria aquela que
informasse a resposta para qualquer equação. Neste caso, o programa deveria receber os
valores dos coeficientes (a, b e c), atribuindo-os às respectivas variáveis e efetuar o cálculo
das raízes. O valor de x não é necessário para este cálculo.

Na matemática, podemos usar letras gregas ou outros símbolos para representar


constantes ou variáveis em equações. Podem ser usadas expressões para calcular o
discriminante de uma equação do segundo grau e a área de um círculo seriam,
respectivamente:

● Δ = 𝑏² − 4𝑎𝑐
● á𝑟𝑒𝑎 𝑐í𝑟𝑐𝑢𝑙𝑜 = π. 𝑟²

Na programação os nomes de variáveis tem que seguir regras muito mais restritas.
Só podem ser usados um conjunto restrito dos símbolos definidos na linguagem. Por
exemplo, as letras gregas Δ e π usadas nos exemplos não fazem parte dos símbolos da
linguagem Python. Em geral, os nomes de variáveis devem ser iniciados com uma letra
A..Z, a..z, ou _, podendo conter depois os caracteres A..Z, a..z, 0..9, _. Não são permitidos
símbolos como +, -, *, /, =, (, ), [, ], {, }, espaços em branco, caracteres acentuados, dentre
outros. Uma possibilidade de definição de nomes de variáveis e as respectivas expressões
em um programa, similares às dos exemplos acima seriam:

● 𝑑𝑒𝑙𝑡𝑎 = 𝑏 * 𝑏 − 4 * 𝑎 * 𝑐
● 𝐴𝑟𝑒𝑎𝐶𝑖𝑟𝑐𝑢𝑙𝑜 = 𝑝𝑖 * 𝑟 * 𝑟

Nos exemplos acima os caracteres ‘*’ e ‘-’ são operadores de multiplicação e


subtração e serão explicados com mais detalhes na próxima seção. Algumas palavras são
“reservadas” na linguagem e também não podem ser usadas como nomes de variáveis. Em

50
Introdução à Programação com Python

Python, a lista de palavras reservadas pode ser obtida no Shell com o comandos ‘import
keyword’ e ‘keyword.kwlist’, como mostrado na Figura 3.2.

Figura 3.2 - Comandos do Shell para visualizar lista de palavras reservadas

Alguns exemplos de nomes ou identificadores válidos para variáveis: x, nome, x7,


y_max e NomeGrande. Alguns exemplos de identificadores não válidos para variáveis, com
a razão explicitada entre parênteses: 8y (não pode começar com número), and (palavra
reservada - vide Figura 3.2), for (palavra reservada) e Nome Grande (não pode ter espaço).

3.1.1. Comando de Atribuição

Conforme dito anteriormente a definição do tipo de uma variável, na linguagem


Python, é feita no momento da execução do código, de acordo com o tipo do valor que será
atribuído à variável. O valor pode ser atribuído diretamente ou ser resultante da avaliação
de uma expressão.

O comando de atribuição é representado pelo caractere ‘=’ e significa que a


expressão (ou valor) que se encontra à esquerda do comando de atribuição será atribuído
para o nome (identificador) que está à sua esquerda. Sua forma geral é:

● <identificador> = <expressão>

onde: <identificador> é um nome válido para variável


<expressão> é uma expressão lógica ou aritmética ou um valor de um
tipo definido na linguagem.

Os comandos de atribuição para definir o conteúdo da memória como mostrado na


Figura 3.1 seriam os seguintes:
● nome = ‘MARIA’
● idade = 40

Cabe ao interpertador Python entender que serão necessários 5 bytes para


armazenar o valor da variável ‘nome’ e quatro bytes para armazenar o valor da variável
idade. E, de fato, a forma e o espaço gasto no armazenamento podem variar dependendo
da linguagem de programação e do tipo de processador. É importante ter a noção de que
cada variável ou estrutura de dados ocuparão espaço na memória.

Importante ressaltar que comando de atribuição não deve ser confundido com uma
equação da matemática. Suponha, por exemplo, que seja necessário atualizar a ‘idade’

51
Introdução à Programação com Python

passando o valor de 40 para 41. Uma possibilidade seria simplesmente executar um novo
comando de atribuição:
● idade = 41

Como o comando de atribuição tem o efeito de armazenar o valor na posição de


memória associada ao nome da variável que se encontra à esquerda do operador de
atribuição (=). O efeito deste comando seria escrever o valor 41 na posição onde, antes,
havia o valor 40. Ou seja, o valor anterior é sobrescrito. Uma outra forma de alterar a idade
seria escrevendo um outro comando de atribuição da seguinte forma:
● idade = idade + 1

Note que na matemática tal equação não faria sentido. Mas, como se trata de um
comando de atribuição, o seu funcionamento se dá da em três etapas, conforme mostrado
na Figura 3.3, supondo que o valor da variável ‘idade’, anterior à execução do comando,
seja 41. Para avaliação da expressão ‘idade + 1’ é necessário, primeiramente, obter o valor
da variável ‘idade’. Para isso, uma operação de busca na memória será feita, na posição
apontada pelo identificador ‘idade’, com o valor do seu conteúdo (41) sendo armazenado
em um registrador do processador. O segundo operando da expressão, o valor 1, será
carregado em um segundo registrador. O processador realizará a operação de soma dos
dois operandos e o valor resultante (42) será colocado em algum registrador do
processador. Com o término da avaliação da expressão, o seu resultado será atribuído para
a posição de memória associada ao identificador ‘idade’.

Figura 3.3 - Etapas do comando de atribuição

Importante chamar a atenção, mais uma vez, que o efeito final de um comando de
atribuição é escrever um valor em uma determinada posição de memória. Portanto, o valor
anterior se perde. Supondo que os três comandos de atribuição foram executados na ordem
apresentada, a variável ‘idade’ foi criada com valor 40 pelo primeiro comando (idade = 40).
O segundo comando (idade = 41) alterou seu valor para 41 e o terceiro comando (idade =
idade + 1) o modificou para 42.

Suponha que um novo comando para modificar o valor da variável ‘idade’ seja
escrito para indicar qual será a idade de uma pessoa daqui a uma década, usando a
seguinte forma:
● idade = idade + uma_decada

52
Introdução à Programação com Python

O interpretador Python, para executar o comando irá fazer a primeira parte da tarefa
que é buscar os operandos (‘idade’ e ‘uma_decada’). A busca do primeiro operando ‘idade’
seria feita com sucesso e o seu valor (42) carregado em algum registrador do processador,
pois a suposição é a de que os 3 comandos de atribuição para a variável ‘idade’
apresentados anteriormente foram executados. Porém, ao tentar buscar o segundo
operando, o interpretador Python apontará um erro de sintaxe, informando que
‘uma_decada’ é um nome desconhecido. E, de fato, esta variável não havia aparecido
anteriormente neste texto.

Na linguagem Python, toda variável precisa ser definida antes de ser usada em uma
expressão. A definição implica em atribuir um valor inicial no momento da criação. Por
exemplo, a variável ‘idade’ foi criada com valor inicial 40, com o primeiro comando de
atribuição (idade = 40). Para corrigir, o erro de sintaxe, o código poderia ser reescrito da
seguinte forma:
● uma_decada = 10 # cria a variável uma_decada com valor 10
● idade = idade + uma_decada # utiliza a variável uma_decada

Note que os dois comandos acima não podem ser invertidos, pois se isso
acontecesse, a mesma situação de erro de sintaxe seria apontada pelo interpretador
Python. Novamente, estaria ocorrendo uma tentativa de utilizar no primeiro comando, uma
variável que só seria criada no segundo comando. Lembre que a sequência correta de
eventos é fundamental para se chegar em uma solução correta de qualquer problema.

Um comentário final sobre o comando de atribuição é que na linguagem Python é


possível atribuir um mesmo valor para duas ou mais variáveis em um comando de
atribuição composto, como por exemplo:
● a=b=c=d=0

Este comando irá atribuir, ao final de sua execução, o valor zero para as quatro
variáveis. A ordem de atribuição é da direita para a esquerda, com a variável d sendo a
primeira a ter o valor definido e a variável a sendo a quarta. Mas, para a lógica da
programação de alto nível pode-se enxergar como as 4 variáveis tendo seus valores
definidos “ao mesmo tempo”.

3.1.2. Tipos de Variáveis

Os tipos primitivos de variáveis da linguagem Python podem ser classificados em


variáveis numéricas, lógicas e de texto. O tipo numérico possui dois subtipos básicos que
são os números inteiros e os números reais ou números de ponto flutuante. A faixa de
valores (menor valor negativo, maior valor positivo) depende do interpretador da linguagem
Python e do processador que a máquina possui.

Os valores lógicos ou booleanos são apenas dois verdadeiro (True) e (False). Um


resultado de uma comparação, como aquelas feitas no algoritmo do pão de queijo, vão

53
Introdução à Programação com Python

resultar sempre em um destes dois valores. Da mesma forma, comparar se uma variável é
maior do que outra, também resultará em valor verdadeiro ou falso.

Já as variáveis do tipo texto (ou strings) podem ter tamanho variável em função do
número de caracteres do texto. Em algumas linguagens, é feita uma distinção para variável
de apenas um caractere. Mas este não é o caso da linguagem Python, que admite até uma
string vazia, ou seja, um texto de zero caracteres.

Conforme já observado, a linguagem Python define o tipo da variável no momento


da execução do programa, ao analisar o comando de criação de cada variável no código.
Por exemplo, uma variável tipo texto (string) é definida pela expressão do lado direito do
comando de atribuição ser colocada entre aspas simples (' ') ou duplas (" "). Já a definição
de uma variável numérica do tipo ponto flutuante ou inteiro pode se dar pela colocação ou
não de um ponto, respectivamente.

Em outras linguagens de programação, o programador deve definir explicitamente o


tipo de cada variável. A abordagem da linguagem Python torna a tipagem mais flexível
permitindo, inclusive, que uma variável que tenha sido criada como sendo do tipo inteiro,
possa ser alterada durante a execução do programa para armazenar um número de ponto
flutuante. A grande vantagem é que o programador não precisa redefinir nada. O
interpretador se encarrega de fazer todas as tarefas necessárias, inclusive com alocação de
mais memória, pois a representação na memória de um número de ponto flutuante gasta
mais espaço (bytes) do que um número inteiro.
A Figura 3.4 apresenta alguns exemplos de criação de variáveis de tipos diferentes e
o uso em algumas operações simples, pois os operadores da linguagem Python serão
formalmente apresentados apenas na próxima seção. Neste capítulo, será utilizado o Shell
para exibição dos valores das variáveis, até que seja apresentado o comando de saída no
próximo capítulo.

Figura 3.4 - Exemplo de definição de variáveis usando o Shell

Note que no Shell do Python algumas informações aparecem com cores diferentes.
O valor False atribuído para a variável ‘terminou’ está na cor laranja. As strings estão na cor
verde e os comentários na cor vermelha. O comentário é iniciado com o caractere # e
aparece na cor vermelha. Um comentário não tem nenhum significado para o interpretador

54
Introdução à Programação com Python

Python, ou seja, tudo o que aparece após o caractere #, na mesma linha, é ignorado pelo
interpretador Python.

A forma de criação e atribuição do valor inicial define implicitamente o tipo de cada


variável na Figura 3.4. As duas primeiras variáveis n e idade são inteiras, as duas variáveis
seguintes fator e k são reais (ou de ponto flutuante), sexo e nome são variáveis do tipo
string (texto) e a variável terminou é do tipo booleana (ou lógica). A notação ‘1.37e-8’ usada
para atribuir o valor para a variável k significa 1, 37𝑥10⁻⁸. Note que na linguagem de
programação Python (e em todas as outras mais populares) utiliza-se o ponto (.) ao invés
da vírgula (,) para representação de números não inteiros. Como foi feito também na
atribuição do valor da variável fator.

No Shell do Python, para exibir o valor atual de uma variável basta digitar o seu
nome e depois a tecla “Enter”. Caso deseje imprimir o valor de mais de uma variável, basta
digitar a lista de nomes de variáveis separando-as com vírgula. Os valores, neste caso,
aparecerão entre parênteses e separadas por vírgulas. No próximo capítulo será
apresentado o comando de impressão, mas até lá as impressões de valores no Shell serão
feitas da forma descrita anteriormente. A Figura 3.5 apresenta um comando para imprimir o
valor de cada variável, na ordem em que foram definidas. Note que a saída deste comando
de impressão é feita na cor azul.

Figura 3.5 - Exibindo o valor das variáveis

A seguir, na Figura 3.6, são mostradas algumas alterações de valor feitas com a
utilização de comandos de atribuição e algumas expressões bem simples. Na próxima
seção serão vistos com detalhes os operadores da linguagem Python e alguns exemplos de
expressão um pouco mais elaboradas. Os comandos estão na sequência dos comandos já
apresentados na Figura 3.6, ou seja, com os valores iniciais das variáveis já definidos. Para
maior clareza, o último comando da figura anterior será sempre exibido na figura seguinte.

55
Introdução à Programação com Python

Figura 3.6 - Alguns comandos de atribuição para alterar o valor de variáveis

Na Figura 3.6, após um ou mais comandos de atribuição, o comando que imprime o


valor de todas as variáveis foi repetido para que seja possível visualizar o efeito do(s)
comando(s) sobre a variável à esquerda do operador de atribuição (variável que recebe o
valor definido pela expressão à direita do operador de atribuição).

Os dois primeiros comandos de atribuição são exatamente aqueles usados na seção


3.1.1 para explicar o funcionamento do comando de atribuição. O primeiro levou o valor da
variável idade para 41 e o segundo para 42. Note que nenhuma outra variável teve seu
valor alterado até este ponto, pois até ali apenas a variável idade apareceu recebendo o
resultado dos dois comandos de atribuição (idade = 41 e idade = idade + 1).

O comando seguinte (k = k + idade) tem uma expressão que soma um valor inteiro
com um valor de ponto flutuante, o que resultará em um valor de ponto flutuante. Portanto, o
resultado ao ser atribuído para a variável k não vai alterar o seu tipo. Entretanto, a forma de
exibição do valor que antes utilizada a notação científica tem que ser alterada para que não
se omita o valor fracionário.

No comando n = n + k também soma um valor inteiro com um valor de ponto


flutuante e o resultado está sendo atribuído para a variável n que foi criada como do tipo
inteiro. Em algumas linguagens de programação esta atribuição seria considerada como um
erro. Mas não é o caso da linguagem Python, que altera dinamicamente o tipo da variável n
para que o valor seja armazenado corretamente na memória. Note, que na impressão
seguinte o valor de n passa a ter várias casas decimais. Note também que o valor de n e k
passaram a ser iguais, pois no momento da avaliação da expressão o valor de n era zero,
logo n + k foi igual a k.

Os comandos seguintes que alteram o valor das variáveis sexo e nome mostram
outra característica dinâmica da linguagem Python. Uma variável do tipo string pode
aumentar ou diminuir de tamanho dinamicamente durante a execução do programa. O texto

56
Introdução à Programação com Python

‘Maria das Dores’ tem um caractere a mais do que ‘Carlos Alberto’, portanto, o espaço na
memória reservado para esta variável teve de aumentar (o interpretador Python faz isso de
forma transparente para o programador). A variável sexo também cresceu de forma mais
fácil de se notar. O comentário no comando de criação indicava que ela era do tipo
caractere, na verdade, não está correto. De fato, sexo é uma variável do tipo string que
recebeu, inicialmente, um texto de apenas 1 caractere (‘M’).

Finalmente, os dois últimos comandos de atribuição da Figura 3.6 atribuem valore


diretamente para as variáveis n e terminou. A variável n volta a ter o valor zero e a variável
terminou passa a valer True (verdadeiro). É importante entender que após um comando de
atribuição, o valor anterior é perdido. Esta foi a razão da inserção dos comandos de
exibição dos valores das variáveis entre os comandos de atribuição.

3.2 Operadores e Expressões

Os operadores da linguagem de programação são utilizados para permitir a escrita


de expressões para o cálculo de valores para a realização da computação desejada

3.2.1. Operadores e Expressões aritméticas

Os principais operadores para a realização de cálculos e criação de expressões


aritméticas são apresentados na Tabela 3.2:

Tabela 3.2 - Principais operadores aritméticos


Operador Nome / Papel do operador

( ) Parênteses / permite alterar a prioridade de execução das operações

+ Soma

- Subtração

* Multiplicação

/ Divisão

% Módulo / Resto da divisão inteira

// Quociente / Quociente da divisão inteira

** Potenciação

57
Introdução à Programação com Python

Considere os exemplos de expressões aritméticas mostradas na Figura 3.7.


Supondo que cada linha corresponda a uma linha de um código de Programa Python
poderia ser perguntado: qual o valor final de cada variável do Programa?

Num. do Código Pyton


comando

1 resultado = 2+6
2 x = 2*resultado
3 pi = 3.14159
4 UmMega = 1024 * 1024
5 y = (x+3)*x/3
6 y = x+y
7 x=y=0

Figura 3.7 - Alguns exemplos simples de expressões aritméticas

Para responder a esta pergunta pode-se utilizar uma tabela de rastreio para simular
a execução do código. A tabela terá o nome de cada variável e uma coluna indicando qual
comando foi o mais recentemente executado. A cada comando, as variáveis vão sendo
criadas e os valores atribuídos. Uma variável que ainda não foi criada terá seu valor
representado na tabela de rastreio com um traço ‘-’. Por exemplo, na primeira linha está
sendo suposto que nenhum comando foi executado e, portanto, todos os valores são ‘-’.

Tabela 3.3 - Tabela de Rastreio para o trecho de código da Figura 3.7


resultado x pi UmMega y Número do último
comando executado

- - - - - Nenhum

8 - - - - 1

8 16 - - - 2

8 16 3.14159 - - 3

8 16 3.14159 1048576 - 4

8 16 3.14159 1048576 101.33333 5

8 16 3.14159 1048576 117.33333 6

8 0 3.14159 1048576 0 7

A tabela de rastreio é sempre útil para ajudar a entender o fluxo de execução e o


que acontece com as variáveis do programa, à medida que os comandos vão sendo
executados. Entretanto, como é um método manual e, por isso, sujeito a erros, a melhor
alternativa para verificar o que acontece com um programa é utilizar alguma ferramenta de
desenvolvimento, como é o caso IDLE. Nas aulas práticas da disciplina INF 100 -
Introdução à Programação I este será o ambiente utilizado. A página do Python Tutor

58
Introdução à Programação com Python

(https://pythontutor.com/), conforme falado no final do capítulo 2, é um excelente ambiente


para automatizar a tarefa de rastreio para código Python.

Até aqui foi utilizado apenas o Shell do ambiente de desenvolvimento IDLE. Se o


Shell fosse utilizado para responder à pergunta sobre o valor final das variáveis para o
trecho de código da Figura 3.7 poderia ser feito da forma mostrada na Figura 3.8, a seguir:

Figura 3.8 - Uso do Shell para verificar valor final de variáveis

Suponha, agora, que se deseja usar o Shell para calcular a área de um círculo. A
fórmula para cálculo da área de um círculo é π. 𝑟², onde r é o raio do círculo e π é um valor
constante igual a 3.14159 na representação com 5 casas decimais de precisão.

Figura 3.9 - Exemplo de uso do Shell para cálculo de área de um círculo

Nos 3 primeiros comando da Figura 3.9 são usados para: definir o valor da
constante pi; definir o valor do raio; e calcular a área. O valor 12.56636 é exibido, como
resultado do quarto comando, como sendo o valor da área de um círculo de raio 2. A área
depende da unidade do raio. Se o raio fornecido significar 2 cm, a área seria de 12.56636
cm². Porém, se o raio estivesse em metros, a área seria de 12.56636 m².

59
Introdução à Programação com Python

Na sequência existe um comando que altera o valor da variável r (que representa o


raio) para 10 e no comando seguinte utiliza-se o comando para exibir o conteúdo da
variável area. Note que o valor da variável area continua o mesmo, pois não houve nenhum
comando de atribuição para a variável area, após a redefinição do valor do raio. Para que
isto ocorra, o sétimo comando calcula novamente a expressão aritmética com o valor da
variável r (raio) com o valor atual (10). No comando seguinte, o novo valor da área
(314.159) é exibido.

Nos comandos seguintes, o valor da variável pi é redefinido, passando a valer -1.


Novamente, o valor da variável area é exibida e repete a exibição do último valor que lhe foi
atribuído (314.159). Finalmente, a expressão de cálculo da área é novamente avaliado e o
seu resultado é atribuído para a variável area. E, no último comando, o valor -100 é
informado como a área do círculo!!!

Um absurdo do ponto de vista lógico, pois não existe área negativa. Note que este
valor absurdo, deriva do erro absurdo de definir o valor da constante pi como -1, ao invés de
3.14159. Mas, do ponto de vista da execução do código, para o computador está tudo certo.
O nome pi, para o computador, não tem nenhum significado especial, logo, qualquer valor
atribuído para a variável será aceito. Não há erro na definição das variáveis e nem nas
expressões aritméticas. Importante frisar que o computador não erra. O que ele pode fazer
é executar comandos que contém erro na sua definição e que ele não consegue identificar.

Portanto, os programadores devem garantir que os comandos não contenham erros,


absurdos ou não, conhecendo o problema que se pretende resolver e observando se as
respostas fazem sentido, em cada caso.

Existe uma precedência entre os operadores aritméticos na linguagem Python.


Conhecer esta ordem é fundamental para que as expressões sejam escritas corretamente
e, consequentemente, processem as informações de maneira correta, para produzir o
resultado desejado. A Tabela 3.4 apresenta a ordem de precedência dos operadores
aritméticos, sendo 1 a mais prioritária..

Tabela 3.4 - Ordem de prioridade dos operadores aritméticos


Ordem Operador Nome

1 () Parênteses

2 ** Potenciação

3 - Negação

4 * / // % Multiplicação, Divisão, Divisão inteira e Resto da Divisão Inteira

5 + - Soma e Subtração

Em uma expressão, quando existirem operadores de mesma prioridade, as


operações são executadas na ordem de aparição (da esquerda para a direita). A seguir, são
apresentados alguns exemplos de expressões e suas avaliações passo a passo:

60
Introdução à Programação com Python

● -1**2 = -1
● (-1)**2 = 1
● 8+3*2 = 8+6 = 14
● (8+3)*2 = 11*2 = 22
● 2+4%3 = 2+1 = 3
● (2+4)%3 = 6%3 = 0
● 5-3+1 = 2+1 = 3
● 5-(3+1) = 5-4 = 1
● 1+4/2+2*2 = 1 + 2 + 2*2 = 1 + 2 + 4 = 3 + 4 = 7

Em caso de dúvida, a utilização de parênteses é sempre uma boa alternativa a ser


adotada. Outra observação importante é que ao utilizar parênteses o número de caracteres
‘(‘ tem que ser igual ao número de caracteres ‘)’. E, obviamente, um caractere ‘(‘ sempre
deve vir antes do caractere ‘)’ correspondente. Ao encontrar um caractere ‘(‘, o interpretador
entende que foi aberto um bloco, que deverá ser fechado, necessariamente, com um
caractere ‘)’.

3.2.2. Operadores e Expressões Lógicos

Os operadores lógicos ou booleanos são utilizados para ajudar a escrever


expressões lógicas. O resultado de uma expressão lógica poderá assumir apenas dois
valores: verdadeiro (True) ou falso (False). Os operadores lógicos costumam ser
apresentados juntamente com os comandos condicional e repetitivo, pois ambos utilizam
um teste para verificar o fluxo a ser seguido. O resultado do teste será sempre verdadeiro
ou falso, ou seja, um valor booleano (ou lógico).

A maioria dos operadores aritméticos são de conhecimento de todos, desde o


ensino fundamental. O mesmo não se aplica aos operadores lógicos, mesmo que no dia a
dia, eventualmente, já tenhamos aplicado alguma destas operações lógicas de maneira
intuitiva. A seguir são descritas as três operações lógicas primitivas: não (not), e (and) e ou
(or). Com estes três operadores é possível escrever qualquer função lógica.

3.2.2.1 - Operador não (not)


O operador not é um operador unário, ou seja, necessita apenas de um operando e
o resultado da operação é a negação ou a inversão do valor lógico. A tabela verdade da
função not para uma entrada A é mostrada a seguir:

A not A

False True

True False

A tabela verdade lista todas as combinações de entradas possíveis e, para cada


combinação, informa o valor da saída. No caso da função not a tabela verdade terá apenas

61
Introdução à Programação com Python

2 linhas. A aplicação da função not, portanto, inverte o valor da entrada fornecida, conforme
indicado em sua tabela verdade.

3.2.2.2 - Operador e (and)


O operador and é um operador que necessita de pelo menos duas entradas e o seu
resultado será Falso se pelo menos uma das entradas for Falsa. O resultado da função and
será verdadeiro somente se todas as suas entradas forem verdadeiras. A tabela verdade da
função and para duas entradas A e B é mostrada a seguir:

A B not(A)

False False False

False True False

True False False

True True True

A tabela verdade para duas entradas, como é o caso da função and mostrada acima
𝑛
terá 4 linhas. O número de linhas de uma tabela verdade será sempre 2 , onde n
corresponde ao número de entradas da função booleana.

3.2.2.3 - Operador ou (or)


O operador or é um operador que também necessita de pelo menos duas entradas e
o seu resultado será Falso somente quando todas as entradas forem falsas. O resultado da
função or será verdadeiro se pelo menos uma de suas entradas for verdadeira. A tabela
verdade da função or para duas entradas A e B é mostrada a seguir:

A B not(A)

False False False

False True True

True False True

True True True

A Tabela 3.5 apresenta os três operadores lógicos com a respectiva notação utilizada na
linguagem Python.

Tabela 3.5 - Operadores lógicos (booleanos)


Operador Equivalente em Python

não (not) not

e (and) and

ou (or) or

62
Introdução à Programação com Python

3.2.2.4 - Expressões lógicas


Tendo visto, então, os três operadores lógicos (booleanos) primitivos é hora de
apresentar as expressões lógicas. Uma expressão lógica pode usar apenas os operadores
booleanos, mas pode conter também expressões aritméticas e fazer uso dos operadores
relacionais (ou de comparação). Os operadores relacionais são apresentados na Tabela 3.6:

Tabela 3.6 - Operadores relacionais


Operador Significado

< menor

<= menor ou igual

> maior

>= maior ou igual

== igual

!= diferente

O uso de um operador relacional resultará em um valor booleano (verdadeiro ou


falso), pois o resultado de uma comparação (relação) só pode ser verdadeira ou falsa.
Considere o trecho de código mostrado na imagem do Shell na Figura 3.10. O código define
duas variáveis inteiras x e y com valores iniciais 1 e 2, respectivamente. Depois são usados
operadores relacionais e lógicos para atribuir valor para 3 variáveis a, b e c, que vão
assumir valor verdadeiro ou falso, dependendo do resultado da avaliação da expressão
relacional/booleana.

Para atribuição do valor para a variável a, a expressão “y < 5” é avaliada. Como o


valor de y é igual a 1, o resultado da comparação é verdadeiro (True) e este valor será
atribuído para a variável a. Na avaliação da expressão relacional “x == y” a comparação a
ser feita é se o valor da variável x é igual ao da variável y. Por óbvio que não, pois x vale 1 e
y vale 2 no momento da comparação. Portanto, a comparação retorna o valor falso (False)
que é atribuído para a variável b.

Finalmente, o valor da variável c é resultante de uma expressão lógica que utiliza o


operador booleano and, onde primeiramente será avaliada a relação “x < y” por causa dos
parênteses (na verdade não seria necessário usar parênteses - vide Tabela 3.7). O valor da
comparação “x < y” será verdadeiro (True) e a operação and será processada com as duas
entradas verdadeiras. Logo, o valor verdadeiro (True) será atribuído para a variável c. No
código foi inserido o comando para exibir o valor das variáveis na ordem de criação no
programa.

Note que o tipo (booleano) das variáveis a, b e c foram definidos em função do valor
(verdadeiro ou falso) resultante da avaliação das expressões relacionais. O que aconteceria
se, por um erro de digitação, fosse utilizado apenas um caractere ‘=’ para fazer a
comparação entre x e y?

63
Introdução à Programação com Python

Figura 3.10 - Exemplo de uso de operadores relacionais e booleano

Ao escrever “b = x = y” não existe mais um operador relacional de igualdade entre x


e y, mas um comando de atribuição “x = y”. Logo, a linha torna-se um comando de
atribuição composto onde, o valor de y (vale 2 no momento) será atribuído para x e o valor
de x (que agora é igual ao de y) será atribuído também para b. Ou seja, x, y e b passam a
ter o mesmo valor (2). O mesmo comando de impressão é utilizado novamente, na Figura
3.10, e mostra o valor 2 para as variáveis x, y e b. Note que no caso da variável b ela deixou
de armazenar um valor booleano (False) para armazenar um valor inteiro (2). Este é um
exemplo de como uma variável em Python pode ter o seu tipo modificado durante a
execução do programa. Isso não acontece em linguagens como C++, Java, dentre outras.

Por isso, é muito importante ter bastante atenção no momento de escrever as


expressões aritméticas, relacionais e lógicas em seus programas. É necessário considerar
também a ordem de execução das operações ou a prioridade entre as operações. A Tabela
3.7 apresenta todos os operadores vistos até aqui com a ordem de prioridade, sendo o
número 1, a operação mais prioritária.

Tabela 3.7 - Ordem de prioridade dos operadores aritméticos


P Operador Nome

1 - negação aritmética

2 ** Potenciação

3 * / // % Multiplicação, Divisão, Divisão inteira e Resto da Divisão Inteira

4 + - Soma e Subtração

5 < <= > >= == != Operadores relacionais

6 not Não lógico

7 and E lógico

8 or OU lógico

9 = Atribuição

64
Introdução à Programação com Python

3.2.2.5 Equivalência de Expressões Lógicas

Conforme já destacado na seção 2.8, algumas vezes os algoritmos são diferentes,


mas levam à mesma solução correta de um problema. O mesmo se aplica às expressões
booleanas. Muitas vezes a forma de desenvolver um raciocínio lógico pode levar
expressões lógicas distintas, mas com resultados idênticos ao serem avaliadas.

Para exemplificar tal situação, imagine um programa que precisa verificar se um


número está dentro do intervalo qualquer, por exemplo, representados por duas variáveis a
e b. Desta forma, podemos definir diferentes intervalos, simplesmente atribuindo valores
diferentes para a e b. Por exemplo, a = 0 e b = 100, para verificar se o valor de uma nota (n)
final está na faixa de valores usados na UFV. A hipótese que se assume aqui é que sempre
o valor de a será menor que o valor de b. Graficamente, podemos representar o nosso
intervalo como mostrado na Figura 3.11.

Figura 3.11 - Intervalo fechado [a, b]

A representação [a, b] indica que os valores das extremidades, a e b, pertencem ao


intervalo. Uma forma de representar este intervalo é como sendo a interseção de dois
intervalos: qualquer número maior ou igual ao limite inferior ([a, +∞)) e qualquer número
menor ou igual ao limite superior ((-∞, b]). A Figura 3.12 representa a definição do intervalo
como a interseção descrita.

Figura 3.12 - Intervalo fechado [a..b]

A operação de interseção define o que é comum em dois conjuntos. No caso


dos intervalos a interseção pegará todos os números que atendem às duas
condições simultaneamente: ser maior ou igual a zero e ser menor ou igual a 100.
Supondo que o valor (nota) a ser verificada esteja armazenada na em uma variável
n, a condição lógica que verifica se n pertence ao intervalo pode ser descrita como:

65
Introdução à Programação com Python

𝑛 >= 𝑎 𝐸 𝑛 <= 𝑏

Ou escrevendo na linguagem Python:

𝑛 >= 𝑎 𝑎𝑛𝑑 𝑛 <= 𝑏 (expressão 1)

Uma outra forma de definir a expressão lógica para testar se um valor n


pertence a um intervalo [a, b] seria utilizando um raciocínio inverso. Ao invés de
pensar no intervalo, pode-se pensar nos valores que não fazem parte do intervalo.
E, posteriormente, após obter a expressão que representa este “não intervalo”,
bastaria aplicar o operador not. Em suma, não(não(intervalo) = intervalo, pois o
intervalo, conforme visto anteriormente, está representado por uma expressão lógica
aplica-se o operador lógico não (not).

A Figura 3.13 mostra na parte superior o intervalo fechado [a, b] e na parte


inferior o “não intervalo” ou os valores que não pertencem ao intervalo. Note que
estes valores do “não intervalo”, na verdade, estão em dois intervalos distintos: (-∞,
a) e (b, +∞).

Figura 3.13 - Intervalo fechado [a..b]

Para estar fora do intervalo, ou no “não-intervalo” um número pode estar em qualquer um


dos dois intervalos. Basta estar em um deles para satisfazer à condição de não pertencer
ao intervalo. Logo, deve-se utilizar a conjunção lógica ou para escrever a expressão que
indica o não-intervalo:

𝑛 < 𝑎 𝑂𝑈 𝑛 > 𝑏

Mas esta expressão representa os números que estão fora do intervalo. Assim,
devemos negá-la para que seja representado os números que pertencem ao intervalo:

𝑛ã𝑜(𝑛 < 𝑎 𝑂𝑈 𝑛 > 𝑏)

Ou escrevendo na linguagem Python:

𝑛𝑜𝑡(𝑛 < 𝑎 𝑜𝑟 𝑛 > 𝑏) (expressão 2)

Uma forma de demonstrar que as expressões 1 e 2 são equivalentes seria definir os


limites do intervalo e testar para valores conhecidos. Vamos supor que o intervalo seja [0,
100] e testar as expressões 1 e 2 para valores que estão no intervalo (ex: 0, 93 e 100) e

66
Introdução à Programação com Python

outros que estão fora (ex: -1 e 230). A Tabela 3.8 apresenta o detalhamento do resultado de
todas as operações relacionais e booleanas, com o valor final das expressões 1 e 2 nas
colunas em negrito, mostrando que são equivalentes.

Tabela 3.8 - Comparação entre (n>=a and n<=b) e not(n<a or n>b) para a=0 e b=100
A B n>=0 and n<=100 C D E not(n<0 or n>100)

n n >= 0 n <= 100 A and B n<0 n > 100 C or D not E

-1 False True False True F alse True False

0 True True True False False False True

93 True True True False False False True

100 True True True False False False True

230 True False False False True True False

Outra forma de demonstrar a equivalência das duas expressões é utilizando o


Teorema de Boole. Por este teorema as seguintes equivalências são válidas:

𝑛𝑜𝑡(𝑝 𝑜𝑟 𝑞) = 𝑛𝑜𝑡(𝑝) 𝑎𝑛𝑑 𝑛𝑜𝑡(𝑞)


𝑛𝑜𝑡(𝑝 𝑎𝑛𝑑 𝑞) = 𝑛𝑜𝑡(𝑝) 𝑜𝑟 𝑛𝑜𝑡(𝑞)

Para a sequência, vai ser considerado o intervalo [0, 100], substituindo, então, a por
0 e b por 100. Considere a primeira equivalência do Teorema de Boole que possui a sua
primeira parte escrita com a mesma estrutura da expressão 2, deduzida anteriormente:

𝑛𝑜𝑡(𝑛 < 0 𝑜𝑟 𝑛 > 100)

Neste caso, 𝑛 < 0corresponde ao operando p e 𝑛 > 100 corresponde ao operando


q da equivalência no Teorema de Boole, reescrita a seguir:

𝑛𝑜𝑡(𝑛 < 0 𝑜𝑟 𝑛 > 100) = 𝑛𝑜𝑡(𝑛 < 0) 𝑎𝑛𝑑 𝑛𝑜𝑡(𝑛 > 100)

Mas o que seriam 𝑛𝑜𝑡(𝑛 < 0) e 𝑛𝑜𝑡(𝑛 > 100)? Ora, negar a comparação 𝑛 < 0 é
utilizar a comparação 𝑛 >= 0, pois todo valor que torna a primeira comparação verdadeira
vai tornar a segunda comparação falsa e, vice-versa. Em Português pode-se dizer que “o
que não é menor do que zero”, só pode “ser maior ou igual a zero”. Usando o operador
booleano not pode-se escrever 𝑛𝑜𝑡(𝑛 < 0) "𝑒𝑞𝑢𝑖𝑣𝑎𝑙𝑒 𝑎" 𝑛 >= 0. Analogamente, para
negar a comparação 𝑛 > 100 deve-se utilizar a comparação 𝑛 <= 100. Usando o operador
lógico not pode-se definir a relação 𝑛𝑜𝑡(𝑛 > 100) "𝑒𝑞𝑢𝑖𝑣𝑎𝑙𝑒 𝑎" 𝑛 <= 100. Desta forma,
podemos reescrever a equivalência anterior:

𝑛𝑜𝑡(𝑛 < 0 𝑜𝑟 𝑛 > 100) = 𝑛 >= 0 𝑎𝑛𝑑 𝑛 <= 100

Portanto, está demonstrado, usando o teorema de Boole que a expressão 1 é


equivalente à expressão 2.

67
Introdução à Programação com Python

3.3. Uso do Shell do IDLE

Neste ponto, é importante lembrar que, apesar de alguns exercícios simples ou


testes de comandos poderem ser executados na janela do Shell do ambiente de
programação IDLE, esta janela deve ser usada para visualizar a saída gerada pelo
programa. Para mais detalhes, veja a seção 1.4.

3.3. Exercícios

1) Para o código mostrado abaixo, informe o valor que será recebido pela variável em
cada um dos comandos de atribuição. Qual o tipo da variável em cada comando de
atribuição ?

A=5
B=A-7
C=A+B*2
D = A + B ** 2
E = D ** 0.5
F=A/3
G = A // 3
H=A%3
I=A+B*C/2*D
J = A + B * C / (2 * D)
K = I // J
L=I/J
M = int(I / J)
N = float(M)

2) Para o código mostrado abaixo, informe o valor que será recebido pela variável em
cada um dos comandos de atribuição. Qual o tipo da variável em cada comando de
atribuição ?

A=2
B=A+7
C=2*A+B
D=C-B>B-C
E = A + B * C == 120
F = E and A>B or C > B
G = A >= 0 and A <= 100
H = A < 0 or A > 100
I = D and G or E and H

68
Introdução à Programação com Python

J = D and (G or E) and H
K = D or G and E or H
L = (D or G) and (E or H)
M = (K and L) == (not(not(K) or not(L)))
N = (K or L) == (not(not(K) and not(L)))

3) Para o código mostrado abaixo, informe o valor que será recebido pela variável do
tipo texto (string) em cada um dos comandos de atribuição.

nome = 'José'
sexo = 'Masculino'
sobrenome = 'Leôncio da Silva'
nomeCompleto = nome + sobrenome
nomeComplComEspaco = nome + ' ' + sobrenome
nomeTriplo1 = 3*nomeComplComEspaco
nomeTriplo2 = 3*(nomeComplComEspaco+' ')
linha = 'Nome: ' + nomeComplComEspaco + ' Sexo: ' + sexo

4) Refaça os exercícios 1, 2 e 3 digitando os comandos na janela do Shell do IDLE e


mande imprimir os valores para as variáveis e verifique seus acertos e erros.

5) Escreva uma expressão que dada uma temperatura em graus Fahrenheit, calcule o
𝐶 𝐹−32
valor correspondente em graus Celsius, de acordo com a fórmula: 5 = 9

6) Escreva uma expressão para calcular a área de um círculo, sabendo o valor do raio
(R). A expressão deve atribuir o valor para a variável de nome Area.

7) Escreva uma expressão para calcular o k-ésimo elemento de uma progressão


aritmética cujos valores do primeiro elemento e da razão serão armazenados em
variáveis de nomes a1 e r, respectivamente. O valor da expressão deve ser atribuído
para uma variável de nome Ak. Dica: faça uma busca na Internet para achar a
fórmula do k-ésimo elemento de uma progressão aritmética.

8) Usando as informações do exercício anterior defina uma expressão para atribuir


para uma variável de nome Soma, o valor dos 100 primeiros números naturais. Dica:
faça uma busca na Internet para achar a fórmula do somatório dos elementos de
uma progressão aritmética. Dica: pesquise na Internet a fórmula da soma dos
elementos de uma PA.

69
Introdução à Programação com Python

9) Generalize a solução do exercício anterior para definir uma expressão para atribuir
para uma variável de nome SomaN, o valor dos N primeiros números naturais.

10) Defina uma expressão para calcular a soma dos N primeiros elementos de uma
Progressão Aritmética (PA), cujos valores do primeiro elemento e da razão terão
valores atribuídos para as variáveis a1 e razao, respectivamente. A expressão para
o cálculo da soma deverá ser atribuído para uma variável de nome SomaNPA. Dica:
utilize uma outra expressão para atribuir para uma variável An o valor do n-ésimo
elemento da PA.

11) Use a janela do Shell do ambiente de programação IDLE para verificar a solução do
exercício anterior. Use sequências pequenas para facilitar a verificação do somatório
dos valores da Progressão Aritmética. Por exemplo para a sequência 2, 5, 8 e 11, na
qual a1 = 2 e razao = 3, a soma dos valores é 26.

12) Defina uma expressão para calcular a soma dos N primeiros elementos de uma
Progressão Geométrica (PG), cujos valores do primeiro elemento e da razão terão
valores atribuídos para as variáveis elem1 e razaoPG, respectivamente. A
expressão para o cálculo da soma deverá ser atribuído para uma variável de nome
SomaNPG. Dica: utilize uma outra expressão para atribuir para uma variável elemN
o valor do n-ésimo elemento da PG.

13) Use a janela do Shell do ambiente de programação IDLE para verificar a solução do
exercício anterior. Use sequências pequenas para facilitar a verificação do somatório
dos valores da Progressão Geométrica. Por exemplo para a sequência 2, 4, 8 e 16,
na qual elem1 = 2 e razaoPG = 2, a soma dos valores é 30.

70
Introdução à Programação com Python

Capítulo 4 - Comandos de Entrada e Saída

A comunicação homem-máquina é importantíssimo para o sucesso de uma solução


computacional. As informações que são necessárias para a realização das tarefas devem
estar bem definidas e de fácil entendimento para quem irá fornecê-las. Da mesma forma, a
saída ou a exibição dos resultados gerados pelo programa devem estar bem organizada de
forma a facilitar a sua visualização.

Para atingir estes objetivos serão apresentados neste capítulo os comandos de


entrada e saída, que servem para fazer a interface homem-máquina. Nos computadores
convencionais, o dispositivo de entrada padrão é o teclado no qual o usuário digita uma
sequência de caracteres e depois aperta a tecla “Enter”. Esta tecla indica o final da entrada
da informação solicitada. Já o dispositivo padrão de saída é o monitor de vídeo.

Para as seções a seguir está sendo suposto que os comandos de entrada e saída
estão relacionados, respectivamente com o teclado e o monitor de vídeo. Porém, é bom
ressaltar que estes dispositivos padrão podem ser alterados como, por exemplo, para
utilizar arquivos como entrada e/ou saída de dados.

4.1 - Comando de Saída

4.1.1 - Forma básica do comando de saída

Considere o seguinte programa bem pequeno, com apenas um comando, escrito em


Python:

print('Olá UFV...')

Esse programa escreverá na tela o seguinte:


Olá UFV…

O comando print() escreve na tela (monitor de vídeo) o texto (string) que foi usado
como parâmetro. Este é o comando utilizado para escrever uma ou mais informações na
saída padrão do computador. A forma geral do comando print() é mostrada a seguir:
print(<lista de parâmetros>)

71
Introdução à Programação com Python

A lista de parâmetros corresponde ao conjunto de informações que se deseja exibir.


Quando houver mais de um parâmetro (ou valor) a ser exibido, eles devem ser separados
por vírgulas. A Figura 4.1 apresenta alguns exemplos de comandos print() usando sempre
mais de um parâmetro. Note que a tela da Figura 4.1 corresponde à janela de edição de
programas do ambiente de desenvolvimento IDLE (segunda aparição, desde a Figura 1.7) e
o arquivo de trabalho recebeu o nome de Figura4-1.py.

Figura 4.1 - Exemplo de Comandos de Impressão

Os comandos iniciais definem uma variável inteira (idade) e quatro variáveis do tipo
string (sexo, nome, cabo e espessura). Note que para a variável cabo a delimitação da
string que contém uma aspas simples (‘) foi feita com aspas duplas (“). Ou seja, quando a
delimitação de uma string é iniciada com um tipo de aspas, ela deve ter o final de sua
delimitação com o mesmo tipo de aspas.
O primeiro comando print possui dois parâmetros: um texto (string) e a variável
nome. Um texto sempre aparecerá da forma que está escrito entre as aspas. A variável será
sempre substituída pelo seu valor. O resultado deste primeiro comando será: Nome: Carlos
Alberto. Note que o espaço em branco (que é um caractere associado à barra de espaço do
teclado) após Nome: na string (primeiro parâmetro) será exibido. Portanto, adicionar
caracteres de espaço serve para separar duas informações em uma string.
O segundo comando print é muito parecido com o primeiro, mas com 4 parâmetros
ao invés de 2. O primeiro e terceiro parâmetros, que são strings, serão exibidos exatamente
como foram escritos no comando print. Já o segundo (sexo) e quarto (idade) parâmetros
são dois nomes de variáveis que serão substituídos pelo valor atual das respectivas
variáveis presentes na memória (valor da última atribuição feita).
Finalmente, o terceiro comando print possui apenas duas variáveis como
parâmetros. Logo, serão exibidos os dois valores das variáveis cabo e espessura. Note que
o comando print() insere um espaço em branco para separar os parâmetros na exibição. A
Figura 4.2 apresenta a janela do Shell do ambiente IDLE, com o resultado da execução do
programa.

72
Introdução à Programação com Python

Figura 4.2 - Resultado da Execução do código da Figura 4.1

Observe que na janela do Shell é exibido apenas o resultado da execução do


programa, ou seja, só irão aparecer os resultados de cada comando print() do programa.
Observe também que na mensagem de ‘RESTART’ é indicado o nome do arquivo que foi
executado (Figura4-1.py).

4.1.2. Comando print() com separador e terminador

O comando de impressão print() usa o caractere branco (ou espaço em branco ou


espaço) como separador padrão, quando existem dois ou mais parâmetros. Observe que no
último comando print() da Figura 4.1 existem duas variáveis do tipo string como parâmetros.
A execução do comando resultou na impressão da primeira string, um caractere branco e a
segunda string: Pirelli’s antichama 20”. O caractere branco está após o último caractere ‘a’ e
antes do caractere ‘2’.
É possível alterar o separador padrão utilizando o parâmetro sep=<separador> onde
<separador> corresponde à string de zero ou mais caracteres que se deseja usar para
separar as informações. A Tabela 4.1 apresenta alguns exemplos de separadores e o
resultado obtido com a execução do comando, considerando as variáveis definidas na
Figura 4.1.
Tabela 4.1 - Exemplos de uso do separador
Comando Resultado da execução

print(cabo, espessura, sep=’’) Pirelli's antichama20"

print(cabo, espessura, sep=’***’) Pirelli's antichama***20"

print(cabo, espessura, sep=’\t’) Pirelli's antichama 20"

print(cabo, espessura, sep=’\n’) Pirelli's antichama


20"

73
Introdução à Programação com Python

No primeiro comando da Tabela 4.1 foi utilizada a string vazia (0 caracteres) como
separador e, por isso, as duas strings foram impressas como se não houvesse separação.
No segundo comando o separador foi uma sequência de três asteriscos. Nos dois últimos
comandos os separadores utilizados fazem parte do grupo de caracteres de controle (ou
não imprimíveis). O caractere ’\t’ (lê-se contrabarra t) é o espaçamento de tabulação (tecla
Tab existente nos teclados) que corresponde ao espaço de alguns caracteres (no resultado
da execução do comando parece ser de 4 espaços). Já o caractere ‘\n’ (contrabarra n)
corresponde ao “Carriage Return” (tecla Enter dos teclados) e indica que se deve ir para o
início da próxima linha. Por isso o último comando print() da Tabela 4.1 utilizou duas linhas.
O caractere ‘\n’ é o terminador padrão do comando de saída print(). Este padrão
também pode ser alterado utilizando o parâmetro end=<terminador> onde <terminador>
corresponde à string de zero ou mais caracteres que se deseja usar imediatamente após a
impressão dos parâmetros imprimíveis. A Tabela 4.2 apresenta alguns comandos de
impressão supondo, novamente, as variáveis criadas na Figura 4.1.
Tabela 4.2 - Exemplos de utilização do parâmetro de terminação
Comandos Resultado da Execução

print(cabo, end=’’) Pirelli’s antichama20”


print(espessura)

print(cabo, end=’ ’) Pirelli’s antichama 20”


print(espessura)

print(cabo, end=’***’) Pirelli’s antichama***20”


print(espessura)

print(cabo, end=’\t’) Pirelli’s antichama 20”


print(espessura)

print(cabo, end=’\n’) Pirelli’s antichama


print(espessura) 20”

O uso de separador e/ou terminador diferentes do padrão podem estratégias úteis


para adequar a formatação da saída gerada pelo comando print(). Da mesma forma, os
caracteres de controle ‘\n’ e ‘\t’ podem ser utilizados para adequar a formatação da saída,
inclusive quando utilizados dentro de uma string. Por exemplo, o comando
print("Pirelli's\tantichama\n20\"") gera a seguinte saída:
Pirelli's antichama
20"
Note que a utilização dos caracteres ‘\t’ e ‘\n’ produziram o espaço de tabulação e a
quebra de linha, ao serem usados antes e depois da palavra “antichama”, respectivamente.
O contrabarra permite também que em uma string delimitada por aspas duplas, uma aspas
dupla seja impressa. Isso ocorrerá se a aspas dupla estiver precedida pelo caractere ‘\’. Ou
seja, o caractere ‘\’ é usado como um caractere de controle e terá o seu significado definido
dependendo do caractere que vem na sequência. Por exemplo, o comando
print("\t\"\\t\"\t\"\\n\"\n\\t\t\\n") irá gerar a seguinte saída:

74
Introdução à Programação com Python

"\t" "\n"
\t \n
O caractere de tabulação é definido somente quando aparece a sequência ‘\t’. Uma
sequência de caracteres ‘\\t’ vai imprimir ‘\t’ na tela (sem as aspas). A mesma coisa vale
para o ‘\n’. E, para imprimir as aspas duplas foi utilizada a sequência '\"' (contra barra aspas
dupla) - usada quatro vezes. Certifique-se de que no comando anterior existem apenas 3
tabulações ('\t') e um “pula linha” (\n) - estão em negrito no comando para facilitar o
entendimento.

4.1.3. Comando print() com apenas um parâmetro de texto

A linguagem Python permite tratar a exibição de várias informações como se


houvesse apenas um único parâmetro de texto, ou uma única string. Mas, e quando se
deseja imprimir uma informação que não é texto (um número, por exemplo)? Para fazer
esta “mágica” o comando de impressão possui uma diretiva de importação de informações
não textuais para dentro do texto.
Esta diretiva de importação consiste na inserção do caractere % na string seguido
do tipo da informação que será inserida no meio do texto: %d para um número inteiro
(decimal), %f para um número de ponto flutuante e %s para uma variável do tipo string.
Para informar qual valor de variável que será inserido no texto, deve ser informado o nome
da variável precedido pelo caractere %, após o fechamento da string e sem o uso de vírgula
para separar a string do nome da variável. A forma geral para utilizar o comando print desta
forma seria:
print(‘...%<t>... ‘ %<nome>)
onde: <t> especifica o tipo da variável e <nome> define o nome da variável a ser
inserida no texto na posição indicada por %<t>.
No caso de importação de mais de um valor de variáveis para dentro do texto o
caractere % seguido do tipo da variável deverá aparecer tantas vezes no corpo da string
quantas forem as variáveis a serem importadas. Após o fechamento da string, deverá vir o
caractere % seguido da lista de variáveis entre parênteses, na mesma ordem de aparição
na string e separadas por vírgulas. A forma geral seria:
print(‘...%<t1>...%<t2>... …<tN> ‘ %(<nome1>, <nome2>, … , <nomeN)
onde: <tk> para k = 1..N especifica o tipo da variável k e <nomek> define o nome da
variável k a ser inserida no texto na posição indicada por %<tk>.
A Figura 4.3 apresenta o código do programa da Figura 4.1 reescrevendo os
comandos de impressão (print()) usando um parâmetro do tipo string com a importação de
valores de variáveis.

75
Introdução à Programação com Python

Figura 4.3 - Exemplos de comando print() usando um parâmetro tipo string

Como o ambiente de desenvolvimento IDLE permite trabalhar com dois ou mais


arquivos simultaneamente, o novo programa foi salvo com o nome Figura4-3.py, conforme
pode ser observado no cabeçalho da janela. Observe que o primeiro comando print()
importou apenas uma variável (nome) do tipo string para dentro do texto. O segundo
comando print() importou duas variáveis (sexo e idade), cujos nomes aparecem entre
parênteses e separadas por vírgula, após o cacartere %. Já o último comando a string foi
criada apenas para importar o valor das duas variáveis já que não havia um texto no
comando correspondente na Figura 4.1. Mas, observe com atenção que um texto foi criado:
a colocação do caractere de espaço para separar o valor das duas variáveis importadas.
Caso isto não fosse feito a impressão sairia assim: Pirelli’s antichama20”.
Para mostrar a equivalência entre os comandos print() das Figuras 4.1 e 4.3, a
Figura 4.4 apresenta o resultado da execução do código da Figura 4.3. A janela do Shell
permanece a mesma que foi usada para a execução do programa anterior. A mensagem de
RESTART que aparece antes da execução de cada programa sempre exibe o nome do
arquivo fonte. Nesta segunda execução o arquivo fonte utilizado foi o arquivo de nome
Figura4-3.py.

Figura 4.4 - Resultado da Execução dos códigos das Figuras 4.1 e 4.3

76
Introdução à Programação com Python

As próximas figuras com exibição do resultado de execuções conterão apenas a


informação referente à última execução feita, iniciando com a mensagem de RESTART.

4.1.4. Formatação de dados no comando print()

Considere o trecho de código para imprimir as informações de cadastro de três


funcionários de uma loja fictícia, mostrado na Figura 4.5.

Figura 4.5 - Exemplo de impressão de informações cadastrais


O resultado da execução do trecho de código mostrado na Figura 4.5 é apresentado
na Figura 4.6. Note que o código apresenta 3 comandos print() utilizando apenas os nomes
das variáveis e 3 comandos print() utilizando a importação dos valores das variáveis para
dentro de uma string. Existe ainda um print() sem parâmetros, com objetivo de separar os
dois tipos conjuntos de comandos print() citados anteriormente.

Figura 4.6 - Trecho da janela do Shell com o resultado da execução do código da Figura 4.5

77
Introdução à Programação com Python

Observe que a utilização da diretiva de importação (%) não ajudou muito na


visualização. Na verdade, parece ter piorado pois os números que representam valores em
Reais (moeda do Brasil em 2020) que estavam com duas casas decimais, passaram para
seis casas decimais. Uma precisão desnecessária pois a menor unidade monetária é o
centavo (exceto para postos de gasolina) e duas casas decimais bastariam.
O caractere ‘%’ é chamado de operador de formatação de string e permite, dentre
outras coisas, definir o número de casas decimais, ou a precisão, para exibir os números
reais ou de ponto flutuante. Na verdade, a formatação permite definir o espaço que o valor
irá ocupar. Cabe ao programador definir de maneira adequada este espaçamento para que
o resultado desejado seja obtido.
A Tabela 4.3 apresenta a forma geral de definição de espaçamento para os
principais tipos de dados vistos até aqui.
Tabela 4.3 - Uso do formatador para string, inteiro e ponto flutuante
Tipo Formatador Observação

String %Ns N: especifica o espaço total reservado para a exibição do valor


(opcional).
Inteiro %Nd P: especifica a precisão (número de casas decimais), apenas no caso
de números de ponto flutuante.
Ponto flutuante %N.Pf As letras s (string), d (inteiro), f (ponto flutuante) e r (booleano)
usadas no final especificam o tipo da informação a ser importada.
Booleano %Nr

A definição do espaço para exibição do valor de uma variável usando o valor N (e P


para número real) é opcional. No caso de número de ponto flutuante é possível especificar
somente o número de casas decimais, deixando livre o espaço total, ou seja, é possível
usar, por exemplo, '%.2f' para exibir um valor com duas casas decimais. O espaço total,
neste caso, será definido pelo número de dígitos da parte inteira do valor. Se o valor na
variável fosse 102.3516 o valor impresso seria 102.35, ocupando 6 espaços (o ponto
decimal é contado).
Caso o espaço total definido pelo parâmetro N seja maior do que o necessário, o
efeito será a inserção de alguns caracteres em branco antes do início do valor impresso.
Isto ocorre porque o alinhamento padrão é feito à direita. Quando se deseja inverter o
alinhamento padrão, para que seja feito à esquerda, basta colocar o sinal negativo ‘-’ antes
do valor do parâmetro N.
Suponha que a informação dos três funcionários do código da Figura 4.5 deva ser
apresentada como se fosse uma tabela, com as informações alinhadas como se estivessem
em colunas de uma tabela. O comando para a impressão dos dados do primeiro funcionário
poderia ser reescrito como:
print('%-24s %-12s %3d %10.2f' %(nome1, cargo1, idade1, salario1))
O espaço de 24 caracteres (ou colunas no monitor de vídeo) para escrever o nome
foi função do maior nome ter 20 caracteres. Da mesma forma, o valor 12 foi escolhido, para
o espaço onde será escrito o cargo, justamente por ser um pouco maior do que a maior
string de cargo (vendedora). Ambos terão alinhamento à esquerda por causa da utilização

78
Introdução à Programação com Python

do caractere ‘-’, antes do valor numérico que definiu o espaço. O espaço de 3 colunas (ou
caracteres) foi definido para escrever o número inteiro de dois dígitos que representa a
idade do funcionário. Finalmente, para escrever o valor do salário foi escolhido o
espaçamento total de 10 colunas, com duas casas decimais. Estes dois últimos valores tem
alinhamento padrão, à direita.
Para exibir a informação dos outros dois servidores serão usados comandos de
impressão com o mesmo espaçamento deste primeiro. Será colocado um comando
adicional para imprimir um cabeçalho para a tabela, antes dos comandos para imprimir as
informações dos funcionários. Este comando pode ser definido da seguinte maneira:
print('Nome%20s Cargo%7s Idade Salário' %(' ', ' '))
O comando acima importa dois caracteres branco (ou espaço) para a string.
‘Nome… ...Salário’. Para o primeiro caractere foram reservados 20 espaços que juntamente
com os caracteres ‘Nome’ totalizam os mesmos 24 caracteres reservados para imprimir o
nome do funcionário. Ou seja, os espaços escolhidos para a impressão do cabeçalho e para
a impressão das informações dos servidores foram de tal forma a dar a ideia de uma tabela.
A Figura 4.7 mostra o código com os comandos de impressão alterados conforme a
discussão apresentada.

Figura 4.7 - Código da Figura 4.5 com comandos de impressão reescritos

Um detalhe importante a ser observado é que para este efeito de impressão do tipo
tabela pressupõe, neste caso, que o tamanho total das strings sejam o mesmo, pois existe o
alinhamento à esquerda da primeira coluna e o alinhamento à direita da última coluna. Note
que a string do cabeçalho reserva 27 espaços, tem 4 caracteres branco (entre Idade e
Salário são 2) e 21 letras (NomeCargoIdadeSalário) totalizando, portanto, um espaço de 52
caracteres. E cada comando de impressão das informações do funcionário tem três
caracteres branco (separando os formatadores para facilitar o entendimento) e reserva
24+12+3+10=49 espaços, totalizando também um espaço de 52 caracteres. O resultado da
execução do código mostrado na Figura 4.7 é apresentado na Figura 4.8.

79
Introdução à Programação com Python

Figura 4.8 - Resultado da execução do código da Figura 4.7

Caso os comandos de impressão das informações fossem reescritos sem os


caracteres em branco, usados para facilitar a visualização, o espaçamento deveria ser
alterado para manter o alinhamento por coluna com o mesmo número de espaços. Por
exemplo, se o comando de exibição das informações do segundo funcionário fosse reescrito
como:
print('%-25s%-13s%3d%11.2f' %(nome2, cargo2, idade2, salario2))
O resultado gerado seria exatamente o mesmo da Figura 4.8 Como o parâmetro do
comando print() é uma string, para cada espaço em branco retirado da string, um aumento
no espaçamento foi feito. Observe que a string continuou com um tamanho total de 52
caracteres (25+13+3+11).

4.2 - Comando de Entrada

O comando input() permite ler um valor fornecido utilizando o dispositivo padrão de


entrada, o teclado. O valor lido deve ser atribuído para uma variável. A forma geral do
comando input() é a seguinte:
<variável> = input(<msg>)

<variável> representa um nome válido de uma variável Python que receberá o valor
lido. <msg> representa uma mensagem que será exibida na tela. Esta mensagem é útil para
que o usuário seja orientado sobre qual a informação que deverá ser fornecida.

A execução do comando input() causa uma parada na execução do programa que


espera que uma informação seja enviada, ou uma entrada seja fornecida. No dispositivo
padrão de entrada que é o teclado, após digitar o valor da entrada o seu envio é feito ao
pressionar a tecla ‘Enter’.

Um exemplo de um pequeno programa Python utilizando um comando de entrada e


um comando de saída é mostrado na janela do editor do IDLE na Figura 4.9. A mesma
figura apresenta também a janela do Shell sobreposta à janela do editor, com o resultado da
execução do programa Figura4-9.py.

80
Introdução à Programação com Python

Figura 4.9 - Programa simples com comando de entrada e saída.

Na janela do Shell do IDLE, conforme já observado, o texto em azul corresponde às


informações geradas pelo comando de saída. Porém, a mensagem associada ao comando
de entrada input() utiliza a mesma cor, pois no fundo trata-se de uma informação de saída,
ou uma informação que é exibida pelo programa. Assim, o programa da Figura 4.9 exibe a
mensagem ‘Entre com o seu nome: ’ e para, aguardando a entrada que será fornecida pelo
usuário.

O texto em preto ‘José da Silva’ foi fornecido pelo usuário do programa, que após a
digitação deste texto, pressionou a tecla ‘Enter’. Neste momento, o valor da string ‘José da
Silva’ é atribuído para a variável nome. Na sequência, o comando de impressão escreve na
tela a string com a importação do valor da variável nome, resultando no texto em azul ‘Bom
dia, José da Silva!’

Por padrão, na linguagem Python, o valor recebido via teclado é interpretado como
string (uma sequência de caracteres). Se o usuário digitar ‘125’ este valor representa um
texto com os caracteres que representam os algarismos 1, 2 e 5 e não o número 125. Para
que uma entrada seja interpretada como um valor numérico inteiro ou real (ponto flutuante)
é necessário explicitar a transformação usando int ou float, respectivamente. A Figura 4.10
apresenta um pequeno programa exemplificando a transformação para inteiro e ponto
flutuante.

Na Figura 4.10, a variável idade será do tipo inteiro (int) e na execução do programa
lhe foi atribuído o valor 56. Já a variável altura será do tipo ponto flutuante (float) com valor
definido na execução do programa igual a 1.77. Observando, mais uma vez, que na janela
do Shell os valores em azul foram escritos pelo programa e os valores em preto foram
fornecidos pelo usuário.

81
Introdução à Programação com Python

Figura 4.10 - Exemplo de transformação para inteiro e real

A conversão pode ser aplicada em qualquer comando de atribuição e não apenas


em comandos de entrada e saída. Alguns exemplos comentados:

age = int(‘18’) # age recebe o valor inteiro 18


x = int(3.14) # x recebe o valor inteiro 3
alt = float(‘1.75’) # alt recebe o valor real 1.75
y = float(x) # y recebe o valor real 3.0

4.3 - Usando os comandos de entrada e saída em programas


simples

A seguir são apresentados dois problemas simples que, em princípio poderiam ser
resolvidos com as informações vistas até aqui: algoritmos, refinamentos sucessivos,
variáveis, expressões aritméticas e comandos de entrada e saída.

Na sequência será mostrado que para os dois casos a solução correta deve
considerar outra estrutura de programação que será vista no próximo capítulo. Mas que
com o conhecimento de algoritmos já é possível identificar o problema e resolvê-lo em
termos de algoritmo. Porém, como as soluções agora são utilizando a linguagem Python,
elas serão apresentadas no capítulo 5.

4.3.1. Cálculo da área de um triângulo

Considere que os valores (inteiros e positivos) a, b e c correspondem aos lados de


um triângulo qualquer. Pelo Teorema de Heron, é possível determinar a área desse triângulo
como sendo igual a:

𝐴𝑟𝑒𝑎 = 𝑝(𝑝 − 𝑎)(𝑝 − 𝑏)(𝑝 − 𝑐), onde 𝑝 = (𝑎 + 𝑏 + 𝑐) ÷ 2

82
Introdução à Programação com Python

O problema a ser resolvido é muito simples e com as fórmulas necessárias já


conhecidas. Aliás, conhecidas há muito tempo pois foram formuladas por Heron de
Alexandria que foi um matemático grego que viveu nos anos 10 a 70 DC. O algoritmo para
resolver este problema poderia ser apresentado como:
1. Ler os valores a, b e c
2. Calcular o valor de p
3. Calcular a área
4. Exibir a área calculada

Uma versão refinada do algoritmo poderia ser escrita como:


1. Leia(a)
2. Leia(b)
3. Leia(c)
4. p = (a+b+c)/2
5. area = raizquadrada(p.(p-a).(p-b).(p-c))
6. imprima(area)

Esta segunda versão já estaria em um nível de detalhe suficiente para a tradução


para Python. Entretanto, como calcular a raiz quadrada? Em Python existe uma biblioteca
matemática com diversas funções, dentre elas a função raiz quadrada. Mas, pode-se utilizar
a exponenciação, cujo operador já foi apresentado no capítulo 3. Esta operação será
detalhada na próxima versão do algoritmo. Também será inserida uma mensagem inicial
para que um usuário que não seja o autor do programa saiba do que se trata.

Feitas estas considerações, a versão final do algoritmo será:


1. Imprima(‘Cálculo da área de um triângulo de lados a, b e c’)
2. Leia(a)
3. Leia(b)
4. Leia(c)
5. p = (a+b+c)/2
6. area = (p.(p-a).(p-b).(p-c)) ** 0.5
7. imprima(area)

A Figura 4.11 apresenta o código Python correspondente. Note que o operador de


multiplicação do algoritmo teve de ser convertido para o operador de multiplicação (*) da
linguagem Python.

Figura 4.11 - Programa para cálculo da área de um triângulo

Para testar o funcionamento do programa, ele foi executado três vezes e os


resultados destas três execuções estão mostrados na Figura 4.12, capturada da janela do
Shell do IDLE.

83
Introdução à Programação com Python

Figura 4.12 - Três execuções do programa da Figura 4.11

Para a primeira execução foram fornecidos os valores 4, 3 e 5 que representam os


lados de um triângulo retângulo bastante utilizado nos livros de matemática quando se
aborda o teorema de Pitágoras (𝑐² = 𝑎² + 𝑏², o quadrado da hipotenusa (25) é igual a
soma do quadrado dos catetos (16+9)). Para este triângulo, a fórmula
á𝑟𝑒𝑎 = 𝑏𝑎𝑠𝑒 𝑥 𝑎𝑙𝑡𝑢𝑟𝑎 / 2 é válida. Considerando que um dos catetos é a base do triângulo,
o outro cateto será a altura e o cálculo seria á𝑟𝑒𝑎 = 4 𝑥 3 / 2 = 6, mostrando que o cálculo
do programa está correto.

Entretanto, as segunda e terceira execuções apresentaram resultados esquisitos. Na


segunda o programa informou que a área do triângulo é zero! E na terceira ocorreu um erro
na execução. O que ocorreu em ambas as situações é que os valores informados para os
lados do triângulo não formam um triângulo. Para que seja possível formar um triângulo,
nenhum dos lados pode ser maior ou igual a soma dos outros dois lados.

Na segunda execução, o lado a é exatamente igual à soma dos lados b e c.


Portanto, com 𝑎 = 𝑏 + 𝑐, a propriedade para formar um triângulo não é satisfeita. Se você
tentar desenhar um triângulo unindo os três segmentos de reta, perceberá que para fazer a
união dos vértices, os lados b e c teriam que ficar sobre o lado a, formando uma figura que
teria área zero. Mas que não é um triângulo, e sim um segmento de reta de tamanho 4.

No terceiro caso, os valores informados para os lados também não permitem a


formação de um triângulo, pois 𝑎 > 𝑏 + 𝑐. Além disso, o cálculo do valor de
𝑝 = (𝑎 + 𝑏 + 𝑐)/2será igual a 3.5. O fator (𝑝 − 𝑎) será -0.5, levando o produto
𝑝 * (𝑝 − 𝑎) * (𝑝 − 𝑏) * (𝑝 − 𝑐)a um valor negativo (-7). Na linguagem Python o cálculo de
− 7é feito, mas o resultado é um número complexo e no comando de impressão foi
suposto que o tipo da variável area seria um número de ponto flutuante. A mensagem de
erro do Shell (TypeError: can’t convert complex to float) informa que não foi possível
converter um número complexo para ponto flutuante.

Mas, este erro só ocorreu porque a condição necessária para determinar se com os
valores informados para os lados (a, b e c) seria, de fato, possível formar um triângulo. Esta

84
Introdução à Programação com Python

condição deveria ser verificada antes de se fazer o cálculo da área. E, em caso negativo,
deveria ser informado ao usuário que não é possível representar um triângulo com os
valores fornecidos. No próximo capítulo será apresentada a solução para este caso.

4.3.2. Cálculo das raízes de uma equação do segundo grau

Um outro problema bastante conhecido é o cálculo das raízes de uma equação do


segundo grau definida pela expressão 𝑎𝑥² + 𝑏𝑥 + 𝑐 = 0 ou representada como uma
função 𝑓(𝑥) = 𝑎𝑥² + 𝑏𝑥 + 𝑐. Os coeficientes a, b e c são valores reais e o coeficiente a
deve ser diferente de zero, pois caso contrário a função não será de segundo grau (x²).

O cálculo das raízes de uma equação de segundo grau pode ser feito utilizando a
fórmula de Bháskara 𝑥 = (− 𝑏 ± 𝑏² − 4𝑎𝑐)/2𝑎.

Conhecendo o problema e sabendo como calcular a resposta, o seguinte algoritmo


poderia ser proposto:
1. Imprima(‘Forneça os coeficientes da equação de segundo grau’)
2. Leia(a)
3. Leia(b)
4. Leia(c)
5. 𝑥1 = (− 𝑏 + 𝑏² − 4𝑎𝑐)/2𝑎
6. 𝑥2 = (− 𝑏 − 𝑏² − 4𝑎𝑐)/2𝑎
7. Imprima(x1, x2)

A implementação do algoritmo acima está mostrado na Figura 4.13. Note que no


algoritmo não há uma preocupação formal com a ordem de execução das operações,
diferentemente do que ocorre nas linguagens de programação. No algoritmo, o numerador
foi colocado entre parênteses, indicando que todas as suas operações devem ser feitas
antes da divisão por “2a”.

Porém, se o divisor (2*a) não for colocado entre parênteses no programa Python,
ocorrerá primeiro uma divisão por 2 e depois uma multiplicação por a. A colocação dos
parênteses forçará primeiro a ocorrência da multiplicação 2*a e, depois, a divisão por “2a”.
Observe que a expressão para cálculo da segunda raiz escreve de maneira diferente (e
correta) o divisor “2a”. O cálculo de b² também foi feito de maneira diferente nas duas
expressões, mas ambas corretas.

Figura 4.13 - Programa para cálculo de raízes de equação do segundo grau

Para testar o programa foram feitas três execuções para diferentes valores de
coeficientes. Nas duas primeiras execuções o programa respondeu corretamente com as

85
Introdução à Programação com Python

raízes das duas equações. Porém, na terceira execução o Shell apontou um erro de divisão
por zero (ZeroDivisionError: float division by zero), conforme mostrado na Figura 4.14.

Figura 4.14 - Resultado de execuções do programa da Figura 4.13

A razão do erro está no fato do valor fornecido para o coeficiente a ter sido zero. A
fórmula de Bháskara pressupõe que o coeficiente a será diferente de zero. De fato, se a for
zero, a equação não será de segundo grau. Para a terceira execução, com os coeficientes
informados, a equação seria: 2𝑥 + 1 = 0 uma equação de primeiro grau.

O programa deveria ter verificado se o valor fornecido para o coeficiente a é


diferente de zero, para prosseguir com o cálculo. Se o valor for zero do coeficiente a for
zero, a equação não é de segundo grau e, portanto, o programa deveria informar que com
este valor não é possível calcular as raízes e terminar a execução do programa. De forma
similar ao exemplo de cálculo de área de triângulo, cuja solução será vista no próximo
capítulo.

Alternativamente, o programa poderia informar que o valor zero é inválido e solicitar


que o usuário forneça uma novo valor. E só prosseguir com a execução do programa após o
usuário fornecer um valor diferente de zero. Este tipo de solução será visto no capítulo 6
com a apresentação das estruturas de comando repetitivo da linguagem Python.

4.4. Exercícios

1) Edite o trecho de código do exercício 1 do capítulo 3 usando o editor de programas


do IDLE e inclua comandos de impressão para informar os nomes e os valores das
variáveis separadas por tipo (inteiro ou de ponto flutuante). A saída do programa
deve ser como a mostrada a seguir:

86
Introdução à Programação com Python

2) Altere os comandos de impressão do exercício anterior para gerar uma saída similar
à mostrada a seguir. A quebra de linha será determinada pela largura da janela do
Shell, por isso o resultado deve ser similar e não exatamente igual ao exibido
abaixo. Na solução deve haver um único comando para imprimir os nomes e valores
das variáveis inteiras e um outro único comando para imprimir os nomes e valores
para as variáveis reais (ou de ponto flutuante). As mensagens de texto devem ser
feitas em comandos de impressão separados, ou seja, deverão existir apenas 4
comandos de impressão no programa.

3) Altere os comandos de impressão do exercício anterior para gerar uma saída igual
à mostrada a seguir, onde os números de ponto flutuante são apresentados com
precisão de 3 casas decimais (use %f para formatar os números reais).

4) Modifique os comandos de impressão usados no exercício anterior para mostrar a


saída com os valores exibidos em colunas de largura 6 (use %d para formatar
também os números inteiros). Observe com atenção que os caracteres de texto (“,” e
“e”) usados na versão anterior para separar as informações não são mais exibidos.

87
Introdução à Programação com Python

5) A solução adotada no exercício anterior não ficou visualmente agradável,


particularmente para os valores inteiros, que aparecem longe do caractere “=”. Altere
os comandos de impressão para que a saída seja igual à mostrada a seguir:

6) Para melhorar a organização visual da saída, altere os comandos de impressão para


que os valores sejam impressos com espaço total 10, tendo no máximo 3 valores
por linha, como mostrado a seguir. Dica: use a quebra de string (\n) e mantenha o
mesmo número de comandos print da versão anterior.

7) Mude o comando de atribuição da variável inteira A para que a atribuição seja feita
por um valor fornecido pelo usuário. Note na figura mostrada a seguir que o valor
digitado pelo usuário aparece na cor preta, enquanto que os valores escritos pelo
programa aparecem em azul. Altere também o comando de impressão das variáveis
de ponto flutuante, para que o alinhamento seja feito à direita (alinhando o ponto
decimal dos valores). Na figura é mostrado um exemplo no qual o usuário forneceu o
valor 10.

8) Altere o programa para que sejam lidos dois valores: um inteiro que será atribuído
para a variável A e outro valor real que será atribuído para a variável E. O programa
deve deixar claro para o usuário que o primeiro valor tem que ser inteiro e o segundo

88
Introdução à Programação com Python

um valor real. A figura mostrada a seguir apresenta um exemplo de execução no


qual o usuário informou os valores 12 e 3.5, nesta ordem.

9) Edite o trecho de código do exercício 2 do capítulo 3 usando o editor de programas


do IDLE e inclua comandos de impressão para informar os nomes e os valores das
variáveis separadas por tipo (inteiro ou booleano). A saída do programa deve ser
como a mostrada a seguir:

10) Altere os comandos de impressão do exercício anterior para gerar a saída similar à
mostrada na figura a seguir. O programa deve usar um único comando para imprimir
os nomes e valores de todas as variáveis inteiras e um outro único comando para
imprimir os nomes e valores de todas as variáveis booleanas. As mensagens de
texto devem ser feitas em comandos de impressão separados, ou seja, deverão
existir apenas 4 comandos de impressão no programa.

11) Modifique os comandos de impressão do exercício anterior, utilizando um espaço de


5 posições para imprimir o valor de cada variável (inteira ou booleana). Deverão ser

89
Introdução à Programação com Python

impressas até 4 variáveis por linha, para gerar uma saída exatamente igual à
mostrada a seguir.

12) Modifique os comandos de impressão da versão anterior para que o programa gere
a saída igual à mostrada a seguir.

13) No programa gerado para resolver o exercício anterior, inclua comandos de leitura
para que o usuário forneça o valor das 3 variáveis inteiras (A, B e C). Com valores
diferentes, algumas das expressões podem gerar resultados diferentes, modificando
os valores das variáveis booleanas. A figura mostrada a seguir apresenta o
resultado da execução na qual o usuário forneceu os valores -10, 13 e 10,
respectivamente, para as variáveis A, B e C.

14) Escreva um programa para imprimir as variáveis tipo texto do exercício 3 do capítulo
3, sendo uma variável em cada linha. No final do programa, inclua os comandos
mostrados a seguir e observe as diferenças entre as saídas.

print('\nNome: %s %s Sexo: %s' %(nome, sobrenome, sexo))


print('\nNome:\t%s %s\tSexo:\t%s' %(nome, sobrenome, sexo))
print('\nNome:%s %30s Sexo:%10s' %(nome, sobrenome, sexo))
print('\nNome:%s %-30s Sexo:%-10s' %(nome, sobrenome, sexo))
print('\Nome:\t%s %s\nSexo:\t%s' %(nome, sobrenome, sexo))

90
Introdução à Programação com Python

15) Escreva um programa que solicite ao usuário o valor de temperatura em graus


Fahrenheit, calcule e informe o valor correspondente em graus Celsius, de acordo
𝐶 𝐹−32
com a fórmula: 5 = 9 . O programa deverá informar o resultado com 1 casa
decimal, conforme o exemplo mostrado a seguir.

16) Escreva um programa para calcular a área de um círculo, sabendo o valor do raio
(R). O programa deverá gerar uma saída como a mostrada a seguir.

17) Escreva um programa para calcular o k-ésimo elemento de uma Progressão


Aritmética cujos valores do primeiro elemento e da razão serão fornecidos pelo
usuário. O programa deverá calcular também a soma dos k elementos da PA. A
execução do programa deverá ser como o mostrado na figura a seguir. Dica:
pesquise na Internet a fórmula da soma dos elementos de uma PA.

18) Escreva um programa para calcular a soma dos N primeiros elementos de uma
Progressão Geométrica (PG), cujos valores do primeiro elemento e da razão serão
solicitados ao usuário. O programa deverá informar também o valor do N-ésimo
elemento. A figura a seguir mostra um exemplo de como deve ser a execução do
programa. Dica: pesquise na Internet a fórmula da soma dos elementos de uma PG.

91
Introdução à Programação com Python

Capítulo 5 - Comandos Condicionais

A estrutura de comando condicional permite definir caminhos alternativos para o


fluxo de execução do programa. Até este ponto os programas apresentados foram todos
sequenciais, onde a execução era iniciada pelo primeiro comando (primeira linha do código
fonte) e depois percorria sequencialmente as demais linhas do código, até chegar ao seu
final.

No final do capítulo passado vimos dois exemplos de programas que podem


apresentar falhas na execução dependendo dos valores fornecidos pelo usuário (cálculo da
área de um triângulo e cálculo das raízes de uma equação do segundo grau). Para estes
dois casos, a solução passa por validar os valores fornecidos pelo usuário, usando um (ou
mais) comandos condicionais.

5.1. Comando if

Em algumas situações um comando ou um bloco de comandos só deve ser


executado quando uma determinada condição for verdadeira. Para isto, na linguagem
Python existe a estrutura de comando condicional mostrada na Figura 5.1.

if <condição> :
<comando>

Figura 5.1 - Estrutura de comando condicional if

Note que, na sintaxe da linguagem Python, o comando é definido pela palavra


reservada if, uma <condição> finalizada pelo caracter ‘:‘ e, na sequência um bloco de um ou
mais comandos deslocados à direita, representado por <comando> na Figura 5.1. Este
deslocamento à direita ou indentação do código é obrigatório na linguagem Python, sendo
considerado um erro de sintaxe a sua não utilização.

A execução do comando condicional se dá da seguinte maneira: primeiramente a


condição é avaliada e caso o resultado da avaliação seja verdadeiro, o bloco de comandos
vinculados à condição será executado. Se a condição for falsa, o bloco de comandos não
será executado, passando-se para o próximo comando. Portanto, com este tipo de
estrutura, um comando (ou um bloco de comandos) poderá ser executado ou não,
dependendo da condição ser verdadeira ou falsa.

A indentação (deslocamento) auxilia na identificação visual dos comandos que serão


executados condicionalmente e, além disso, define quais são os comandos que pertencem
ao bloco de comandos. O próximo comando sequencial deverá ser escrito alinhado com a

92
Introdução à Programação com Python

palavra reservada if. Considere a Tabela 5.1 com um código genérico de comandos Ci e o
fluxo de execução para os casos da condição ser verdadeira ou falsa.

Tabela 5.1 - Exemplos dos dois fluxos de execução possíveis de comandos condicionais
Código Sequência de execução quando Sequência de execução quando
<condição> == True <condição> == False

C1 C1 C1
C2 C2 C2
if <condição> : C3 C5
C3 C4 C6
C4 C5
C5 C6
C6

C1 C1 C1
C2 C2 C2
if <condição> : C3 C4
C3 C4 C5
C4 C5 C6
C5 C6
C6

Para exemplificar, considere o programa para cálculo da área de triângulos da seção


4.3.1. Para evitar o erro de tentativa de cálculo de área com lados que não formam um
triângulo é necessário testar se com os valores fornecidos para os lados (a, b e c) é
possível construir um triângulo. Em caso positivo, o cálculo será feito. O algoritmo poderia
ser reescrito da seguinte forma:

1. Imprima(‘Cálculo da área de um triângulo de lados a, b e c’)


2. Leia(a)
3. Leia(b)
4. Leia(c)
5. Se “é triângulo?” :
5.1. p = (a+b+c)/2
5.2. area = (p.(p-a).(p-b).(p-c)) ** 0.5
5.3. imprima(area)

Note que os comandos 5.1, 5.2 e 5.3 constituem o bloco de comandos


condicionados ao teste “é triangulo?” e que, portanto, só serão executados quando o teste
for verdadeiro. Caso o teste seja falso, o programa vai para o próximo comando, que não
existe, ou seja, o programa termina sem que o cálculo seja feito.

A condição “é triângulo?” consiste em testar, para cada lado se este lado é menor
que a soma dos outros dois lados. A condição tem que ser verdadeira para cada um dos
lados, logo a junção deve ser feita pela função lógica E (and), como a seguir:

𝑎<𝑏+𝑐 𝐸 𝑏<𝑎+𝑐 𝐸 𝑐<𝑎+𝑏

A seguir, o algoritmo com a condição detalhada e sem a numeração dos comandos.


A partir deste ponto, a ordem de execução dos comandos vai estar explícita pela
indentação, sem a necessidade de numerar os comandos sequenciais que estarão
alinhados no bloco ao qual eles pertencem.ser reescrito da seguinte forma:

93
Introdução à Programação com Python

Imprima(‘Cálculo da área de um triângulo de lados a, b e c’)


Leia(a)
Leia(b)
Leia(c)
Se a<b+c E b<a+c E c<a+b :
p = (a+b+c)/2
area = (p.(p-a).(p-b).(p-c)) ** 0.5
imprima(area)

A implementação do algoritmo acima, na linguagem Python é mostrada na Figura


5.2. Observe que as palavras reservadas if e and são exibidas em cor laranja no editor de
programas. Da mesma forma outras cores são usadas para outras palavras reservadas da
linguagem (print, float e input) e verde para as strings,delimitadas neste código com aspas
simples. É importante prestar atenção nestes detalhes, pois alguns erros de sintaxe ficam
mais fáceis de enxergar com o esquema de cores do editor de programas.

Figura 5.2 - Programa para cálculo de área de triângulos

A Figura 5.3 mostra o resultado da execução do programa da Figura 5.2 usando os


mesmos 3 conjuntos de valores utilizados nas execuções apresentadas na Figura 4.12.
Observe que agora, como a condição de que os lados podem formar um triângulo está
sendo testada, as saídas informando uma área zero ou com erro de transformação de tipos
não ocorrem mais.

Figura 5.3 - Execuções do código da Figura 5.2

Entretanto, com a solução apresentada um usuário que não tenha escrito o


programa pode ficar com a impressão que o programa não funcionou em duas das três
tentativas. Na próxima seção será mostrada uma solução para este problema.

94
Introdução à Programação com Python

5.2 Comando if-else

Eventualmente, para uma dada condição é desejável executar uma sequência de


comandos quando ela for verdadeira ou uma outra sequência de comandos quando ela for
falsa. Para atender a estes casos a linguagem de programação Python possui a seguinte
estrutura mostrada na Figura 5.4.

if <condição> :
<comando1>
else:
<comando2>
Figura 5.4 - Estrutura de comando condicional if/else

A sintaxe do comando é a mesma do comando if simples, com a inclusão da


cláusula else identificada pela palavra reservada else e o caractere ’:’. A palavra reservada
else deve estar alinhada com a palavra reservada if. Os blocos de comandos da cláusula if
e da cláusula else devem estar alinhados e deslocados para a direita. Esta é a indentação
definida para o comando if-else.

No comando condicional, o teste da condição sempre é executado primeiro. Caso o


teste seja verdadeiro <comando1> será executado. Caso contrário (else), <comando2> será
executado. Ou seja, o fluxo de execução do programa neste tipo de estrutura tem dois
caminhos alternativos. Em uma execução, um dos dois blocos sempre será executado, mas
apenas ele. Os blocos <comando1> e <comando2> nunca serão executados em sequência.
A execução de um bloco, exclui necessariamente a execução do outro. O resultado da
avaliação da expressão irá determinar qual dos dois será executado.

Tabela 5.2 - Exemplos dos dois fluxos de execução possíveis de comandos condicionais
Código <condição> = True <condição> = False

C1 C1 C1
if <condição> : C2 C4
C2 C3 C5
C3 C6 C6
else:
C4
C5
C6

C1 C1 C1
if <condição> : C2 C4
C2 C3 C5
C3 C5 C6
else: C6
C4
C5
C6

95
Introdução à Programação com Python

Para exemplificar, o algoritmo para cálculo da área de triângulos pode ser


ligeiramente modificado para informar ao usuário que os valores informados para os lados
do triângulo não permitem formar um triângulo:

Imprima(‘Cálculo da área de um triângulo de lados a, b e c’)


Leia(a)
Leia(b)
Leia(c)
Se a<b+c E b<a+c E c<a+b :
p = (a+b+c)/2
area = (p.(p-a).(p-b).(p-c)) ** 0.5
imprima(area)
Senão:
imprima(‘Os lados informados não formam um triângulo’)

A implementação deste algoritmo está mostrado na Figura 5.5. O uso do ‘:’ e da


indentação no algoritmo não são obrigatórios, porém, é uma boa prática para que a solução
algorítmica fique mais parecida com o programa.

Figura 5.5 - Uso do comando if-else

Agora, com a cláusula else sempre que os lados informados não puderem formar
um triângulo, a mensagem ‘Os lados informados não formam um triângulo’. será
apresentada ao usuário.

Suponha que o programa tenha sido feito para uso de alunos do ensino fundamental
e que a mensagem de erro não seja considerada adequada. O que se pretende é a
utilização de uma mensagem que mostre a razão da impossibilidade do cálculo. Deverá ser
informado que nenhum dos lados pode ser maior ou igual à soma dos outros dois e, além
disso, apresentar qual lado está violando a condição da formação de triângulo.

Será considerado apenas o bloco da cláusula “senão” para refinarmos o que o


algoritmo deverá executar quando a condição testada no primeiro comando condicional for
falsa.
imprima(‘Os lados informados não formam um triângulo’)
imprima(‘Nenhum dos lados pode ser maior ou igual à soma dos outros lados’)
se a >= b+c :
imprima(‘a deve ser menor que (b+c)’)
senão:
se b>=a+c :
imprima(‘b deve ser menor que (a+c)’)
senão:
imprima(‘c deve ser menor que (a+b)’)

96
Introdução à Programação com Python

Figura 5.6 - Programa Python com uso de comandos if aninhados

O código correspondente a este algoritmo é apresentado na Figura 5.6. Este tipo de


solução utiliza comandos condicionais aninhados. Na execução deste código sempre que a
condição do primeiro comando condicional for verdadeira (linha 5), o bloco de comandos
para calcular e informar a área (linhas 6-8) será executado e o programa termina.

Quando o resultado da condição do primeiro comando condicional for falsa, o fluxo


de execução vai para o bloco de comandos da cláusula else e os dois comandos de
impressão (linhas 10 e 11) são executados. Na sequência é testada a condição (linha 12) do
comando if que verifica se foi o lado a que violou a condição de formação do triângulo. Se
esta condição for verdadeira será informado para o usuário que ‘a deve ser menor que
(b+c)’ e o programa termina.

Se a condição da linha 12 for falsa, o fluxo de execução será desviado para a


cláusula else correspondente (linha 14) e um novo teste do comando condicional da linha
15 será realizado. Este teste verifica se foi o lado b que violou a condição de formação de
triângulo. Sendo verdadeira esta condição (linha 15) a mensagem ‘b deve ser menor que
(a+c)’ será impressa e o programa termina. E, finalmente, se a condição da linha 15 for
falsa, o comando de impressão da última linha escreverá ‘c deve ser menor que (a+b)’
informando que o problema é com o lado c. Repare não foi necessário colocar um terceiro
teste para saber se o problema foi devido ao lado c, pois para chegar nesta última linha,
ambos os testes que verificaram, respectivamente, se o problema era com o lado a e b
foram falsos.

5.3 Comando if-elif-else

O uso dos comandos condicionais aninhados possui uma desvantagem em relação


à organização do código. Quando o nível de aninhamento começa a aumentar, a indentação
obrigatória dos blocos, vai fazendo um deslocamento do código para a direita. Isso, muitas
vezes, prejudica uma visualização de trechos do código na janela do editor de programas.

A linguagem Python possui uma outra forma de comando condicional que permite
resolver este problema. A estrutura if-elif-else é mostrada na Figura 5.7.

97
Introdução à Programação com Python

if <condição1> :
<comando1>
elif <condição2>:
<comando2>

elif <condiçãoN>:
<comandoN>
...
else:
<comandoN+1>
Figura 5.7 - Estrutura de comando condicional if/elif/else

A sintaxe do comando é a mesma do comando if-else com a inclusão da cláusula elif


entre elas. Podem existir uma ou mais cláusulas elif sendo que cada uma deve especificar
uma <condição> sucedida pelo caractere ‘:’. A palavra reservada elif deve estar alinhada
com as palavras reservadas if e else. Os blocos de comandos das cláusulas if, elif e else
devem estar alinhados e deslocados para a direita. Esta é a indentação definida para o
comando if-elif-else.

O funcionamento desta estrutura é equivalente à utilização de comandos


condicionais (if) aninhados. A <condição1> é testada e se for verdadeira, <comando1> será
executado e o comando condicional termina. Se <condição1> for falsa, o fluxo de execução
vai testar a <condição2>. Se esta segunda condição for verdadeira, <comando2> será
executado e o comando condicional termina. Podem existir várias cláusulas elif, cada uma
com uma condição a ser testada. Se todas as N condições forem testadas e todos os
resultados forem falsos, o bloco <comandoN+1> associado à cláusula else será executado.
As condições são testadas na ordem em que aparecem no comando. Se houver duas ou
mais condições verdadeiras, a condição que aparece primeiro, ao ser testada, fará com que
o bloco de comandos associado a ela seja executado e o comando condicional termina.

Note que, com esta estrutura, todos os blocos do comando condicional estarão com
o mesmo alinhamento ou com a mesma indentação. A Tabela 5.3 exemplifica os possíveis
fluxos de instrução para um comando if-elif-else com duas condições.

Tabela 5.3 - Exemplos dos possíveis fluxos de execução de um comando if-elif-else.


Código <condição1> = True <condição1> = False <condição1> = False
<condição2> não <condição2> = True <condição2> = False
importa

C1 C1 C1 C1
if <condição1> : C2 C4 C6
C2 C3 C5 C7
C3 C8 C8 C8
elif <condição2>:
C4
C5
else:
C6
C7
C8

98
Introdução à Programação com Python

No algoritmo a cláusula elif pode ser escrita como “Senãose”. Usando esta notação,
o final do algoritmo que identifica e informa qual o lado do triângulo que está violando a
condição pode ser reescrito como:

imprima(‘Os lados informados não formam um triângulo’)


imprima(‘Nenhum dos lados pode ser maior ou igual à soma dos outros lados’)
Se a >= b+c :
imprima(‘a deve ser menor que (b+c)’)
Senãose b>=a+c :
imprima(‘b deve ser menor que (a+c)’)
Senão:
imprima(‘c deve ser menor que (a+b)’)

Ao analisar o algoritmo, foi percebido que a mensagem do tipo ‘a deve ser menor
que (b+c)’ não representa bem a informação, por exemplo, quando o lado a está violando a
condição de formação do triângulo. Talvez fosse melhor usar algo do tipo ‘a >= (b+c)’. Ou de
forma mais detalhada, usando o potencial da estrutura condicional que permite vários
“senãose” e informar mais precisamente que ‘a > (b+c)’ ou ‘a = (b+c)’. Dessa forma, o final
do algoritmo pode ser reescrito como:

imprima(‘Os lados informados não formam um triângulo’)


imprima(‘Nenhum dos lados pode ser maior ou igual à soma dos outros lados’)
Se a > b+c :
imprima(‘a > (b+c)’)
Senãose a==b+c :
imprima(‘a = (b+c)’)
Senãose b>a+c :
imprima(‘b > (a+c)’)
Senãose b==a+c :
imprima(‘b = (a+c)’)
Senãose c>a+b :
imprima(‘c > (a+b)’)
Senão:
imprima(‘c = (a+b)’)

A Figura 5.8 apresenta a versão final do programa completo para cálculo da área de
um triângulo utilizando a estrutura if-elif-else.

99
Introdução à Programação com Python

Figura 5.8 - Versão final do programa para cálculo da área de um triângulo

A Figura 5.9 mostra a captura de janelas do comando if-elif-else do programa da


Figura 5.8, ao lado de outro código utilizando comandos condicionais aninhados. Note como
a versão if-elif-else fica mais compacta. Ambos possuem as mesmas comparações, na
mesma ordem, e os mesmos comandos de impressão. Nos dois casos, o resultado será o
mesmo: a impressão de apenas uma das seis mensagens, sempre que os lados não
formarem um triângulo.

Figura 5.9 - Comparação entre o uso de ifs aninhados e if-elif-else

A Figura 5.10 mostra o resultado da execução do programa da Figura 5.8 para as


mesmas três situações da Figura 5.3. Na primeira execução é possível calcular a área e nas
duas seguintes não.

100
Introdução à Programação com Python

Figura 5.10 - Exemplos de execução da versão final do programa Figura 5.8

5.4 Cálculo de raízes de uma equação do 2⁰ grau

O problema introduzido na seção 4.3.2 trata do cálculo das raízes de uma equação
do segundo grau, na forma 𝑎𝑥² + 𝑏𝑥 + 𝑐 = 0, tendo sido implementado um programa
mostrado na Figura 4.13. Conforme discutido naquela seção, o programa proposto como
solução possui um problema por não testar se o valor fornecido pelo usuário para o
coeficiente a era diferente de zero. A solução para este problema seria trivial com o uso de
comando condicional, para calcular as raízes apenas quando o coeficiente fosse diferente
de zero.

Um outro caso que precisa ser testado é referente ao discriminante da equação,


definido como Δ = 𝑏² − 4𝑎𝑐. O discriminante define o número de raízes reais que a
equação de segundo grau terá:
● Δ > 0, duas raízes diferentes
● Δ = 0, uma raiz (ou duas raízes iguais)
● Δ < 0, não possui raízes reais.

Graficamente, com Δ > 0a curva que representa a equação corta o eixo x em dois
pontos distintos, com Δ = 0 o ponto de máximo (ou mínimo) da curva fica sobre o eixo x
(abcissas) e no caso de Δ < 0 a curva não corta o eixo x. As equações 𝑥² − 2𝑥 + 1 = 0,
𝑥² − 4 = 0 e 𝑥² + 1 = 0 exemplificam, respectivamente, cada um dos casos citados.

Feitas estas considerações, o algoritmo para cálculo das raízes de uma equação de
segundo grau será refinado, a partir da versão apresentada na seção 4.3.2:

Imprima(‘Forneça os coeficientes da equação de segundo grau’)


Leia(a)

101
Introdução à Programação com Python

Leia(b)
Leia(c)
se a == 0:
imprima(‘Com a = 0, não é equação do segundo grau!’)
senão:
delta = b**2 - 4*a*c
se delta < 0:
imprima(‘Equação não possui raízes reais’)
senãose delta == 0:
x1 = -b/(2*a)
imprima(‘Equação possui apenas uma raiz real’, x1)
senão:
x1 = (-b+delta**0.5)/(2*a)
x2 = (-b-delta**0.5)/(2*a)
imprima(‘Equação possui as raizes reais’, x1, x2)

A Figura 5.11 apresenta o código Python com a implementação do algoritmo descrito


anteriormente. Observe que o cálculo do valor do discriminante (delta), para ser testado e
definir o tipo equação, também auxilia a escrever expressões mais simples, substituindo a
expressão 𝑏 ** 2 − 4 * 𝑎 * 𝑐 pelo nome da variável (delta) que recebeu o valor da
expressão (linha 8 do código).

Figura 5.11 - Programa para cálculo de raízes de equação do 2⁰ grau

Alguns resultados de execução do programa da Figura 5.11 são apresentados na


Figura 5.1. As três primeiras execuções correspondem às equações 𝑥² − 2𝑥 + 1 = 0,
𝑥² − 4 = 0 e 𝑥² + 1 = 0 que foram utilizadas para exemplificar os 3 casos: Δ = 0, uma
raiz; Δ > 0, duas raízes reais, e; Δ < 0, nenhuma raiz real. E na quarta execução foi
fornecido o valor 0 (zero) para o coeficiente a (não é equação de 2⁰ grau).

102
Introdução à Programação com Python

Figura 5.12 - Quatro exemplos de execução do programa da Figura 5.11

Como pode ser observado, o programa apresentou o comportamento esperado para


os quatro tipos de situações possíveis para os dados de entrada. Uma possível melhoria no
programa seria advertir o usuário que o valor zero não pode ser fornecido para o coeficiente
a, solicitando que seja fornecido um valor válido. Este tipo de solução é implementada com
uma estrutura de comando repetitivo, que será apresentada no próximo capítulo.

5.5. Exercícios

1) Escreva um programa para ler um número inteiro e escrever se ele é par ou ímpar.

2) Escreva um programa para ler um valor e escrever se ele é positivo ou negativo ou


zero.

3) Faça um programa que receba 2 números inteiros e imprima o maior deles, ou


informe que os dois são iguais.

4) Faça um programa que leia 2 números inteiros. Se o segundo for diferente de zero,
calcular e imprimir o quociente do primeiro pelo segundo. Caso contrário, imprimir a
mensagem: “DIVISÃO POR ZERO”.

5) Escreva um programa que leia 4 números inteiros e calcule a soma dos que forem
par.

103
Introdução à Programação com Python

6) Escreva um programa para ler o número de gols marcados pelo Flamengo e o


número de gols marcados pelo Fluminense em um Fla-Flu. Então, escreva o nome
do time vencedor ou que houve empate.

7) Faça um programa que leia 3 números inteiros (a, b e c) e diga se eles são números
Pitagóricos, ou seja, se são da forma a² + b² = c².

8) Escreva um programa que leia três valores e imprima o maior deles.

9) Faça um programa para ler o número de lados de um polígono regular, e a medida


do lado. Em seguida, ele deve calcular e imprimir o seguinte:
- Se o número de lados for igual a 3 escrever Triangulo e o valor do seu
perímetro;
- Se o número de lados for igual a 4 escrever Quadrado e o valor da sua área;
- Se o número de lados for igual a 5 escrever Pentagono;
- Em qualquer outra situação escrever Poligono não identificado.

10) Escreva um programa que leia as medias (a, b e c) dos lados de um suposto
triângulo e escreva se essas medidas podem formar um triângulo ou não. Caso
afirmativo, dizer seu tipo (equilátero ou isósceles ou escaleno). A condição de
existência de um triângulo é dada por:
- |b−c|<a<b+c
- |a−c|<b<a+c
- |a−b|<c<a+b

Observação: triângulo equilátero possui os 3 lados iguais; triângulo isósceles possui


2 lados iguais; e triângulo escaleno possui 3 lados diferentes.

11) Escreva um programa que leia o valor de 3 ângulos de um triângulo. Se os ângulos


formarem um triângulo (soma deles igual a 180°) então, escreva se o triângulo é
acutângulo, retângulo ou obtusângulo. Caso contrário, escreva que os ângulos não
formam um triângulo.
Observação: triângulo retângulo possui um ângulo reto (90°); triângulo obtusângulo:
possui um ângulo obtuso (ângulo maior que 90°); e triângulo acutângulo: possui 3
ângulos agudos (ângulo menor que 90°).

12) Escreva um programa que leia a velocidade máxima permitida de uma avenida e a
velocidade com que o motorista estava dirigindo nela e calcule a multa que uma
pessoa vai receber, sabendo que são pagos:
a) Nenhuma multa, se não ultrapassou a velocidade máxima;
b) 50 reais se o motorista ultrapassar em até 20km/h da velocidade máxima
permitida;
c) 100 reais, se o motorista ultrapassar de 21km/h a 40 km/h a velocidade máxima
permitida;
d) 200 reais, se estiver acima de 41km/h da velocidade máxima permitida.

13) No exercício 18 do capítulo 4, para cálculo da soma dos N elementos de uma


𝑛
𝑞 −1
Progressão Geométrica foi necessário usar a fórmula: 𝑆𝑛 = 𝑎1. ( 𝑞 − 1 ), onde a1
é o primeiro elemento e q é a razão da PG. Observe que se o usuário informar que a
razão da PG é 1, ocorrerá um erro de divisão por zero. Este é um caso particular de

104
Introdução à Programação com Python

uma PG com todos os valores iguais. Faça a correção deste problema no programa,
para que a execução se dê sem erros, como mostrado a seguir.

14) Faça um programa que leia o salário base e o código de um funcionário e imprima o
cargo e o salário bruto do funcionário de acordo com o percentual de aumento
mostrado na seguinte tabela:

Código Cargo Percentual


de aumento

1 Diretor 75%

2 Secretário 20%

3 Atendente 10%

4 Caixa 30%

5 Gerente 50%

15) Faça um programa que leia duas datas, compostas por dia, mês e ano: uma é a data
de nascimento de alguém, e a outra é a data atual. Em seguida, o programa deve
imprimir a idade da pessoa. Veja os exemplos:

Data de nascimento. 1 3 1990


Data atual: 1 10 2000
Idade: 10 anos

Data de nascimento. 12 10 2000


Data atual: 3 10 2010
Idade: 9 anos

Data de nascimento. 12 10 2000


Data atual: 12 10 2010
Idade: 10 anos

16) Faça um programa para ler o tempo gasto por dois maratonistas para completar uma
prova, informando quem foi o vencedor e calculando a diferença de tempo entre
eles. Todos os valores serão dados em horas, minutos e segundos. Veja os
exemplos:
Tempo do corredor 1: 3 10 20
Tempo do corredor 2: 3 5 10

105
Introdução à Programação com Python

Vencedor: corredor 2
Diferença: 0 horas 5 minutos 10 segundos

Tempo do corredor 1: 3 5 10
Tempo do corredor 2: 2 58 20
Vencedor: corredor 2
Diferença: 0 horas 6 minutos 50 segundos

Dica: converta o tempo de cada maratonista para segundos antes de fazer os


cálculos.

17) O Dia da Páscoa, por definição, é o primeiro Domingo após a primeira lua cheia que
ocorre depois do equinócio da Primavera (no hemisfério norte, Outono no hemisfério
sul), e pode cair entre 22 de Março e 25 de Abril. As fórmulas existentes calculam o
que se convencionou chamar de "Cálculo Eclesiático", definido pelo Concílio de
Nicea (325 d.C.). Existem diversas fórmulas para se determinar o Domingo de
Páscoa, entretanto uma das mais simples é a fórmula de Gauss, descrita a seguir.
Para calcular o dia da Páscoa (Domingo), usa-se a fórmula abaixo, onde o ANO
deve ser introduzido com 4 dígitos e X e Y são dados pela tabela a seguir.

a = ANO MOD 19
b= ANO MOD 4
c = ANO MOD 7
d = (19 * a + X) MOD 30
e = (2 * b + 4 * c + 6 * d + Y) MOD 7

ANO X Y

1582 a 1699 22 2

1700 a 1799 23 3

1800 a 1899 23 4

1900 a 2099 24 5

2100 a 2199 24 6

2200 a 2299 25 0

2300 a 2399 26 1

2400 a 2499 25 1

Em seguida:
● Calcula-se o valor de P dado por P = (22 + d + e). Se P for menor ou igual a
31, a Páscoa será no dia P de Março. Caso contrário:
○ Calcula-se P'= (d + e – 9). Se P’ for menor ou igual a 25 a Páscoa
será no dia P' de Abril. Caso contrário:

106
Introdução à Programação com Python

■ Calcula-se P'' = (P' – 7) e a Páscoa será a P'' de Abril, já que


não pode ser celebrada em data posterior a 25 de Abril.

Faça um programa que leia um ano e diga o dia e mês que ocorreu (ou ocorrerá) a
Páscoa naquele ano. Lembre-se de verificar se o ano digitado é válido e se está
presente na tabela acima. Veja os exemplos:

Digite um ano: 2011


Em 2011 a Páscoa foi ou será em 24 de Abril.

Digite um ano: 2002


Em 2002 a Páscoa foi ou será em 31 de Março.

18) Reescreva o código da Figura 5.11 usando apenas 1 comando condicional


(if-elif-else). Dica: faça o cálculo do determinante (Δ) logo após a leitura dos valores
dos coeficientes e antes do comando condicional.

107
Introdução à Programação com Python

Capítulo 6 - Comandos Repetitivos


A estrutura de comando repetitivo permite executar uma mesma tarefa tantas vezes
quantas sejam necessárias. Em computação este é um fato muito comum: executar tarefas
repetitivamente. Aliás, essa é uma das grandes vantagens dos computadores: a rapidez e
eficiência para executar tarefas repetitivamente. Tarefas que se tivessem que ser
executadas por um ser humano, o deixariam extremamente chateado, cansado e, talvez,
louco, iriam demorar muito mais e, muito provavelmente, estaria com erros. Imagine, por
exemplo, conferir todas as apostas de uma loteria de final de ano (algo em torno de 50
milhões).

Neste capítulo serão apresentadas duas estruturas de comando repetitivo Python:


while e for. Estas estruturas permitem resolver alguns dos problemas já mencionados no
capítulo 4. E, em conjunto com as estruturas condicional e sequencial permitem escrever
qualquer programa.

6.1. Comando while

Considere o exemplo do programa visto no final do Capítulo 5 no qual um valor igual


a zero não permite o cálculo pois ele representa o coeficiente a do termo 𝑎𝑥² da equação de
segundo grau que, com este termo igual a zero deixa de ser de segundo grau. Em termos
de algoritmo, a estrutura repetitiva já foi vista na seção 2.6. Para esta caso, o trecho de
algoritmo poderia ser escrito como:

Leia(a)
enquanto a == 0:
imprima(‘Valor tem que ser diferente de 0 (zero)’)
Leia(a)

A linguagem Python possui o comando while que permite mapear trechos de


algoritmo, como o mostrado acima. A forma geral do comando while é mostrada na Figura
6.1.

while <condição> :
<comando>

Figura 6.1 - Forma geral do comando while

A sintaxe do comando é definida com a palavra reservada while, seguida de uma


<condição> finalizada pelo caracter ‘:‘ e, na sequência um bloco de um ou mais comandos
deslocados à direita, representado por <comando> na Figura 6.1. Como nos comandos
anteriores, a indentação do código é obrigatória na linguagem Python, sendo considerado
um erro de sintaxe a sua não utilização.

108
Introdução à Programação com Python

A execução do comando while tem início com a avaliação da <condição>. Quando a


condição for verdadeira, <comando> será executado e a condição será novamente
avaliada, ao final de cada execução do bloco de comandos. Quando a condição avaliada
tiver resultado falso, o comando while termina. Observe que, funcionando desta forma, o
<comando> poderá ser executado zero ou mais vezes. O nome while (enquanto) escolhido
para o comando indica de maneira clara que: enquanto a condição for verdadeira a
execução do comando vai ser repetida.

A Figura 6.2 mostra uma parte da janela do editor de programas e da janela do Shell
com o resultado da execução na qual o usuário fornece o valor zero duas vezes. Na terceira
vez é fornecido o valor 1 e o programa solicita o valor do coeficiente b.

Figura 6.2 - Uso do while para validar uma entrada diferente de zero

Observe que a estrutura é exatamente a mesma usada no algoritmo do início desta


seção: um comando de leitura (input()) para atribuir um valor para a variável a; o comando
repetitivo while com um bloco de dois comandos (uma mensagem de erro e o mesmo
comando de leitura usado antes do comando repetitivo).

O comando de leitura antes do comando repetitivo é necessário para definir o valor


da variável a que será usada no teste do comando repetitivo que vem na sequência. Caso
este comando de leitura seja omitido, haverá um erro de sintaxe no teste da condição do
comando repetitivo, pois a variável a ainda não estaria definida. Ou seja, é importante
garantir que todos os valores de variáveis que compõem a expressão da condição já
estejam definidas antes do início do while.

E o comando de leitura dentro do bloco de comandos do comando repetitivo é


fundamental, pois ele é que irá causar a atribuição de um novo valor para a variável a.
Quando o valor atribuído para a variável a for diferente de zero, o próximo teste da condição
do comando repetitivo resultará no valor Falso e o comando repetitivo terminará.

109
Introdução à Programação com Python

6.1.1. Cuidado com o loop infinito

O que aconteceria se o comando de leitura não fosse repetido dentro do bloco de


comandos repetitivos? A resposta pode ser visualizada na Figura 6.3. Note que a
“eliminação” do comando de leitura interno ao comando repetitivo foi feita com a colocação
de um caractere ‘#’, transformando o comando em um comentário. Os comentários são
ignorados pelo interpretador e aparecem na cor vermelha no editor de programas do IDLE.
A Figura 6.3, mostra o trecho de código com a alteração e a janela do Shell com o resultado
de duas execuções, a primeira com a = 1, b = 3, c = -4 e a segunda com a = 0.

Figura 6.3 - Código com possibilidade de loop infinito

110
Introdução à Programação com Python

Observe que na primeira execução, o comando repetitivo foi executado zero vezes,
pois para o primeiro valor fornecido para o coeficiente a, igual a 1, a condição do comando
repetitivo, a == 0, resultou no valor False e o comando repetitivo termina, sem entrar
nenhuma vez no bloco de comandos a serem executados repetitivamente. Na sequência, a
partir do comando de leitura para a variável b, o código é idêntico ao mostrado na Figura
5.11 e, então, os valores 3 e -4 são lidos e atribuídos para as variáveis que representam os
coeficientes b e c. O valor 25, resultante da expressão 𝑏 ** 2 − 4 * 𝑎 * 𝑐, é atribuído para
a variável delta. O que fará com que os comandos na cláusula else do comando if-elif-else
seja executado para calcular o valor de duas raízes e imprimir a mensagem vista na Figura
6.3.

Já na segunda execução do programa ocorreu o chamado loop infinito. O termo loop


(laço em inglês) em computação significa repetição. Como explicado na seção 6.1 um
comando repetitivo pode ser executado zero ou mais vezes. Mas, associado com o conceito
de algoritmo (“um conjunto de regras e procedimentos lógicos perfeitamente definidos que
levam à solução de um problema em um número finito de etapas”) o comando repetitivo tem
que terminar, ou tem que executar um número máximo de vezes.

O que gerou o laço infinito foi exatamente a supressão do comando de leitura dentro
do bloco de comandos repetitivos. O comando de leitura, antes do comando repetitivo,
atribuiu o valor 0 (zero) para a variável a. Ao testar a condição do comando repetitivo, a==0,
o resultado foi verdadeiro e, por causa disso, será executado o comando repetitivo que
agora tem apenas o comando print(). Ora, se o comando print() não altera o valor da
variável a (quem alterava o valor de a era o comando input(), que virou comentário), então a
condição do comando repetitivo será verdadeira para sempre e o comando repetitivo não
terminará…

Por isso, é importante observar que no bloco de comandos repetitivos deve sempre
haver (pelo menos) um comando que torne, em algum momento, a condição de teste falsa,
para que o comando repetitivo termine e o programa continue a sua execução, terminando
em um tempo finito. Se todos os comandos repetitivos atenderem a este requisito (terminar
em algum tempo), o programa estará mapeando de maneira adequada um algoritmo.

O tempo que um comando repetitivo levará para terminar pode ser indeterminado. É
o caso do exemplo da Figura 6.2. Primeiramente, porque a avaliação da condição no
comando repetitivo depende de um comando de entrada (input()), que só termina a sua
execução após o usuário digitar a informação e apertar a tecla ‘Enter’. Se o usuário iniciar o
programa e, antes de digitar o primeiro valor, parar durante uma hora para fazer qualquer
outra atividade, e depois voltar a usar o programa, uma única iteração do comando
repetitivo vai demorar uma hora.

Em segundo lugar, o número de repetições vai depender dos valores fornecidos para
o coeficiente a da equação do segundo grau. Se o primeiro valor for diferente de zero,
conforme já explicado, o valor é válido e o comando repetitivo será executado zero vezes.
Se o usuário fornecer, no início, uma sequência de N valores zeros antes de fornecer antes
de fornecer um primeiro valor diferente de zero, o comando repetitivo será executado N
vezes. Este evento já foi visto na Figura 6.2, em uma execução onde os valores 0, 0 e 1
foram informados para o coeficiente a, fazendo com que o comando repetitivo fosse
executado 2 vezes (observe na Figura 6.2 que a mensagem de erro seguida de um novo
pedido do coeficiente a foram exibidos 2 vezes).

111
Introdução à Programação com Python

6.1.2. Número determinado de repetições com o while

Em algumas situações o número de repetições do comando repetitivo é


pré-determinado. Por exemplo, suponha que um programa seja feito para ler as notas de
uma turma com N alunos. A solução geral para este tipo de situação consiste em utilizar
uma variável auxiliar para contar o número de execuções. A Figura 6.4 mostra um trecho de
código utilizando o comando while e uma variável i como contador.

i = <valor inicial>
while i < <valor final> :
<comando>
i=i+1
Figura 6.4 - Forma geral do comando while com contador

O contador será incrementado de uma unidade (i = i + 1) a cada iteração da


execução do comando repetitivo. O <valor inicial> e o <valor final> juntamente com a
expressão lógica, determinarão o número de repetições. Por exemplo, um possível código
para ser executado 10 vezes, poderia ser escrito como:

i=0
while i < 10:
print('%4d' %i, end='') # bloco de comandos
i=i+1 # repetitivos
print()
print('%4d' %i)

A saída gerada por este trecho de código será:

0 1 2 3 4 5 6 7 8 9
10

Com os valores impressos é possível confirmar que a execução do bloco repetitivo


se deu por 10 vezes, para os valores de i variando de 0 a 9. O bloco de comandos
repetitivos imprime o valor de i e depois o incrementa. Quando o valor 9 foi impresso, na
sequência o valor de i chegou a 10. Ao voltar para o teste do while, o teste 10<10 deu
resultado falso e o comando repetitivo terminou. Na sequência, o comando print() sem
parâmetros faz pular para a próxima linha e o último comando imprime o valor final de i, que
foi o valor que fez o comando repetitivo terminar.

O que aconteceria se os dois comandos do bloco repetitivo fossem invertidos, como


no trecho a seguir:
i=0
while i < 10:
i=i+1 # bloco de comandos
print('%4d' %i, end=' ') # repetitivos
print()
print(‘%4d’ %i)

112
Introdução à Programação com Python

Note que os elementos que determinam o número de repetições não sofreram


alterações. O valor inicial, o valor final e o incremento unitário do contador, bem como a
expressão relacional do comando while estão iguais. Portanto, o comando será repetido 10
vezes, para os valores de i de 0 a 9. A saída gerada por este trecho de código será
diferente porque agora a impressão é feita após a operação de incremento:

1 2 3 4 5 6 7 8 9 10
10

O último comando de impressão confirma que o valor do contador i que provocou a


parada do comando repetitivo foi 10 (valor impresso fora do comando repetitivo). Por isso, é
preciso ter muita atenção no caso de utilização do contador, para verificar se o incremento
já foi realizado ou não. Em geral, recomenda-se a utilização do estilo do código da Figura
6.4, deixando o incremento como o último comando do bloco repetitivo.

É importante observar que alterações na expressão relacional também pode alterar


o número de repetições. Por exemplo, se a comparação fosse i >= 10 ao invés de i < 10, a
execução seria realizada 11 vezes, para i de 0 a 10. Ou ainda uma alteração na regra de
incremento. Por exemplo, se ao invés de usar i = i + 1 tivesse sido utilizado i = i + 3, o
comando repetitivo seria executado apenas 4 vezes para i = {0, 3, 6, 9}, com o valor i=12
determinando a parada do comando repetitivo. Considerando o incremento (i = i + 3) como
o último comando do bloco repetitivo, a saída gerada pelo código seria:

0 3 6 9
12

A operação de incremento possui uma forma abreviada na linguagem Python. Na


verdade, outras operações também possuem formas abreviadas. A Tabela 6.1 apresenta
uma relação de operações e suas formas sintéticas. Para o interpretador ou para o
processador não importa a forma de escrita dos comandos mostrados na tabela na
linguagem de alto nível.

Tabela 6.1 - Formas abreviadas de operadores na linguagem Python


Operador Exemplo Equivale a

+= x += 1 x=x+1

-= x -= 1 x=x-1

*= x *= 2 x=x*2

/= x /= 2 x=x/2

//= x //= 2 x = x // 2

%= x %= 2 x=x%2

**= x **= 2 x = x ** 2

Note que o operador é definido como a sequência de 2 (ou) 3 caracteres,


dependendo do caso. Portanto, não pode haver espaço entre os caracteres do operador,
pois seria considerado um erro de sintaxe. Se o operador ‘+=’ fosse escrito como ‘+ =’, o

113
Introdução à Programação com Python

interpretador da linguagem Python ao ler o caractere ‘+’ e depois um espaço em branco iria
entender que se trata do operador de adição. Logo, após o espaço em branco deveria vir
obrigatoriamente um número ou o nome de uma variável ou uma expressão. Mas o que
aparece é um caracter de atribuição ‘=’. Assim, tem um erro de escrita (sintaxe) no código.

6.1.3. Usando while-True

O trecho de código discutido no início da seção utiliza um mesmo comando antes do


comando repetitivo e dentro do bloco de comandos repetitivos, conforme destacado a
seguir:
Leia(a)
enquanto a == 0:
imprima(‘Valor tem que ser diferente de 0 (zero)’)
Leia(a)

O objetivo do comando anterior ao comando repetitivo, conforme já discutido, é para


atribuir um valor inicial para ser usado na expressão relacional, na condição de teste do
comando repetitivo. Eventualmente, o código a ser executado antes do comando repetitivo
pode conter vários comandos e sua repetição poderia, consequentemente, aumentar de
forma significativa o tamanho do código.

A solução para este problema seria a de usar os comandos uma única vez, dentro
do bloco de comandos repetitivos. Como os comandos agora só existem dentro do bloco
repetitivo, a condição no início do comando tem que permitir a entrada sempre que se
chegar no comando repetitivo. Por exemplo, sendo o valor fixo e igual a verdadeiro (True).
Mas, como não se pode ter um loop infinito deve ser criada uma forma de se quebrar o loop
se uma determinada condição for alcançada. Em termos de algoritmo, o trecho anterior,
poderia ser reescrito como:

enquanto Verdadeiro:
Leia(a)
se a != 0 :
quebra_loop
imprima(‘Valor tem que ser diferente de 0 (zero)’)

Note que, semanticamente, os dois trechos de algoritmo são idênticos. Vai ter que
ser lido um valor inicial (agora dentro do comando repetitivo). Enquanto o valor lido for igual
a zero, a impressão da mensagem de erro será feita e uma nova iteração do comando
repetitivo irá realizar nova leitura de valor. Quando o valor lido for diferente de zero, o loop
será quebrado, com o valor atribuído para a variável a. Inclusive, se o primeiro valor
fornecido for diferente de zero, a mensagem de erro não será impressa.

Usando a linguagem Python, o trecho de algoritmo mostrado anteriormente pode ser


escrito, usando a estrutura while-true, como mostrado na Figura 6.5. Nesta mesma figura é
exibida a janela do Shell, sobreposta à janela do editor de programas, com o resultado da
execução do programa, para os mesmos valores utilizados na execução mostrada na Figura
6.2.

114
Introdução à Programação com Python

Figura 6.5 - Exemplo de utilização da estrutura while-true

O comando no estilo while-true sem o break em seu interior se transformaria em um


loop infinito. Por isso, é importantíssimo não esquecer da inserção da comando break que,
geralmente, é vinculada a um comando condicional, como no exemplo. Alguns programas
têm esta particularidade de se comportarem como um grande laço infinito e, eventualmente
e muito raramente, executam o break vinculado a uma condição qualquer.

É o caso da maioria dos programas que implementam serviços de internet. Um


servidor de páginas web, por exemplo, que executa algum código de inicialização e depois
entra em um loop infinito e espera, sem fazer nada, pela chegada de uma requisição por
uma página. Ao receber uma requisição, o servidor web procura pela página em seu banco
de dados e a envia para o requisitante. Caso a página não seja encontrada, o servidor web
envia uma mensagem de erro (página não encontrada).

Posteriormente a uma destas duas ações, o servidor volta para o comando onde ele
fica esperando a chegada de uma nova requisição. Um bom servidor de páginas deve ficar
nesta execução 24 horas por dia, sete dias por semana. Eventualmente ele será parado por
algum comando do administrador (um break será executado) para alguma manutenção
rápida ou problema de segurança ou talvez para dar lugar a uma nova versão.

6.2. Comando for

Um comando repetitivo pode ser utilizado um número pré-determinado de vezes,


conforme discutido na seção 6.1.2, utilizando o comando while e uma variável auxiliar

115
Introdução à Programação com Python

fazendo o papel de um contador do número de execuções do comando repetitivo. Usando a


estrutura do comando while é necessário inicializar um contador antes do comando while e
fazer o incremento deste contador dentro do bloco de comandos repetitivos. Um erro muito
comum é o esquecimento de incrementar o contador no bloco de comandos repetitivos.

6.2.1. Comando for

Para resolver este problema, uma outra estrutura de comando repetitivo com
incremento automático do contador está presente na linguagem Python. Nesta estrutura, o
contador é inicializado no próprio comando repetitivo. A Figura 6.6 apresenta uma forma
geral do comando repetitivo for:

for <contador> in range (<valor inicial>, <valor final>) :


<comando>
Figura 6.6 - Forma geral do comando for

A sintaxe do comando é definida com o uso da palavra reservada for seguida do


nome da variável a ser utilizada como contador do número de execuções. O cabeçalho do
comando continua com as palavras reservadas in range (na faixa), seguidas pelos valores
inicial e final para definição da faixa de valores que o contador irá assumir. O cabeçalho é
finalizado com o caractere ‘:’. Após o cabeçalho vem o bloco de um ou mais comandos a
serem executados repetitivamente, com a indentação (deslocamento à direita).

A variável a ser usada como contador é definida no próprio comando, não havendo a
necessidade de definição anterior ao comando for. Mas, também é possível utilizar alguma
variável que já tenha sido criada. O <valor inicial> será o primeiro valor da variável contador
e <valor final - 1> será o último valor. O comando for não executa para <contador> = <valor
final>. O incremento padrão do contador é de uma unidade a cada execução ou à cada
iteração.

O trecho de código usado como exemplo na seção 6.1.2, pode ser reescrito com a
substituição do while pelo comando for. Para facilitar a comparação, os dois códigos são
apresentados lado a lado na Tabela 6.2.

Tabela 6.2 - Comparação dos comandos for e while


Uso do comando for Uso do comando while

for i in range (0, 10): i=0


print(‘%4d’ %i, end) while i < 10:
print(‘%4d’ %i, end)
i=i+1

Observe que o comando for fica mais compacto porque na linha do cabeçalho é
definido o valor inicial e final do contador e, portanto, o número de repetições. Como o
comando for não executa para o valor final (10) os dois comandos irão executar para os
valores de i variando de 0 a 9. Porém, no caso do comando for, o valor da variável de

116
Introdução à Programação com Python

controle não assume o valor 10, diferentemente do que acontece com o comando while, no
qual a variável i tem que assumir o valor 10, para tornar a condição i<10 falsa. No trecho de
código a seguir, são incluídos os mesmos dois comandos de impressão usados no código
do início da seção 6.1.2:

for i in range (0, 10):


print(‘%4d’ %i, end) # bloco de comandos repetitivos
print()
print(‘%4d’ %i, end)

A saída gerada por este trecho de código será:

0 1 2 3 4 5 6 7 8 9
9

Observe que os dois códigos imprimem os mesmos valores como resultado do


comando print() do bloco repetitivo, confirmando que ambos são executados para i variando
de 0 a 9. Porém, o valor final de i (impressão feita na última linha) do código usando o while
foi 10 e para o código usando o for foi 9.

Outras formas de utilização do comando for serão apresentadas no próximo capítulo


quando estiverem sendo apresentadas as estruturas de dados conhecidas como arranjos.
Para a manipulação de arranjos, o comando for possui características bem interessantes
que simplificam sua forma de escrita.

6.2.2. Comando for com incremento não unitário

Suponha um programa simples para imprimir todos os números inteiros múltiplos de


um número inteiro k no intervalo 1 a N. O programa deverá receber como entradas os
valores k e N. Um algoritmo para solução poderia ser o seguinte:

Leia(N)
Leia(k)
para i na faixa (k, N+1):
se “i é múltiplo de k”:
imprima(i)

A condição “i é múltiplo de k” pode ser feita comparando o resto da divisão inteira


com zero, ou “i % k == 0” em Python. Uma possível implementação para o comando
repetitivo do algoritmo acima, poderia ser feita utilizando o comando for da seguinte
maneira:

for i in range(k, N+1):


if i%k == 0: # o operador % é o resto da divisão inteira
print(i, end=' ')

Imagine uma situação em que o usuário forneça os valores N=1000000000 e k =


50000000. O comando repetitivo seria executado aproximadamente 50 milhões de vezes, o
que representou 23s de tempo de execução em um computador com processador de 1.86

117
Introdução à Programação com Python

GHz de clock. O número exato de repetições é calculado como o <valor final> - <valor final>
ou 100000001 - 50000000 = 50000001.

Uma solução usando o comando repetitivo while seria muito mais eficiente se
utilizasse o valor inicial igual a k e um incremento também igual a k, ao invés de um
incremento unitário. Este incremento eliminaria ainda a necessidade de comparação, pois a
regra de geração definiria a seguinte sequência: k, 2k, 3k…, etc. enquanto o número da
sequência fosse menor do que N. Para o exemplo, a sequência teria apenas dois números
50000000 e 100000000. Aliás, para este caso nem seria necessário escrever um programa.

Na linguagem Python, o comando for permite especificar o valor do incremento,


utilizando um terceiro parâmetro, nos parênteses, após as palavras reservadas in range, ou
mais especificamente, após a definição da faixa, como mostrado na Figura 6.7.

for <contador> in range (<valor inicial>, <valor final>, <incremento>) :


<comando>
Figura 6.7 - Forma geral do comando for

O parâmetro de <incremento> define o valor do incremento que a variável


<contador> irá receber após cada iteração do bloco de comandos repetitivos. O comando
repetitivo, para gerar a sequência de números múltiplos de k pode ser escrito da seguinte
forma:

for i in range(k, N+1, k):


print(i, end=’ ‘).

Desta forma, para os valores de N=100000000 e k=50000000 o comando repetitivo


que imprime o valor de i seria executado apenas duas vezes para os valores de
i={50000000, 100000000} e o programa é executado em alguns milisegundos. Imagine se o
bloco repetitivo estivesse relacionado com o processamento de uma transação cujos testes
fossem mais complexos e demorassem exatamente 1s cada. A solução com o incremento
não unitário demoraria 2s aproximadamente e a de incremento unitário demoraria cerca de
3,17 anos, ou seja, aproximadamente 3 anos, 2 meses e 12 dias.

Esta comparação é para que você se convença de que nem sempre é suficiente ter
uma solução correta. Às vezes, é necessário ter uma solução correta e eficiente. Embora
este aspecto não seja cobrado nas soluções desta disciplina de Introdução à Programação,
é fundamental conhecer este aspecto e tratá-lo de maneira adequada (com uma solução
eficiente) quando ele aparecer.

Note que quando se deseja um incremento diferente do unitário, o valor do


incremento deve ser definido no cabeçalho do comando for, usando o terceiro parâmetro,
após a definição da faixa, como mostrado na Figura 6.7. O número de repetições do
comando for é definido pelos parâmetros que são definidos no cabeçalho do comando for.
Incrementar a variável <contador> no bloco de comandos repetitivos não produz nenhum
efeito no número de repetições.

Como exemplo, suponha a alteração mostrada a seguir no código utilizando o


comando for com incremento unitário e no final do bloco de comandos repetitivos, o
contador está sendo incrementado de k unidades.

118
Introdução à Programação com Python

for i in range(k, N+1):


print('antes i=%d' %i, end=' ')
if i%k == 0:
print('**%d**' %i, end=' ')
i=i+k
print('depois i=%d' %i)

Para facilitar a compreensão, o valor da variável de controle do comando for é


impresso no início e no final do bloco de comandos repetitivos. A impressão será feita em
uma mesma linha e quando o valor de i for múltiplo de k, ele aparecerá impresso no meio
da linha precedido e sucedido por dois asteriscos (*). Com os valores de k=5 e N=10, a
saída gerada por este trecho de código será a seguinte:

antes i=5 **5** depois i=10


antes i=6 depois i=11
antes i=7 depois i=12
antes i=8 depois i=13
antes i=9 depois i=14
antes i=10 **10** depois i=15

Veja que o número de repetições do comando for foi igual a 6, por causa da faixa
definida: N+1-k = 10+1-5 = 6. O valor inicial de i = 5 (<valor inicial>), com incremento
unitário a cada nova iteração, eliminando o efeito do comando de incremento, i = i + k. Por
isso, uma boa prática de programação é não usar comando de atribuição para alterar a
variável de controle do for.

O comando for também permite especificar execuções em uma faixa com


incremento negativo (ou decremento) e, desta forma, iniciando a faixa com um número
maior do que o valor final da faixa. Suponha, por exemplo, que se desejasse imprimir os
valores múltiplos de k de 1 a N em ordem decrescente. Para resolver este problema, o
código a seguir poderia ser utilizado:

for i in range(N, k-1, -1):


if i%k == 0:
print(i, end=’ ‘)

Lembre-se que, com o decremento unitário, o comando for caminha do maior valor
para o menor valor da faixa especificada e não executa para o valor final da faixa, que deve
ser igual a k-1 e não igual a k, quando se deseja executar para o valor de i = k.

Como o decremento é unitário, se a faixa de valores for muito grande o número de


repetições poderá gastar muito tempo, conforme já discutido. Uma solução mais eficiente,
com o incremento igual a -k, pode ser implementada com o código a seguir:

for i in range(N//k*k, k-1, -k):


print(i, end=’ ‘)

A determinação do maior múltiplo foi feita com a divisão inteira de N por k,


multiplicado por k. Por exemplo, se N=50 e k=8, teremos 50//8*8 = 6*8 = 48. Como as
operações têm mesma ordem de prioridade, não há necessidade de uso de parênteses.

119
Introdução à Programação com Python

6.2.3. Comando for-break

Suponha que para resolver o problema anterior, o programador não soubesse


determinar o valor do maior múltiplo de k no intervalo 1..N. Então, ele decide escrever um
código para determinar o valor do maior múltiplo, percorrendo a sequência na ordem
inversa, começando por N. Para cada número na sequência, será feita a operação de resto
da divisão inteira por k. A primeira vez em que for encontrado o resto igual a zero, a divisão
foi feita usando o maior múltiplo de k e o comando repetitivo pode parar.

Lembrando que a suposição inicial é de que N>k e, portanto, sempre haverá pelo
menos um múltiplo na sequência de 1..N (na verdade a verificação pode se feita apenas na
sub-sequência de k..N). Assim, o maior múltiplo de k encontrado poderá ser utilizado como
o valor inicial da faixa do comando for. O seguinte código poderia ser usado para encontrar
o maior múltiplo de k:

mm = N
while mm % k != 0: # testa se mm não é múltiplo de k
mm = mm - 1 # passa para o “próximo” número da sequência

Na linguagem Python o comando break pode ser utilizado para parar o comando
repetitivo while, como mostrado na seção 6.1.3. Da mesma forma, a comando break pode
ser utilizada no comando for, geralmente associado a uma condição. Por exemplo,
encontrar um número que seja múltiplo de k. Desta forma, um código equivalente ao
mostrado anteriormente pode ser escrito utilizando o comando for:

for i in range (N, k-1, -1):


if i % k == 0:
mm = i # maior múltiplo (mm)
break

Observe que as duas estruturas repetitivas executam as mesmas ações: percorrer


uma lista de números, do maior para o menor, verificando se o número é múltiplo de k; e
parar quando o número for múltiplo de k. Independente de qual estrutura seja usada, o
código que virá na sequência para imprimir os múltiplos de k, em ordem decrescente
poderia ser:

for i in range(mm, k-1, -k):


print(i, end=’ ‘)

6.3. Alguns exemplos de uso de comandos repetitivos

Nesta seção serão apresentados alguns problemas cujas soluções demandam a


utilização de comando repetitivo. A maioria das soluções serão apresentadas utilizando o

120
Introdução à Programação com Python

comando repetitivo while. No próximo capítulo serão vistos exemplos onde o uso do
comando for é mais adequado.

Para cada problema será apresentado o enunciado no estilo de listas de exercícios e


avaliações.

6.3.1. Cálculo de média

Faça um programa que peça para o usuário digitar as notas de uma turma e, então,
calcula a média das notas. O número de alunos da turma deve ser requisitado ao usuário,
antes do programa iniciar a leitura das notas. As notas devem estar no intervalo [0..100] e
valores fora desta faixa não deverão ser aceitos.

A solução para este problema poderia ser descrita nos seguintes passos: 1. obter o
número de alunos da turma; 2. ler uma nota; 3. se a nota for válida, totalizar o valor e
incrementar o número de notas lidas; 4. Voltar ao passo 2 enquanto o número de notas for
menor que o número de alunos da turma; 5. Calcular e informar a média das notas.

Uma primeira versão para este algoritmo, baseada na descrição feita, pode ser
escrita como: 3.2.2.5

Leia “número de alunos na turma”


enquanto “número de notas < número de alunos na turma”:
Leia “nota”
Se “nota for válida”:
totaliza nota
incrementa número de notas
Senão:
Escreva(“Nota inválida”)
Calcula a média
Escreva(média)

Para o detalhamento do algoritmo, os comandos de leitura e escrita já serão escritos


em estilo similar ao da linguagem Python para os comandos input() e print(),
respectivamente. A verificação da validade da nota, consiste em testar se a nota está no
intervalo [0, 100], conforme discutido na seção 3.2.2.5, podendo ser utilizada a expressão
“nota >=0 E nota <=100”.

Outro detalhamento importante é o cálculo da média, que necessita do cálculo do


somatório de todas as notas válidas. A média será calculada pela expressão:
𝑛𝑢𝑚
( ∑ 𝑛𝑜𝑡𝑎𝑖)/𝑛𝑢𝑚 .
𝑖=1
O somatório das notas consiste em definir uma variável que receberá o valor inicial
igual a zero, antes do comando repetitivo (ex: soma=0). Dentro do comando repetitivo será
lido o valor de uma nota e o valor atribuído para uma variável de nome nota, por exemplo.
Se a nota lida for válida, o valor do somatório deve ser incrementado pelo valor da nota que
acabou de ser lida, usando o comando padrão de incremento, por exemplo, soma = soma +
nota.

121
Introdução à Programação com Python

Também será necessário usar um contador (cont) para controlar o número de notas
lidas. O comando repetitivo deve parar quando o número de notas válidas lidas for igual ao
número de alunos da turma. Portanto, este contador só deve ser incrementado quando uma
nota lida for válida.

Feitas estas considerações, chega-se à versão final do algoritmo, como mostrada a


seguir:
num = Leia(“Numero de alunos da turma”)
soma = 0
cont = 0
enquanto cont < num:
nota = Leia(“Nota = “)
se nota >= 0 E nota <= 100:
soma = soma + nota
cont = cont + 1
senão:
Escreva(“Nota inválida”)
media = soma / cont

A implementação do algoritmo refinado, usando a linguagem Python é apresentada


na Figura 6.8.

Figura 6.8 - Programa para cálculo da média de N notas usando apenas while

122
Introdução à Programação com Python

Esta figura também apresenta a janela do Shell com a execução onde o usuário
informa que a turma tem 4 alunos e entra com a seguinte sequência de notas: 0, 100, 130,
90, -2 e 80. A sequência possui 2 notas inválidas (130 e -2) e 4 notas válidas (0, 100, 90 e
80). É fácil verificar que o somatório das 4 notas será 270 e a média igual a 67.5.

Na solução apresentada foi usada apenas o comando repetitivo while. Poderia ser
usado o comando for? Na verdade, a pergunta que deve ser feita é se seria adequado
utilizar o comando repetitivo for. Em princípio, o comando for é mais adequado quando o
número de repetições é conhecido à priori.

Nesta solução, o número de notas que o usuário deve informar é definido pelo
próprio usuário ao informar o número de alunos da turma. Desta forma, o uso do comando
repetitivo for parece ser adequado. Entretanto, não existe garantia de que o usuário só
entrará com valores válidos para as notas. No exemplo anterior, o usuário forneceu um total
de 6 valores, com 4 notas válidas e 2 inválidas.

Uma estratégia que pode ser adotada é obrigar que o usuário forneça uma nota
válida, antes de passar para o próximo comando do programa. A ideia desta abordagem
levaria a um algoritmo diferente, que pode ser descrito como:

num = Leia(“Numero de alunos da turma”)


soma = 0
cont = 0
para i de 0 a num:
enquanto “verdadeiro”:
nota = Leia(“Nota = “)
se nota >= 0 E nota <= 100:
“quebra_enquanto”
Escreva(“Nota inválida”)
soma = soma + nota
cont = cont + 1
media = soma / cont

O comando de leitura de notas válidas pode ser traduzido para Python como:

while True:
nota = float(input(‘Nota = ‘)
if nota >= 0 and nota <=100:
break
print(‘Nota inválida’)

Quando o teste da condição for verdadeiro, o comando repetitivo termina, porque foi
fornecido um valor válido. Caso contrário, será impressa a informação de que a nota é
inválida e uma nova nota será solicitada, no primeiro comando de um nova iteração do
comando repetitivo. Neste caso, o comando de impressão para informar que a nota é
inválida não precisa estar vinculado à cláusula else. Mas caso fosse colocada, o resultado
seria o mesmo.

Com esta abordagem, podemos reescrever o programa, conforme mostrado na


Figura 6.9, usando o comando for para controlar o número de notas lidas, com a tradução
do algoritmo apresentado anteriormente.

123
Introdução à Programação com Python

Figura 6.9 - Programa para cálculo da média de N notas usando for e while

Como era de se esperar, o resultado da execução do programa Figure6-9.py é


identico ao do programa Figure6-8.py para os mesmos valores. Isso reforça a ideia de que
duas soluções diferentes podem estar ambas corretas.

6.3.2. Números Primos

Faça um programa que peça para o usuário digitar um número inteiro e, então, testa
se o número digitado é um número primo. Como resultado, o programa deve informar se o
número informado é primo ou não. O programa deverá testar a primalidade de vários
números. Use qualquer valor menor ou igual a zero como 'sentinela' para indicar que o
término do programa. Ou seja, quando o usuário não quiser mais testar se um número é
primo. O algoritmo para este problema poderia ser descrito da seguinte forma:

Leia(num)
Se “num é primo”:
Escreva(“num é primo)
Senão:
Escreva(“num não é primo”)

124
Introdução à Programação com Python

Por definição, um número inteiro é primo se ele for divisível apenas por 1 e por ele
próprio. Desta forma, o teste não é um teste simples e que possa ser verificado dentro da
cláusula “Se”. Para verificar se um número é primo, uma possibilidade é testar para todos
os números na sequência de [2..num-1], se algum deles é divisor de num. Se nenhum dos
elementos da sequència [2..num-1] for divisor, num é primo.

Para verificar se um número i é divisor de um número num, basta realizar a


operação de resto da divisão inteira de num por i e testar o resultado. Se o resultado for
zero, i é divisor de num. Caso contrário, i não é divisor.

Além disso, o algoritmo não considerou a possibilidade de testar vários números. A


ideia é que após responder se um número é primo ou não, o programa deverá solicitar ao
usuário um novo número para ser testado. Quando o usuário informar um valor menor ou
igual a zero. Refinando o algoritmo, com as observações feitas, a segunda versão pode ser
escrita como:

Escreva(“Este programa verifica se um número é primo”)


enquanto Verdadeiro:
Leia(num)
se num <= 0:
quebra_enquanto
dv = 2 # primeiro divisor da sequência
enquanto dv < num E “resto da divisão de num por dv ≠ 0”:
dv = dv + 1
se dv == num :
Escreva(“num é primo”)
senão:
Escreva(“num não é primo”)

Observe que antes do comando repetitivo, o divisor (dv) é inicializado com o valor 2
e a cada repetição, dv é incrementado de uma unidade, para permitir que toda a sequência
de possíveis divisores seja percorrida. Uma das condições de parada do comando repetitivo
é encontrar um divisor, o que torna a segunda cláusula do E lógico falsa.

A outra condição de parada, representada na primeira parte do E lógico, é


exatamente quando toda a sequência de divisores foi testada e nenhum divisor foi
encontrado. Quando esta condição de parada acontece, dv sai do comando repetitivo com
valor igual a num.

O comando condicional verifica, então, se dv é igual a num. Se o teste for


verdadeiro, informa que o número é primo. Caso contrário, informa que o número não é
primo.

A implementação do algoritmo discutido nesta subseção é mostrada na Figura 6.10,


juntamente com o resultado da execução para 3 números.

125
Introdução à Programação com Python

Figura 6.10 - Programa para verificar a primalidade de números inteiros

Note que esta solução poderia ser melhorada (tornada mais eficiente), pois se o
número fornecido for muito grande, o número de repetições do comando repetitivo também
será, quando o número for primo. Se for um número não primo, o número de repetições
pode ser pequeno, dependendo do seu menor divisor. Por exemplo, para todo número par o
comando repetitivo não será executado, se for múltiplo de 3 o comando repetitivo será
executado apenas uma vez, se for múltiplo de 5 será repetido 3 vezes e assim por diante.

Observe que na última frase não foi mencionado o caso do número ser divisível por
4. Obvio! Se o número fosse divisível por 4, ele seria par e já teria sido identificado como
não primo quando dv era igual a 2. Uma possível melhoria no algoritmo do programa
poderia ser fazer primeiro o teste se o número é par (divisível por 2). Caso não seja, usar a
mesma lógica de caminhar por uma lista de possíveis divisores, contendo apenas valores
ímpares, iniciando com o divisor 3. Esta alteração, reduziria à metade o número de
repetições quando o número for primo. Outra simplificação seria a de não percorrer a lista
de divisores até se chegar no próprio número. Em princípio, a parada poderia acontecer
quando o divisor for igual à metade do número. Um dos exercícios deste capítulo é para
desenvolver uma solução mais eficiente do que a apresentada aqui.

6.3.3. Cálculo de raiz quadrada

Escreva um programa que leia um valor x qualquer pelo teclado e calcule o valor da
raiz quadrada de x. O programa deve garantir que o cálculo da raiz quadrada seja feito

126
Introdução à Programação com Python

apenas quando um valor não negativo seja fornecido. Quando for fornecido um valor
negativo, o programa deverá ser encerrado. O cálculo da raiz quadrada de x deve ser feito
de acordo com o método de Heron de Alexandria, descrito a seguir:
1. Chute um valor inicial para a raiz como sendo r (por exemplo, r = x/2).
2. Faça 𝑟 = (𝑟 + 𝑥/𝑟)/2.
3. Se |𝑟² − 𝑥| > ε, retorne ao passo 2.
4. Escreva r.
Obs.: o valor de ε corresponde à precisão desejada para o valor da raiz, por
exemplo, 10⁻⁵.

Em programação muitas vezes o cálculo de um valor utiliza um método numérico.


Neste caso, o método de Heron, criado na Grécia antiga, muito antes de se imaginar
construir o primeiro computador, pode ser classificado como um método de aproximações
sucessivas.

Estima-se um valor inicial, a partir de um valor qualquer. No passo 1, sugere-se um


chute inicial igual à metade do valor. Os valores estimados vão usar o valor da estimativa
atual, usando sempre a mesma fórmula: 𝑟 = (𝑟 + 𝑥/𝑟)/2. Para cada valor estimado será
feita uma comparação de quão próximo do valor exato, a estimativa feita está. A estimativa
do erro é feita pegando o módulo da diferença entre x e r². Quando o módulo da diferença é
menor do que o valor de ε o cálculo do valor da raiz é considerado satisfatório.

A Tabela 6.3 mostra os valores estimados pelo algoritmo e o valor do erro, para cada
iteração do comando repetitivo, para cálculos da raiz quadrada de 4, 3, 2 e 1. Todos os
valores estão mostrados com 6 casas decimais, já que a precisão utilizada foi de 10⁻⁵. Em
negrito, foi feito o destaque para o valor considerado como a resposta correta, dentro da
margem de erro para cada cálculo.

Observe que para calcular 4 a primeira estimativa (2) coincide exatamente com o
valor da raiz e o erro é zero. Para os cálculos de 3 e 2 foram necessárias 3 iterações do
algoritmo. Observe que o erro para 3 aparece como se fosse zero, mas isso é devido ao
uso de 6 casas decimais. Caso a impressão tivesse sido feita com 10 casas decimais, os
valores de estimativa para 3 e o erro, na terceira iteração seriam, respectivamente
1.7320508100 e 0.0000000085.

Tabela 6.3 - Estimativas e erro para cálculo de raiz quadrada com precisão 10⁻⁵.
Iteração 4 3 2 1

Estim. Erro Estim. Erro Estim. Erro Estim. Erro

1 2.000000 0.000000 1.750000 0.062500 1.500000 0.250000 1.250000 0.562500

2 1.732143 0.000319 1.416667 0.006944 1.025000 0.050625

3 1.732051 0.000000 1.414216 0.000006 1.000305 0.000610

4 1.000000 0.000000

Este algoritmo converge muito rapidamente para o valor considerado satisfatório,


dentro da margem de erro especificada. Por isso ele é implementado para cálculo de raiz

127
Introdução à Programação com Python

quadrada em bibliotecas matemáticas. No código foi utilizada a função abs(x) que, dado um
número x, informa o seu módulo. Implementar um código para realizar tal tarefa é trivial,
pois bastaria testar se o valor de x é negativo e, se for, multiplicar por -1. O código que
implementa o algoritmo discutido anteriormente é apresentado na Figura 6.11, juntamente
com a exibição do resultado da execução, na janela do Shell, para os valores de raiz
quadrada de 4, 3, 2 e 1.

Note que os resultados são os mesmos da Tabela 6.3. Obviamente, os valores da


tabela 6.3 não foram obtidos utilizando uma calculadora, pois poderiam ocorrer erros de
digitação e levaria muito mais tempo. Ao invés disso, foi utilizado o comando de impressão,
após cada nova estimativa feita pelo programa com a expressão 𝑟 = (𝑟 + 𝑥/𝑟)/2, para
exibir a nova estimativa (r) e o módulo do erro: print('Estim.: %.6f Erro: %.6f' %(r, (r**2 - x))).
Os valores gerados pelo programa foram, então, copiados para a tabela 6.3. Na versão final
do programa, estes comandos de impressão foram retirados e uma nova execução foi feita
para gerar os resultados apresentados na Figura 6.11.

Figura 6.11 - Programa para cálculo de raiz quadrada

128
Introdução à Programação com Python

Observe que no programa o caractere ‘\n’ foi utilizado em alguns comandos de


impressão para forçar a criação de uma nova linha para melhorar a visualização dos
resultados gerados pelo programa.

Note, também, que a variável epson foi criada fora do comando repetitivo enquanto
que a variável r foi criada dentro da cláusula else, que está dentro de um comando
repetitivo. Como a precisão (epson) é fixa, ela pode (e deve) ser inicializada uma única vez.
Em outras linguagens de programação seria chamada de constante e não de variável. Já o
valor da variável r deve ser inicializada para cada novo cálculo de raiz a ser feito, com um
valor (x/2) que depende do valor informado pelo usuário.

Eventualmente, em uma outra versão do programa onde o usuário possa definir a


precisão que ele queira, a variável epson poderia ser inicializada com diferentes valores
para cada execução do programa ou para cada cálculo novo.

6.4. Exercícios

1) Faça um programa que imprima a soma dos 100 primeiros números naturais.

2) Escreva um programa que imprimir os múltiplos de 7 menores que 100.

3) Escreva um programa que exiba os números divisíveis por 4 e por 5 menores que
200.

4) Faça um programa que receba um inteiro N e calcule os seus divisores.

5) Escreva um programa para ler o número de alunos existentes em uma turma, ler a
nota de cada aluno e calcular a média aritmética da turma.

6) Escreva um programa para escrever a soma dos números pares e a soma dos
números ímpares de 1 a 200, inclusive.

7) Escreva um programa que verifique a validade de uma senha fornecida pelo usuário.
A senha válida é 1234. Caso a senha informada pelo usuário seja inválida, a
mensagem "ACESSO NEGADO" deve ser impressa e repetida a solicitação de uma
nova senha até que ela seja válida. Caso contrário deve ser impressa a mensagem
"ACESSO PERMITIDO" junto com um número que representa quantas vezes a
senha foi informada.

8) Faça um programa para ler um número entre 1 e 9 e mostrar a tabuada da


multiplicação do número lido.

129
Introdução à Programação com Python

9) Escreva um programa que calcule o fatorial de N (N!), informado pelo usuário.


Sendo que: N! = 1 * 2 * 3 * ... * (N - 1) * N. Por definição o fatorial de 0 é 1 (0! = 1).
Caso o usuário digite um valor negativo, o programa deve informar que a função
fatorial não está definida para números negativos e solicitar um novo número.

𝑏
10) Faça um programa que receba dois números, inteiros e positivos a e b, e calcule 𝑎 ,
sem usar a função ou o operador **.

11) Escreva um programa para ler 2 notas de um aluno, calcular e imprimir a média final.
Logo após escrever a mensagem "Calcular a média de outro aluno [S]im [N]ao?" e
solicitar uma resposta. Se a resposta for “S” ou “s”, o programa deve ser executado
novamente, caso contrário deve ser encerrado imprimindo a quantidade de alunos
aprovados, reprovados e que ficaram em exame final, considerando o mesmo
critério adotado pela UFV, conforme tabela mostrada a seguir.

Nota Situação

0-39 Reprovado

40-59 Exame Final

60-100 Aprovado

OBS: as notas finais na UFV são sempre valores inteiros, com arredondamento para
cima se o valor decimal for maior ou igual a 0,5 e arredondamento para baixo, caso
contrário. Ex: 59.4 vira 59 e 59.5 vira 60.

12) A CBF contratou você para escrever um programa que faça uma estatística do
resultado de vários Fla-Flu. Você deve escrever um programa para ler o número de
gols marcados pelo Flamengo e o número de gols marcados pelo Fluminense em
um Fla-Flu. Logo após escrever a mensagem "Novo Fla-Flu 1.Sim 2.Nao?" e solicitar
uma resposta. Se a resposta for 1, o algoritmo deve ser executado novamente
solicitando o número de gols marcados pelos times em uma nova partida, caso
contrário deve ser encerrado imprimindo:
Quantos Fla-Flu fizeram parte da estatística.
O número de vitórias do Flamengo.
O número de vitórias do Fluminense.
O número de Empates
Uma mensagem indicando qual o time que venceu o maior número de Fla-Flu (ou
NÃO HOUVE VENCEDOR).

Veja os exemplos:
Numero de gols do Flamengo: 2
Numero de gols do Fluminense: 1
Novo Fla-Flu 1.Sim 2.Nao? 2

--Resultado Final--

130
Introdução à Programação com Python

Numero de partidas do Fla-Flu: 1


Numero de vitorias do Flamengo: 1
Numero de vitorias do Fluminense: 0
Numero de empates: 0
Time com maior numero de vitorias: Flamengo

Numero de gols do Flamengo: 0


Numero de gols do Fluminense: 2
Novo Fla-Flu 1.Sim 2.Nao? 1
Numero de gols do Flamengo: 2
Numero de gols do Fluminense: 0
Novo Fla-Flu 1.Sim 2.Nao? 1
Numero de gols do Flamengo: 0
Numero de gols do Fluminense: 0
Novo Fla-Flu 1.Sim 2.Nao? 2

--Resultado Final--
Numero de partidas do Fla-Flu: 3
Numero de vitorias do Flamengo: 1
Numero de vitorias do Fluminense: 1
Numero de empates: 1
Nao houve vencedor

13) Altere o programa da solução do exercício 12 para incluir como critério de


desempate o maior número de gols marcados, no caso de não haver time com maior
número de vitórias.

14) Considere somatório de uma série infinita como a mostrada a seguir:


∞ (𝑖)
−1 1 1 1 1 1
∑ 𝑖
= 2
− 3
+ 4
− 5
+ 6
+...
𝑖=2

Faça um programa para calcular o somatório dos N primeiros elementos da


sequência. O valor de N deve ser informado pelo usuário do Programa. Execute seu
programa para diferentes valores de N e certifique-se de que o somatório é
convergente.

Altere o programa para que ele execute diversas vezes, parando quando o usuário
informar um valor menor ou igual a zero para N.

15) Faça um programa para calcular o produto dos N primeiros elementos de uma série,
conforme mostrado a seguir:
𝑁
𝑖 1 2 3 4 5 𝑁
∏ 𝑖+1
= 2
× 3
× 4
× 5
× 6
×... × 𝑁+1
𝑖=1
O número de elementos do produtório deverá ser informado pelo usuário do
programa. Execute seu programa para diferentes valores de N e certifique-se de
que o produtório é convergente.

131
Introdução à Programação com Python

Altere o programa para que ele execute diversas vezes, parando quando o usuário
informar um valor menor ou igual a zero para N.

16) Uma série conhecida para o cálculo de π foi desenvolvida por Leibniz em 1682,
utilizando-se da série de Taylor para a função arctan(x), tomando-se x=1, e, por
conseguinte, arctan(1) = π/4 (Fonte: https://pt.wikipedia.org/wiki/Pi). Assim, pode-se
escrever que:
𝑁 𝑖
4×(−1) 4 4 4 4 4
π = ∑ 2×𝑖+1
= 4− 3
+ 5
− 7
+ 9
− 11
+...
𝑖=0

Faça um programa para calcular o valor de π usando o somatório dos N primeiros


elementos da sequência acima. Execute seu programa para diferentes valores de N
e verifique como a precisão do resultado evolui com o aumento de N. Imprima o
resultado com 8 casas decimais.

Altere o programa para que ele execute diversas vezes, parando quando o usuário
informar um valor menor ou igual a zero para N.

17) Uma outra série conhecida para o cálculo de π foi desenvolvida por Nilakantha e tal
proposição é mostrada a seguir:

∞ 𝑖+1
(−1) ×4 4 4 4 4
π=3 + ∑ (2𝑖)(2𝑖+1)(2𝑖+2)
= 3+ 2×3×4
− 4×5×6
+ 6×7×8
− 8×9×10
𝑖=1

Faça um programa para calcular o valor de π usando o somatório dos N primeiros


elementos da sequência acima. Note que o primeiro elemento não segue a regra de
geração dos demais elementos. Execute seu programa para diferentes valores de N
e verifique como a precisão do resultado evolui com o aumento de N. Imprima o
resultado com 8 casas decimais.

Altere o programa para que ele execute diversas vezes, parando quando o usuário
informar um valor menor ou igual a zero para N.

18) O valor de π também pode ser obtido com o produtório. Uma destas soluções foi
proposta pelo matemático francês François Viète, que estudando o método de
Arquimedes, desenvolveu a seguinte série para o cálculo de em 1593 (Fonte:
https://pt.wikipedia.org/wiki/Pi):

2 2 2+ 2 2+ 2+ 2 2+ 2+ 2+ 2
π
= 2
× 2
× 2
× 2
×...

Escreva um programa para calcular o valor de π usando o produtório acima,


considerando os N primeiros elementos da sequência acima. Note que o primeiro
elemento não segue a regra de geração dos demais elementos. Execute seu
programa para diferentes valores de N e verifique como a precisão do resultado
evolui com o aumento de N. Imprima o resultado com 8 casas decimais.

132
Introdução à Programação com Python

Altere o programa para que ele execute diversas vezes, parando quando o usuário
informar um valor menor ou igual a zero para N.

19) Junte as soluções feitas para os exercícios 16 a 19 para implementar um programa


que apresente o valor de π com precisão de 8 casas decimais, para diferentes
valores de N, comparando a eficiência de cada um dos algoritmos em convergir mais
rapidamente para o valor exato. O valor de π com 8 casas decimais é 3,14159265.
O programa deve perguntar ao usuário o número máximo de elementos da série (N)
e mostrar o valor calculado de πpara a série com 1 até N elementos, em forma de
tabela, como mostrado na figura a seguir.

20) Modifique o programa da questão anterior para permitir que o usuário especifique a
precisão (limitada a 15 casas decimais) e a execução do programa seja feita de
maneira repetitiva, até que o usuário informe que o número de elementos é zero. O
programa deverá, ainda, verificar a diferença entre o valor calculado e o valor exato,
de cada método e informar qual deles teve a menor diferença, ou o melhor, em cada
passo. O valor de πcom 15 casas decimais é 3,141592653589793. O programa
deverá gerar uma saída como a mostrada a seguir:

133
Introdução à Programação com Python

21) Modifique a implementação do programa mostrado na seção 6.3.2 para determinar


se um número é primo usando as ideias discutidas no último parágrafo da referida
seção. Teste seu programa para um número primo grande (ex: 2147483647) e
verifique que o tempo cairá de alguns minutos para alguns milisegundos.

134
Introdução à Programação com Python

Capítulo 7 - Arranjos

Até este ponto foram utilizadas apenas variáveis simples ou escalares. Elas são
muito úteis, mas não permitem realizar alguns tipos de cálculos. Suponha um programa
para ler uma sequência de notas de uma turma de N alunos e informar: a média das notas,
a maior nota, a menor nota, o desvio padrão das notas e o número de notas abaixo da
média. Suponha uma turma com apenas N=4 alunos com a seguinte lista de notas: 65, 92,
87 e 54.

O cálculo da média é um problema já resolvido na seção 6.3.1, bastando calcular o


somatório de todas as notas e dividir o valor pelo número de notas lidas (N). O valor do
somatório deve ser inicializado com o valor zero e, para cada nota lida, incrementar no valor
do somatório o valor lido. Em Python, para as 4 notas, poderia ser escrito o seguinte código:

soma = 0
for i in range (0, N):
nota = float(input(‘Nota: ‘))
soma = soma + nota
media = soma/N
print(‘A média das notas é: %.2f’ %media)

A identificação da maior (ou menor) nota poderia ser feita com a informação da faixa
de valores das notas, por exemplo, de [0, 100], utilizando a mesma estrutura do código
acima. A variável maior seria criada antes do comando repetitivo com um valor -1. Com este
valor inicial, qualquer nota lida na faixa [0, 100] será maior do que o valor inicial. Portanto,
dentro do comando repetitivo, basta comparar se a nota lida é maior do que a variável
maior. Se for, a variável maior seria atualizada para receber o valor da nota que acabou de
ser lida. O código poderia ser incrementado para determinar a maior nota, como mostrado a
seguir. Em negrito, os comandos para computar e informar a maior nota:

soma = 0
maior = -1
for i in range (0, N):
nota = float(input(‘Nota: ‘))
soma = soma + nota
if nota > maior:
maior = nota
media = soma/N
print(‘A média das notas é: %.2f’ %media)
print(‘A maior nota é: %.2f’ %maior)

Analogamente, para identificar a menor nota bastaria criar outra variável (por
exemplo menor) com valor inicial acima da faixa. E no comando repetitivo, para cada nota
lida que for menor do que o valor atual da variável menor, o valor da variável menor deverá
receber o valor da nota que acabou de ser lida. Com esta inclusão, o código ficaria como a
seguir. Em negrito, agora, os comandos para calcular e exibir a menor nota:

135
Introdução à Programação com Python

soma = 0
maior = -1
menor = 101
for i in range (0, N):
nota = float(input(‘Nota: ‘))
soma = soma + nota
if nota > maior:
maior = nota
if nota < menor:
menor = nota
media = soma/N
print(‘A média das notas é: %.2f’ %media)
print(‘A maior nota é: %.2f’ %maior)
print(‘A menor nota é: %.2f’ %menor)

Para completar a tarefa demandada, é necessário calcular o desvio padrão e o


número de nota abaixo da média. O desvio padrão pode ser calculado pela expressão:

𝑛
𝐷𝑒𝑠𝑣𝑖𝑜𝑃𝑎𝑑𝑟𝑎𝑜 = ∑ (𝑥𝑖 − µ)² / 𝑛
𝑖=1

Onde 𝑥𝑖 corresponde a cada uma das notas e µ é a média das notas lidas, que já foi
calculada. O cálculo do somatório poderia ser feito usando a estrutura já conhecida e usada
para o somatório das notas. Porém, cada incremento deste novo somatório seria definido
pela expressão (nota - media)**2. Porém, não é possível fazer este cálculo pois apenas o
valor da última nota lida está disponível na variável nota. Os demais N-1 valores de notas
foram sobrescritos (perdidos) a cada novo comando de leitura (input()). Só existe uma
posição de memória associado à variável nota, onde só “cabe” um único valor.

O mesmo problema acontece para determinar o número de notas menores do que a


média. É necessário, primeiramente, ter a média calculada para, depois, comparar cada
uma das notas lidas com o valor da média. Novamente, não seria possível realizar a
computação pretendida. Pedir ao usuário para digitar novamente todas as notas está
totalmente fora de questão.

7.1. Arranjo unidimensional

Para as variáveis escalares que foram utilizadas nos capítulos anteriores, o


interpretador Python aloca espaço na memória suficiente para armazenar um único valor.
Por isso, no problema para ler várias notas e realizar alguns cálculos, cada vez que uma
nova nota era lida, o valor que estava guardado na posição de memória da variável nota era
perdido. Apenas a última nota lida estava disponível na memória. Para resolver o problema
da necessidade de armazenar valores lidos para uso posterior, as linguagens de
programação possuem a definição de estrutura de dados conhecida como arranjos, também
chamados de arranjos unidimensionais, listas, vetores ou arrays.

Na linguagem Python não existe a estrutura de dados para reprresentar o arranjo


que será apresentado na sequência. Ao invés disso, Python usa uma estrutura de dados

136
Introdução à Programação com Python

chamada lista, que é bem mais genérica, mas que será objeto de estudo na disciplina INF
101 - Introdução à Programação II. Pode-se dizer que um arranjo seria um tipo particular de
lista na qual todos os elementos são do mesmo tipo. Como um dos objetivos da disciplina
INF 100 - Introdução à Programação I é apresentar os conceitos fundamentais de
programação, habilitando o estudante a usar outras linguagens de programação, neste texto
os arranjos serão apresentados como definido em outras linguagens de programação como
C, C++, Java, etc.

Um arranjo é um agregado de elementos (conjunto de variáveis) do mesmo tipo,


todos relacionados a um mesmo nome dentro do programa. Um arranjo pode ser uni, bi, tri
ou n-dimensional. Nesta seção, será tratado apenas dos arranjos unidimensionais. Cada
elemento do agregado, ou cada valor individual, será indexado por um número número
inteiro, indicando a sua posição relativa no arranjo. Os índices dos elementos de um arranjo
começam sempre de 0.

O esquema de representação de um arranjo unidimensional em memória pode ser


visto como o diagrama da Figura 7.1, onde cada posição é identificada por um índice e pode
armazenar um valor de um determinado tipo.

Figura 7.1 - Esquema de representação de um arranjo

No exemplo, a estrutura (arranjo) de nome v contém 5 números inteiros em


memória. Da mesma forma que acontece com uma variável escalar, um arranjo deve ser
referenciado pelo seu nome. Porém, quando se deseja acessar um elemento do arranjo, ele
deve ser referenciado pelo nome do arranjo e o seu índice.

O elemento da posição 4 do arranjo v deve ser referenciado no programa como v[4].


O valor de v[4] é igual a -3. Os valores dos índices possui valor -3. Atente para o fato de que
a posição 4 de um arranjo corresponde à quinta posição, pois a primeira posição é sempre
a posição 0.

Figura 7.2 - Esquema alternativo de representação de um arranjo

No exemplo da Figura 7.1, em que o arranjo possui tamanho igual a 5 (número de


elementos do arranjo) o interpretador da linguagem Python irá alocar 5 posições na
memória e associar a primeira posição (0) ao nome do arranjo (v). Por isso, é necessário

137
Introdução à Programação com Python

usar o nome do arranjo (v) junto com o índice, de modo a definir o deslocamento (em
posições de memória) a partir da posição inicial, chegando ao elemento desejado. Uma
outra forma de visualizar uma arranjo é mostrado na Figura 7.2.

Note que não há problema algum em armazenar um mesmo valor em posições


diferentes de um arranjo, mas os índices do arranjo são sempre distintos, iniciando em 0 e
incrementado unitariamente até N-1, para um arranjo de tamanho N. No exemplo ilustrado
nas Figuras 7.1 e 7.2, N=5 e os índices são 0, 1, 2, 3 e 4. Os valores armazenados nas
posições de índice 1 e 3, ou na segunda e quarta posições são iguais, ou ainda, v[1] = v[3]
= 3.

7.1.1 Arranjos em Python

Para criar e manipular arranjos numéricos (vetores e matrizes) em Python, pode ser
usada a biblioteca numpy, pois ela proporciona uma maior facilidade para criar e inicializar
os arranjos, além de possuir características similares a outras linguagens de programação,
permitindo criar arranjos de tipos específicos. Para isso, é preciso importar a biblioteca
usando a diretiva de importação como mostrado a seguir:

import numpy

Após a importação, as funções definidas na biblioteca numpy podem ser


referenciadas (usadas) no programa. A função empty permite criar um arranjo de tamanho
N números reais, não inicializado:

identificador = numpy.empty(N)

O identificador determina o nome da variável do tipo arranjo que identifica o conjunto


de dados. Exemplo:

notas = numpy.empty(5) # cria o arranjo notas com 5 posições


alturas = numpy.empty(10) # cria o arranjo alturas com 10 posições

O não inicializado significa que as posições de memória alocadas para o arranjo


possuem um valor qualquer. Um comando de impressão para mostrar o valor de uma
posição de um arranjo que acabou de ser criado com a função empty poderia exibir algo
como 6.9481849316902e-310 (este foi um resultado exibido pelo Shell do IDLE).

Em alguns casos pode ser necessário preencher todas as posições de um arranjo


com o valor zero. A função zeros realiza esta tarefa. Também é possível dar um 'apelido'
para uma biblioteca, só para podermos usar um nome menor, chamando numpy de np, por
exemplo. A seguir, um exemplo de criação de arranjos com todos os valores iguais a zero e
o uso do apelido para a biblioteca numpy:

import numpy as np
notas = np.zeros(5) # cria o arranjo notas com 5 posições iguais a 0
alturas = np.zeros(10) # cria o arranjo alturas com 10 posições iguais a 0

Por padrão, na biblioteca numpy a criação de um arranjo considera que o tipo de


cada elemento será número real (ou de ponto flutuante). Para criar um arranjo com

138
Introdução à Programação com Python

elementos de outro tipo deve ser usado o parâmetro dtype=<tipo>, onde <tipo> especifica o
tipo dos elementos do arranjo que será criado. Por exemplo, a criação de um arranjo de
números inteiros, já inicializado com zeros poderia ser feita assim:

import numpy as np
idades = np.zeros( 10, dtype=int )

Quando um arranjo é pequeno, o programador pode definir os valores inciais


manualmente, como nos comandos a seguir:

A = np.array([4, 3, 2, 1]) # arranjo de números inteiros


notas = np.array([70.5, 80, 54.3, 77.8]) # arranjo de números reais

Alguns exemplos simples de operações e acesso sobre elementos de um arranjo


são apresentadas a seguir no trechos de código com comentários (ressaltando um erro
existente):

v = np.empty(5) # Cria um vetor v de 5 elementos

v[0] = -9 # Atribui valor na primeira posição


v[1] = 3 # idem, na segunda posição
v[2] = 4 # idem, na terceira posição
v[3] = 3 # idem, na quarta posição
v[4] = -3 # idem, na quinta posição, compare com Figura 7.1

print( v[4] + v[0] ) # exibe -12.0 (-3 + -9)


v[0] = v[2] = -10 # armazena -10 nas 3a e 1a posições
v[3] = float(input()) # lê, do usuário, novo valor para v[3]

v[4] = v[3] + v[2]*v[2] # v[4] = valor informado pelo usuário + 100


print(v[-1]) # Imprime o valor da última posição v[4]
print(v[5], v[1.5] ) # Erro de acesso (índices inválidos)

O trecho de código executaria até parar no comando input(), à espera de um valor


digitado pelo usuário. Supondo que o usuário digite o valor 0 (zero) e a tecla Enter. O
programa, então, imprimiria o valor 100 e terminaria com a exibição de uma mensagem de
erro : ‘IndexError: index 5 is out of bounds for axis 0 with size 5’. Esta mensagem indica que
foi feita uma tentativa de acesso a uma posição (5) que não existe no arranjo. Um arranjo
de tamanho 5, possui índices de 0 a 4. Note, que o índice 1.5 também é inválido, mas não
chegou a ser analisado pelo interpretador Python, que para a execução no primeiro erro
encontrado.

Mas porque o comando print() anterior que referenciou a posição -1 não deu erro de
acesso ou índice fora da faixa? A linguagem Python possui algumas características bem
peculiares. Uma delas é permitir o uso de índices negativos, dentro de uma faixa bem
específica, como no penúltimo comando do trecho de código acima. O comando print(v[-1])
imprime o valor contido na última posição ou a posição N-1 do arranjo. É como se o arranjo
também fosse indexado de trás para frente, com o valor -1 referenciando a posição N-1, o
valor -2 referenciando a posição N-2 e assim por diante, até chegar ao índice -N que
corresponde à posição N-N, ou posição 0. Ou seja, para um arranjo de 5 elementos, como o
do exemplo, são permitidos os índices 0 ou -5, 1 ou -4, 2 ou -3, 3 ou -2 e 4 ou -1, para

139
Introdução à Programação com Python

referenciar da primeira para a última posições do arranjo. Nos exemplos, serão utilizados
sempre os índices positivos.

7.1.2 Percorrendo Arranjos

Ao usar arranjos, uma necessidade frequente é percorrer todos os elementos do


arranjo, fazendo alguma tarefa com cada elemento ou com os elementos que atendam a
uma determinada condição. Alguns exemplos possíveis:

para cada elemento i do arranjo A:


Escreva A[i] na tela

para cada elemento i do arranjo A:


Multiplique A[i] por 2

É possível fazer isso facilmente usando o comando repetitivo while. No caso do


comando while é fundamental fazer a inicialização correta da variável de controle (i) e o seu
incremento dentro do comando repetitivo:

i=0
while i < len( A ):
print( A[i] )
i=i+1

No entanto, o comando repetitivo for é bem mais apropriado para essas situações
pois a inicialização da variável de controle é feita no cabeçalho do comando e o seu
incremento é automático:

for i in range(len(A)):
print( A[i] )

A função len(A) retorna o valor do da dimensão do arranjo A, ou a quantidade de


elementos que o arranjo A possui. A seguir são apresentados dois exemplos simples de
programas completos utilizando arranjos com tamanho definido pelo usuário. O tamanho do
arranjo e, consequentemente, o número de repetições para percorrer todo o arranjo será
dependente de um parâmetro informado pelo usuário. Este tipo de solução é chamada de
solução parametrizada.

O primeiro exemplo é um programa que solicita ao usuário o tamanho (N) do arranjo


e depois cada um dos N valores do arranjo. Na sequência, cada elemento do arranjo é
multiplicado por 2 e, depois, os valores do arranjo são impressos, um em cada linha:

import numpy as np
n = int( input('Número de elementos: '))
A = np.empty( n ) # Criação do arranjo
# Leitura do arranjo pelo teclado
for i in range(0, n):
A[i] = float( input('Informe o %d⁰ elemento: ' % (i+1)))
# Multiplicando o arranjo por 2
for i in range(0, n):

140
Introdução à Programação com Python

A[i] = A[i] * 2
# Escrita do arranjo na tela
for i in range(0, n):
print( A[i] )

Observe que para solicitar que o usuário forneça cada valor foi usado o índice i+1,
de modo que a mensagem apareça como ‘Informe o 1⁰ elemento: ’, quando o valor de i for
0, referente ao primeiro elemento do arranjo. O usuário do programa não é obrigado a
conhecer programação e para ele pode não fazer sentido falar em elemento da posição
zero.

No exemplo anterior, como os valores do arranjo não são utilizados para nenhuma
outra tarefa posterior, o mesmo resultado (o que o usuário enxerga na execução do
programa) poderia ser obtido com o seguinte código:

import numpy as np
n = int( input('Número de elementos: '))
A = np.empty( n ) # Criação do arranjo
# Leitura do arranjo pelo teclado
for i in range(0, n):
A[i] = float( input('Informe o %do elemento: ' % (i+1)))
# Escrita dos elementos do arranjo multiplicados por 2, na tela
for i in range(0, n):
print( 2*A[i] )

O próximo exemplo também solicita que o usuário informe o tamanho do arranjo.


Mas os valores dos elementos são gerados por uma regra definida no código do programa
para gerar a sequência: 0, 2, 4, .., 2*(N-1). Ou seja, se o usuário informar N=8, a sequência
gerada e armazenada nas posições do arranjo será: 0, 2, 4, 6, 8, 10, 12 e 14. Depois, o
programa imprime os elementos do arranjo na mesma linha (end=’ ‘) de três formas
diferentes: separados por um espaço; separados por um espaço de tabulação (caractere
'\t'); e usando formatação de número de ponto flutuante com espaço total 7 e precisão de 3
casas decimais.

import numpy as np
n = int( input('Número de elementos: '))
A = np.zeros( n ) # Criação do arranjo, preenchido com 0.0
# Preenchimento do arranjo
for i in range(1, n):
A[i] = A[i-1] + 2
# Escrita do arranjo na tela, elementos separados por espaço
for i in range(0, n):
print( A[i], end=' ')
print()
# Escrita do arranjo na tela, elementos separados por tabulação
for i in range(0, n):
print( A[i], end='\t')
print()
# Escrita do arranjo na tela, elementos formatados
for i in range(0, n):
print('%7.3f' % A[i], end='')

141
Introdução à Programação com Python

A criação do arranjo, neste último exemplo, foi feita usando a função zeros da
biblioteca numpy. Inicialmente, então, todas as posições foram preenchidas com o valor 0
na criação do arranjo.

O primeiro comando for foi usado para gerar os elementos das posições 1 a N-1
usando o valor do elemento imediatamente anterior. Observe que a faixa definida para o for
começa em 1. Deve ficar claro que nem sempre será necessário percorrer todo o arranjo,
vai depender da tarefa que se deseja fazer. O elemento da posição i será igual ao elemento
da posição anterior (i-1) incrementado de 2 ou A[i] = A[i-1] + 2, para i de 1 até N-1 ou da
segunda posição do arranjo em diante. O elemento da posição 0 será o elemento base para
a geração de todos os outros. Como o valor da primeira posição é zero, a sequência gerada
será 0, 2, 4, 6,...,2*(N-1). Se o comando A[0] = 5 fosse inserido no código, antes do primeiro
comando for, alterando o elemento base de 0 para 5, a sequência gerada seria: 5, 7, 9,
11,...,2*(N-1)+5. A regra de geração continuou a mesma: cada elemento é igual ao elemento
anterior + 2.

Na sequência, os elementos gerados são exibidos de 3 formas diferentes. Um dos


exercícios propostos é a implementação deste exemplo e a execução do programa para
diferentes valores de N, pois dependendo da quantidade de números gerados na
sequência, a forma de exibição da saída na tela pode ajudar (ou atrapalhar) a sua
visualização por parte do usuário do programa.

7.1.3. Alguns Exemplos

Nesta seção são apresentados alguns exemplos para a solução de problemas


utilizando arranjos e comandos repetitivos. O problema será proposto como se fosse um
enunciado de exercício a ser resolvido.

7.1.3.1. Cálculo do desvio-padrão

Faça um programa em Python que leia as notas de uma turma de N alunos de um


curso de idiomas e exiba em tela: a média das notas; o desvio padrão das notas; a maior
nota; a menor nota; e a quantidade de notas menor que a média. As notas estão na faixa de
0 a 100.

Este foi o problema apresentado no início do capítulo e já se sabe que é necessário


computar média para depois ser possível calcular o desvio padrão e verificar quantas notas
são menores do que a média. Assim, a última versão do algoritmo apresentada na
introdução deste capítulo pode ser complementado para computar estas duas informações,
como mostrado a seguir:

Leia(N) # Lê o tamanho da turma


nota = arranjo(N) # cria o arranjo de tamanho N
soma = 0 # inicializa o valor do somatório
maior = -1 # inicializa com valor MENOR que qualquer nota
menor = 101 # inicializa com valor MAIOR que qualquer nota
# comando repetitivo para computar a soma das notas, maior nota e menor nota

142
Introdução à Programação com Python

para i de 0..N-1:
nota[i] = Leia(‘Nota: ‘) # guarda cada valor em uma posição do arranjo
soma = soma + nota[i]
se nota[i] > maior: # compara se a nota lida é a maior
maior = nota[i]
se nota[i] < menor: # compara se a nota lida é a menor
menor = nota[i]
# fim do comando repetitivo
media = soma/N # cálculo da média
soma = 0 # inicializa o segundo somatório
cnam = 0 # contador de notas abaixo da media
# comando repetitivo: computa somatório (nota[i] - media)² e total de notas < média
para i de 0.. N-1:
soma = soma + (nota[i] - media)**2
se nota[i] < media:
cnam = cnam + 1
# fim do comando repetitivo
dp = (soma / N)**0.5 # cálculo do desvio padrão
# exibição dos resultados
Escreva(‘A média das notas é ‘, %media)
Escreva(‘O desvio padrão das notas é: ‘, dp)
Escreva(‘A maior nota é: ‘, maior)
Escreva(‘A menor nota é: ‘, menor)

A implementação do algoritmo acima é mostrada no programa da Figura 7.3.


Observe que na implementação em Python, alguns detalhes que não estavam
presentes no algoritmo foram considerados. O primeiro diz respeito à mensagem
inicial para que o usuário do programa possa saber o que o programa faz,
implementada com os dois primeiros comandos print().

Na leitura das notas foi considerado que o valor poderia ser real e que seria
feita a validação, verificando se está na faixa de 0..100. Caso não esteja, o
programa informará que a nota é inválida e repetirá o comando de leitura. Embora
esta validação não tenha sido explicitamente pedida no enunciado, foi mencionado a
faixa para as notas. Além disso, faz parte das boas práticas de programação
prevenir possíveis erros nas informações que o programa irá processar. Já em uma
questão de prova, a abordagem deve ser a de se ater apenas ao que está sendo
pedido explicitamente no enunciado.

Outra boa prática de programação é definir nomes para as variáveis que


ajudem a lembrar para que elas são usadas no programa. Um comentário, no
momento da criação da variável pode ser muito útil para este mesmo propósito. Por
exemplo a variável cnam foi batizado com as primeiras letras de “contador notas
abaixo média” e recebeu o comentário “# contador de notas abaixo da média”.

Comentários também são úteis para identificar a tarefa executada por certos
trechos do programa. Note que em um mesmo comando repetitivo for foram
executadas as tarefas de ler as notas, calcular o somatório das notas lidas,
identificar a maior e a menor notas lidas. Após o término deste primeiro comando for
é que a média das notas foi calculada.

143
Introdução à Programação com Python

Somente após o cálculo da média das notas é que seria possível calcular
corretamente, o desvio padrão e identificar o número de notas menores que a
média. Estas duas tarefas são feitas no segundo comando repetitivo for, pois
demandam percorrer novamente o arranjo.

Figura 7.3 - Programa para leitura de N notas e geração de estatísticas

Na parte final do programa todos os resultados foram exibidos. Nada impediria a


exibição dos resultados, à medida que estivessem sendo gerados. Mas a opção foi de
agrupar a exibição de todos os resultados ao final, para que fossem exibidos na ordem
especificada no enunciado.

7.1.3.2. Relação entre vizinhos

Faça um programa que leia uma sequência de N valores inteiros quaisquer e


escreva na tela a relação entre cada elemento 'vizinho'. Os elementos vizinhos são aqueles
em posições adjacentes do arranjo. A seguir é apresentado um exemplo da execução do
programa, observado na janela do Shell:

144
Introdução à Programação com Python

Figura 7.4 - Exemplo de execução do programa

Observe que no enunciado é apresentada uma determinada saída que deve ser
gerada pelo programa. Porém, a solução pode ser iniciada pelo algoritmo que tem uma
lógica relativamente simples, confome descrito a seguir:

Leia os elementos do arranjo


Escreva o primeiro elemento
para cada elemento da posição i = 1 até N-1:
escreva o operador relacional correto entre o elemento i e elemento i-1
escreva o elemento i

O primeiro elemento deve ser sempre escrito (posição 0), sem nenhuma restrição. A
partir deste elemento, antes de imprimir o próximo elemento do arranjo, deve ser verificado
que relação ele tem com o seu antecessor: maior, menor ou igual. O índice i do comando
repetitivo indicará o próximo elemento a ser escrito o seu antecessor, consequentemente,
será apontado por i-1. Por isso, o comando repetitivo será executado para a faixa de 1..n-1.

O resultado da comparação indicará que símbolo o programa deve imprimir: >, < ou
igual, dependendo da relação entre os valores das posições i e i-1. A seguir, a versão
detalhada do algoritmo:

Escreva(‘msg inicial’)
n = Leia(‘Informe o número de elementos do arranjo: ')
v = arranjo(n)
Escreva('Entre com os valores (um em cada linha):')
para i na faixa (0,n):
v[i] = input(i, '⁰ elemento: ')
Escreva(‘'Relações: ', mesmalinha')
Escreva(v[0], mesmalinha)
para i na faixa (1,n):
se (v[i] > v[i-1]):
print(' < ', mesmalinha)
senãose (v[i] < v[i-1]):
print(' > ', mesmalinha)
senão:
print(' = ', mesmalinha)
imprima(v[i])

A implementação do algoritmo para gerar exatamente a saída vista na Figura 7.4


pode ser vista na Figura 7.5.

145
Introdução à Programação com Python

Figura 7.5 - Implementação do programa para determinar a relação entre vizinhos

Nesta implementação a informação solicitada ao usuário do programa usa o índice


i+1 para que não apareça uma mensagem como: ‘0⁰ elemento’ na primeira execução do
primeiro comando repetitivo for.

Todos os comandos para imprimir o valor de um elemento do arranjo usam a diretiva


para manter o cursor na mesma linha (end=' '), para que a saída fique exatamente como a
proposta no exemplo do enunciado.

7.2. Arranjos multidimensionais

Os arranjos podem ser multidimensionais para representar estruturas mais


complexas do que as vistas até aqui. Um exemplo são os arranjos bidimensionais que
podem ser utilizados para a representação de matrizes. Diversos problemas na computação
e em outras tantas áreas do conhecimento podem ser mapeados em soluções matriciais.

Um arranjo bidimensional (ou matriz) M pode ser representado por um conjunto de


células (ou posições) de memória organizadas em linhas e colunas, como representado na
Figura 7.6, para um arranjo de 3 linhas e 4 colunas.

M
Índices 0 1 2 3

0 1 2.5 0 -4

1 0 1 -2 0.5

2 0 4 1 0.7

Figura 7.6 - Representação de um arranjo 3x4

146
Introdução à Programação com Python

Cada elemento é identificado pelo nome do arranjo e por dois índices para
referenciar a linha e a coluna do elemento. Por exemplo, o elemento M[i][j] corresponde à
célula posicionada na linha i e na coluna j. Na Figura 7.6, o índice de linha i varia de 0..2 e o
índice de coluna varia de 0..4. Da mesma forma que a primeira posição de um arranjo
unidimensional é referenciada pelo índice 0, em um arranjo bidimensional a primeira linha e
a primeira coluna também são referenciadas pelo índice 0.

Na Figura 7.6, o elemento M[2][1] possui valor 4. Cada posição do arranjo


bidimensional armazena um único valor. Um arranjo com m linhas e n colunas possui m x n
posições. O primeiro índice corresponde ao número da linha, enquanto que o segundo
índice indica o número da coluna.

Uma tarefa comum utilizando arranjos bidimensionais é percorrer todas as suas


posições para executar alguma tarefa. Um comando repetitivo aninhado dentro de outro
comando repetitivo pode ser usado para tal tarefa:

para cada linha i do arranjo:


para cada coluna j do arranjo:
executar tarefa com o elemento M[i][j]

Neste tipo de estrutura, o comando repetitivo interno é executado completamente


para cada iteração do comando repetitivo externo. Suponha o caso de um arranjo com m
linhas e n colunas. A execução do comando repetitivo externo começa com o índice i igual a
zero (primeira linha) e, dentro dele, se inicia a execução do comando repetitivo interno com j
também igual a zero (primeira coluna). Neste momento, o elemento M[0][0] está sendo
apontado pelos índices i e j.

O comando repetitivo interno continua a sua execução fazendo j igual a 1 (segunda


coluna), depois 2 (terceira coluna) e assim por diante. Ou seja, a variação do segundo
índice (j), mantendo o primeiro índice (i) fixo, faz com que a primeira linha seja percorrida,
coluna por coluna. Quando terminar a primeira iteração do comando repetitivo externo, o
índice i será incrementado e passará a valer 1 (segunda linha). E o comando repetitivo
interno será executado novamente, fazendo o índice j variar de 0 a N-1, percorrendo a
segunda linha, coluna por coluna. E assim, sucessivamente.

Desta forma a matriz vai sendo percorrida por linha. Em algumas situações pode
ser necessário percorrer a matriz por coluna. Para realizar a tarefa desta maneira, bastaria
inverter a ordem dos comando repetitivos, fixando no comando repetitivo externo o índice
da coluna e variando o índice de linha no comando repetitivo interno.

para cada coluna j do arranjo:


para cada linha i do arranjo:
executar tarefa com o elemento M[i][j]

Uma outra forma de visualizar um arranjo bidimensional é como uma estrutura de


dados de arranjo de arranjos unidimensionais, conforme mostrado na Figura 7.7, para
representar o mesmo arranjo exibido na Figura 7.6.

147
Introdução à Programação com Python

Figura 7.7 - Representação de arranjo bidimensional

O primeiro arranjo seria apenas um arranjo de índices (0..m-1), com cada índice
apontando para um arranjo unidimensional, com os elementos de uma linha da matriz. De
fato, esta estrutura é utilizada na implementação de algumas linguagens de programação,
como Python, por exemplo. Ela é bastante flexível, permitindo a sua recorrência para definir
um arranjo n-dimensional ou para ter estruturas com arranjos de tamanho diferente (mas
isso é assunto para quem for cursar a disciplina INF 101 - Introdução à Programação II).

Note que os algoritmos para percorrer o arranjo bidimensional independem da forma


de representação. Dessa forma, pode-se adotar a representação que se considere mais
conveniente ou a mais fácil de entender.

7.2.1. Definição de arranjos bidimensionais em Python

A definição de arranjos na linguagem Python pode ser feita diretamente no código


informando os valores de cada posição. Em geral, esta forma é adotada quando o número
de elementos é pequeno. A definição do arranjo 3x4 da Figura 7.6 na linguagem Python
pode ser feita da seguinte forma:

M = [ [1, 2.5, 0, -4], [0, 1, -2, 0.5], [0, 4, 1, 0.7] ]

Uma forma comumente adotada na definição de um arranjo bidimensional é


escrever os valores de maneira similar à representação em linhas e colunas, como
mostrado a seguir:

M = [ [1, 2.5, 0, -4] ,


[0, 1, -2, 0.5] ,
[0, 4, 1, 0.7]
]

Para o interpretador da linguagem Python não faz diferença a forma de escrita, se


em uma única linha ou imitando a representação matricial. O importante é que as regras de
sintaxe sejam respeitadas, ou seja, o identificador deve ser um nome válido, seguido do
operador de atribuição e dos elementos do arranjo entre colchetes e separados por vírgula.
Como cada linha possui um conjunto de valores, estes também devem vir entre colchetes e
separados por vírgulas.

Para a definição de arranjos com um número maior de elementos ou cujos


elementos serão definidos durante a execução do programa, ou ainda, quando não se sabe
inicialmente quais serão as dimensões do arranjo. Nestes casos, pode ser utilizada a

148
Introdução à Programação com Python

biblioteca numpy, como feito para arranjos unidimensionais, obviamente definindo as duas
dimensões (número de linhas e de colunas), como a seguir:

import numpy as np
A = np.empty( (3, 4) ) # cria o arranjo A com 3 linhas e 4 colunas

O arranjo criado acima, usando a função empty() da biblioteca numpy, não define
valores para os elementos de A. Caso tivesse sido utilizada a função zeros(), todos os
elementos teriam valor 0. Mas a biblioteca numpy também pode ser utilizada quando se
pretende definir valores iniciais para os elementos da matriz, como em:

import numpy as np
mi = np.array( [ [1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12] ] )
# imprime os elementos da matriz mi
for i in range(0, 4):
for j in range(0, 3):
print('%3d' % (mi[i][j]), end='')
print()

O trecho de código acima, além de definir os valores da matriz mi, faz também a
impressão dos elementos da matriz, usando a implementação do algoritmo de percorrer a
matriz por linha. Os elementos de cada linha são impressos pelo comando print() dentro do
comando for interno. Após a impressão de cada elemento, a diretiva ‘end=’ mantém o cursor
na mesma linha, de forma que todos os elementos da linha da matriz sejam impressos na
mesma linha na tela do computador. Na primeira iteração do comando for externo, com i=0,
a primeira linha da matriz foi impressa.

O comando print() dentro do comando for externo (última linha do código), faz pular
para a próxima linha. Após este print() o comando for externo termina uma iteração e
incrementará a variável de controle i. Para i = 1, 2 e 3 o comando for será executado
novamente, imprimindo os elementos das linhas 1, 2 e 3 ou segunda, terceira e quarta linha,
respectivamente. O resultado da impressão será:

1 2 3
4 5 6
7 8 9
10 11 12

Note que o parâmetro de formatação com 3 espaços foi suficiente para separar os
valores inteiros e dar a visão espacial de matriz, como nos livros de matemática, pois os
maiores valores numéricos ocupam 2 posições. Se o programador tivesse esquecido de
colocar o espaçamento, usando apenas '%d' invés de '%3d', a impressão sairia como
mostrada abaixo:

123
456
789
101112

149
Introdução à Programação com Python

7.2.2. Exemplos usando matrizes

A tarefa de percorrer um arranjo unidimensional ou bidimensional é, talvez, a tarefa


mais comum quando este tipo de estrutura de dados é utilizada. Nesta seção serão
apresentados alguns exemplos básicos de problemas utilizando arranjos.

7.2.2.1. Pesquisa em matriz

Faça um programa que leia os dados de uma matriz A de números reais, de


dimensões m x n. Em seguida, o programa deve ler um valor x que deverá ser pesquisado
na matriz. O programa deverá indicar em que posições da matriz o valor x aparece.

Repare que o enunciado não especificou as dimensões da matriz. Logo, estas


informações também deverão ser solicitadas ao usuário. Isso é bom, pois o programa ficará
parametrizado com o número de linhas (m) e o número de colunas (n). O algoritmo para
resolver este problema pode ser descrito assim:

m = Leia(‘Número de linhas da matriz: ‘)


n = Leia(‘Número de colunas da matriz: ‘)
A = arranjo(m, n)
“Leia os elementos da matriz”
x = Leia(‘Entre com o valor a ser pesquisado”)
“Pesquise x na matriz e informe a posição quando encontrar”
Se “não achou”
Escreva(‘x não está presente na matriz’)

O algoritmo acima ainda não está em uma forma que possa ser traduzido para a
linguagem Python. É necessário refinar as ações “Leia os elementos da matriz” e “Pesquise
x na matriz e informe a posição quando encontrar”. A primeira é mais simples e corresponde
à ação de solicitar ao usuário o valor de cada elemento da matriz. Isso pode ser
implementado com o algoritmo de percorrer a matriz por linha:

para i na faixa (0, m):


para j na faixa de (0, n):
A[i][j] = Leia(‘Elemento i, j)

Já a tarefa “Pesquise x na matriz e informe a posição quando encontrar” deve ser


feita com um pouco mais de atenção para tratar o caso de não ser encontrado o valor x na
matriz. O algoritmo básico também será o de percorrer toda a matriz e, para cada elemento,
fazer a comparação com o valor de x. Se for igual deverá ser impressa a sua posição. Além
disso deverá ser registrado que o valor foi encontrado. O registro de que o valor foi
encontrado pode ser feito atribuindo o valor verdadeiro para uma variável booleana. O nome
dessa variável será achou e seu valor será inicializado com Falso (antes de iniciar a
pesquisa, não achou é verdade, ou achou é falso). A seguir, o detalhamento desta ação:

achou = False
para i na faixa (0, m):
para j na faixa de (0, n):
se A[i][j] == x

150
Introdução à Programação com Python

Imprima(i, j)
achou = True

A Figura 7.8 apresenta a implementação Python do algoritmo discutido até este


ponto. Observe que, novamente, alguns elementos fundamentais para um programa como a
importação da biblioteca numpy e comandos adicionais para melhorar sua usabilidade e
visualização não estão presentes no algoritmo.

Figura 7.8 - Programa para encontrar um valor e informar sua posição em uma matriz

A impressão da matriz não foi solicitada no enunciado, mas fica melhor para o
usuário verificar se o programa gerou o resultado correto. A Figura 7.9 apresenta o
resultado de uma execução do programa da Figura 7.8, onde o valor procurado aparece 1
vez.

151
Introdução à Programação com Python

Figura 7.9 - Resultado de uma execução do programa da Figura 7.8

7.2.2.2. Verificação de propriedades de uma matriz

Faça um programa que leia os dados de uma matriz A de números reais, de


dimensões m x n. O programa deverá indicar se a matriz é uma matriz diagonal (elementos
fora da diagonal principal são todos iguais a zero) e, além disso, se é também uma matriz
identidade (matriz diagonal com todos os elementos da diagonal principal iguais a 1).

O algoritmo para atender ao que se pede no enunciado pode ser descrito da


seguinte forma:

m = Leia(‘Número de linhas da matriz: ‘)


n = Leia(‘Número de colunas da matriz: ‘)
A = arranjo(m, n)
“Leia os elementos da matriz”
“Verifique se a matriz é uma matriz diagonal”
Se “diagonal”:
“Verifique se a matriz é uma matriz identidade”
Se “identidade”:
Escreva(‘matriz é identidade’)
Senão:
Escreva(‘matriz é diagonal’)
Senão:
Escreva(‘matriz não é diagonal’)

Os quatro primeiros comandos do algoritmo são exatamente os mesmos do


algoritmo da subseção 7.2.2.1 e não serão rediscutidos aqui. Em caso de dúvidas, releia a
subseção anterior. O foco será no refinamento das ações “Verifique se a matriz é uma
matriz diagonal” e “Verifique se a matriz é uma matriz identidade”.

A primeira observação a ser feita é que para uma matriz ser diagonal (e identidade)
a primeira condição necessária é que ela seja uma matriz quadrada, ou seja, o número de
linhas deve ser igual ao número de colunas. Somente as matrizes quadradas possuem uma

152
Introdução à Programação com Python

diagonal principal. E matriz identidade é um caso particular da matriz diagonal. Então, o


algoritmo informará uma (e apenas uma) das quatro opções: 1) matriz não é quadrada; 2)
matriz não é diagonal; 3) matriz é diagonal; ou 4) matriz é identidade. Um primeiro
refinamento das ações para verificar se a matriz é uma matriz diagonal e matriz identidade
poderia ser escrito como:

se m != n:
Escreva(‘A matriz não é quadrada’’)
senão:
“Verifique se a matriz é uma matriz diagonal”
Se “diagonal”
“Verifique se a matriz é uma matriz identidade”
Se “identidade”
Escreva(‘matriz é identidade’)
Senão
Escreva(‘matriz é diagonal’)
Senão:
Escreva(‘matriz não é diagonal’)

Note que a ação “Verifique se a matriz é uma matriz diagonal” foi deslocada e
associada ao teste de uma condição, pois a verificação só precisa ser processada quando
m (número de linhas) for igual a n (número de colunas) - resultado falso do teste m != n. Se
o teste for verdadeiro, o algoritmo termina escrevendo que a matriz não é diagonal.

A verificação da propriedade de ser diagonal consiste em testar todos os elementos


fora da diagonal principal são iguais a zero. Para auxiliar na visualização da tarefa a ser
feita, a Figura 7.9 apresenta três matrizes quadradas de ordem 4: uma não diagonal, uma
diagonal e a outra identidade. A diagonal principal está destacada em cada uma delas.

Figura 7.9 - Exemplos de matrizes

A característica dos elementos da diagonal principal é que o número da linha é igual


ao número da coluna, ou seja, o índice de linha i é igual ao índice de coluna j.
Consequentemente, os elementos fora da diagonal principal tem o índice de linha i diferente
do índice de coluna j.

O algoritmo para percorrer toda a matriz pode ser usado e aplicando o teste apenas
para os elementos que estão fora da diagonal principal. Antes de iniciar o percorrimento da
matriz, pode-se supor que ela é diagonal. Se algum elemento fora da diagonal principal for
diferente de zero, ela não será diagonal. Em termos de algoritmo, isto pode ser escrito
como:

diagonal = True

153
Introdução à Programação com Python

para i de (0, m):


para j de (0, n):
se i != j E A[i][j] != 0
diagonal = False

Ao terminar este trecho, o algoritmo já terá armazenado na variável diagonal o valor


verdadeiro ou falso. Se o valor for falso, o algoritmo termina, escrevendo que a matriz não é
diagonal. Caso contrário, ele processará a verificação dos valores dos elementos da
diagonal principal, para informar se é uma matriz diagonal qualquer ou se é o caso especial
da matriz identidade. Para verificar se a matriz é uma matriz identidade, uma lógica similar a
usada anteriormente pode ser aplicada, porém, o teste agora será para os elementos com
valor do índice de linha i igual ao índice de coluna j:

identidade = True
para i de (0, m):
para j de (0, n):
se i == j E A[i][j] != 1
identidade = False
A versão completa do algoritmo refinado, juntando os refinamentos discutidos, é
mostrada a seguir:

# lendo dimensões da matriz


m = Leia(‘Número de linhas da matriz: ‘)
n = Leia(‘Número de colunas da matriz: ‘)
A = arranjo(m, n)
# leitura dos elementos da matriz A
para i na faixa (0, m):
para j na faixa de (0, n):
A[i][j] = Leia(‘Elemento i, j)
#verifica se matriz é quadrada (só pode ser diagonal ou identidade se for quadrada)
se m != n:
Escreva(‘A matriz não é quadrada’’)
senão:
# verifica se é diagonal. Elementos fora da diagonal devem ser iguais a zero
diagonal = True
# percorre a matriz toda e testa elementos com i != j (fora da diagonal principal)
para i de (0, m):
para j de (0, n):
se i != j E A[i][j] != 0
diagonal = False
Se “diagonal”
# verifica se é identidade. Todos elementos da diagonal devem ser iguais a 1
identidade = True
# percorre a matriz toda e testa elementos com i = j (da diagonal principal)
para i de (0, m):
para j de (0, n):
se i == j E A[i][j] != 1:
identidade = False
Se “identidade”:
Escreva(‘matriz é identidade’)
Senão:

154
Introdução à Programação com Python

Escreva(‘matriz é diagonal’)
Senão:
Escreva(‘matriz não é diagonal’)

A implementação deste algoritmo é mostrada na Figura 7.10. O resultado da


execução do algoritmo para 2 matrizes diferentes é mostrado na Figura 7.11. Foram usadas
matrizes 3x3 para que a figura não ocupasse mais de uma página.

Novamente o programa faz mais tarefas além daquelas expressas no enunciado,


como a impressão da matriz. Isso foi feito para o usuário visualizar não só o resultado da
classificação, mas também os elementos da matriz dispostos em linhas e colunas, de modo
a facilitar a inspeção visual para observar a correção do resultado.

Outras abordagens diferentes poderiam ser adotadas no algoritmo/programa. Uma


delas seria obrigar que toda matriz seja quadrada, ou seja, ao invés de aceitar valores
quaisquer para m e n, o programa poderia forçar que os dois valores fossem sempre iguais.

Figura 7.10 - Programa para classificação de uma matriz quadrada

155
Introdução à Programação com Python

Figura 7.11 - Resultados de duas execuções do programa da Figura 7.10

Outra modificação possível (e desejável) seria no sentido de melhorar a eficiência da


execução do código. O comando para percorrer todos os elementos de uma matriz executa
𝑚 𝑥 𝑛vezes ou 𝑚² vezes, quando a matriz é quadrada (m = n). Uma matriz com 1000 linhas
e 1000 colunas executaria 1000000 a comparação do comando if que está dentro de dois
comandos for aninhados, tanto para identificar o caso de matriz diagonal quanto para
identificar depois se a matriz diagonal é um caso particular de matriz identidade.

No caso da identificação da matriz diagonal, quando o primeiro elemento fora da


diagonal principal for diferente de zero, o comando repetitivo poderia parar, depois de
atribuir o valor falso para a variável diagonal. Este é um dos casos onde vale a pena

156
Introdução à Programação com Python

trabalhar com o comando repetitivo while. Veja como ficaria o código para a identificação da
propriedade da matriz ser diagonal:

# verifica se é diagonal. Elementos fora da diagonal devem ser iguais a zero


diagonal = True
# percorre a matriz até encontrar o primeiro elemento diferente de zero,
# com i != j (fora da diagonal principal)
i = 0 # índice da primeira linha
while diagonal E i < m :
j=0
while diagonal E j < n :
se i != j E A[i][j] != 0
diagonal = False # para os dois comandos while
j=j+1
i=i+1

Já no caso de identificação de matriz identidade ao invés de percorrer toda a matriz,


o algoritmo/programa deveria percorrer apenas a diagonal principal. Com isso, invés de
executar 𝑚² vezes, o comando repetitivo executaria, no máximo, 𝑚 vezes. O comando
repetitivo pode ser interrompido quando for encontrado na diagonal principal um primeiro
valor diferente de 1 e após ter atribuído o valor falso para a variável identidade. A seguir é
exibido o trecho do algoritmo implementando estas ideias:

Se “diagonal”
# verifica se é identidade. Todos elementos da diagonal devem ser iguais a 1
identidade = True
# percorre a diagonal principal (i = j) e para quando achar algum elemento
# diferente de 1
i=0
while identidade and i < m :
se A[i][i] != 1:
identidade = False
i=i+1
Se “identidade”:
Escreva(‘matriz é identidade’)
Senão:
Escreva(‘matriz é diagonal’)

7.2.3. Arranjos e Processamento de Imagens

O processamento digital de imagens vem crescendo muito rapidamente e diversas


aplicações novas têm sido viabilizadas pelo aumento do poder de processamento dos
computadores atuais. Estas aplicações vão desde a manipulação de fotos até o
processamento de imagens em tempo real com aplicação de filtros. Em associação com
técnicas de Inteligência Artificial, as chamadas deep fakes se tornaram muito conhecidas
permitindo manipulação de vídeos e áudios de pessoas famosas, fazendo com que elas
apareçam dando depoimentos que nunca existiram. Mas para quem vê apenas o vídeo
deep fake processado jura que as imagens e o áudio são reais.

157
Introdução à Programação com Python

O princípio básico do processamento digital de imagem é a manipulação de


arranjos. Um vídeo nada mais é do que uma conjunto de imagens estáticas (ou quadros),
que exibidas com uma determinada frequência nos dão a sensação de movimento. Um dos
parâmetros para definir a qualidade de um vídeo é exatamente a taxa de quadros por
segundo exibidas para o usuário. Os sistemas de TV analógicos, PAL e NTSC, utilizam
taxas de 30 e 25 quadros por segundo, respectivamente.

A nova tecnologia de transmissão de vídeos digitais permite alterar ligeiramente a


taxa de quadros sem que haja uma percepção de perda de qualidade por parte do usuário.
A melhoria da qualidade da imagem tem sido obtida através melhorias tecnológicas tais
como HD (High Definition), Full HD (Full High Definition), 4K UHD (Ultra High Definition) e
8K UHD (Ultra High Definition). A cada nova versão o número de pixels da imagem
aumenta. Mas o que é um pixel?

A Figura 7.11 mostra uma imagem de satélite em preto e branco (ou em tons de
cinza), com a ampliação de um pequeno trecho quadrado de 5x5 pixels. Um pixel é um
ponto da imagem, conforme mostrado no detalhe e pode ser visualizado como o
cruzamento de uma linha com uma coluna da imagem. Ou seja, uma imagem é uma matriz
de pontos.

Figura 7.11 - Imagem de satélite

No caso de uma figura monocromática (em tons de cinza) como a da Figura 7.11, a
cor é codificada em um byte (8 bits) e pode assumir 256 (2⁸) valores diferentes, codificando
tons de cinza variando de 0 (preto) a 255 (branco). Os valores mais baixos representam
tons de cinza mais claros e os valores mais altos codificam os valores mais escuros. Assim,
a matriz de pontos destacada na imagem é codificada como uma matriz 5x5 de números
inteiros, como a que aparece também em destaque na Figura 7.11.

Portanto, uma imagem será representada como uma matriz com o número de linhas
igual ao número de linhas da imagem e o número de colunas igual ao número de colunas
da imagem. No caso de uma imagem em tons de cinza, cada elemento da matriz será um
número inteiro no intervalo de 0 a 255. Um algoritmo para escurecer uma foto
monocromática teria que percorrer a matriz e somar um valor constante, tomando o cuidado
de atribuir 255 (valor máximo permitido), toda vez que a soma der valor maior que 255.

158
Introdução à Programação com Python

No caso de uma imagem colorida, a estrutura principal de representação é


exatamente a mesma, ou seja, a figura é uma matriz de pontos (ou pixels). Uma imagem da
tela de computador padrão SVGA possui resolução 1024x768, o que significa uma matriz de
pixels com 1024 linhas por 768 colunas e um total de 786.432 pixels. Cada pixel é
representado em 24 bits (3 bytes) e cada byte representa um componente das cores
primárias: vermelho (Red), verde (Green) e azul (Blue), conforme mostrado na Figura 7.12.
Com 24 bits é possível codificar 16.777.216 (2²⁴) de cores diferentes, que segundo alguns
especialistas é muito mais do que o olho humano é capaz de perceber.

Figura 7.12 - Imagem Digital colorida (padrão RGB)

Além do padrão RGB, outro padrão utilizado é o CYMK (Cian (ciano), Magenta
(magenta), Yellow (amarelo) e blacK (preto)). Porém, este padrão não será tratado aqui. É
importante lembrar que no caso de usar os códigos feitos para o padrão RGB, com uma
figura codificada como CYMK a execução irá gerar um erro na abertura do arquivo..

A codificação RGB usa os 24 bits do pixel, armazenando o componente R


(vermelho) no primeiro byte, o componente G (verde) no segundo byte e o componente B
(azul) no terceiro byte. Em Python é possível ler ou escrever um pixel da imagem e fazendo
a separação dos componentes RGB na operação de escrita e leitura.

Suponha uma imagem armazenada em uma matriz de nome imagem. O comando


abaixo lê o valor de um pixel (um elemento da matriz imagem) da linha i, coluna j e atribui
para cada variável um componente da cor:

r, g, b = imagem[i][j]

O resultado será a variável r recebendo o valor do componente vermelho, a variável


g recebendo o valor do componente verde e a variável b recebendo o valor do componente
azul.

Para atribuir um valor de cor para um pixel na imagem (ou um elemento da matriz
imagem), o comando de atribuição deve ser feito no sentido inverso, atribuindo uma tripla
de valores inteiros para um pixel de uma das posições da matriz. No exemplo abaixo, um
ponto azul está sendo atribuído para um pixel.

159
Introdução à Programação com Python

imagem[0][0] = (0, 0, 255)

Os valores precisam estar entre parênteses e separados por vírgula e o efeito deste
comando será atribuir zero para os componentes vermelho e verde e o valor máximo (255)
para o componente azul. Desta forma, o comando atribui uma cor azul para o ponto no
canto superior esquerdo de uma imagem (primeira linha, primeira coluna). Mas, a alteração
de apenas um ponto na imagem não causa um efeito perceptível para o usuário.

Em geral, manipulação de imagens irá percorrer toda a matriz e aplicar alguma


transformação em todos os pixels, como por exemplo para realçar o tom de verde em
relação aos tons de azul e vermelho. Ou aplicar a transformação em apenas alguns pontos,
como por exemplo, em uma foto da torcida Botafogo transformar apenas os pixels brancos
em pixels vermelhos e dizer que a foto é da torcida do Flamengo. Ou ainda, poderá
percorrer apenas parte a matriz, e aplicar as alterações em apenas alguns pontos, como por
exemplo, na implementação da função de “redução de olhos vermelhos”, onde o usuário
marca a região dos olhos, mas a transformação será apenas nos pixels onde o componente
vermelho seja predominante em relação aos outros dois.

Para o processamento de imagens, usando o processamento matricial é necessário


ter instalado, além da biblioteca numérica numpy (que tem sido usada desde que os
arranjos unidimensionais foram apresentados), a biblioteca gráfica Pillow. Esta biblioteca é
importada com o nome de PIL (import PIL).

Um algoritmo genérico para processamento de imagem pode ser descrito como a


seguir:

largura = obter a largura da imagem


altura = obter a altura da imagem

para i = 0 até altura-1:


para j = 0 até largura-1:
pixel = imagem[i][j]
Alterar valor do pixel
imagem[i][j] = pixel

Observe que o algoritmo está parametrizado em função da altura e da largura da


imagem. Para a implementação em Python, estes valores serão obtidos através de uma
biblioteca de manipulação de imagens, que deverá ser importada no início do código da
mesma forma que tem sido feito com a biblioteca numpy.

Como exemplo de processamento de imagem, suponha um programa que deve


implementar as seguintes tarefas: ler uma imagem digital, exibindo-a na tela; alterar o valor
dos pixels, aumentando o componente verde em 50% e o azul em 30%, e reduzindo o
vermelho em 10%; exibir a imagem resultante.

O programa para implementar a solução do problema dado é mostrado na Figura


7.13. Importante observar que o arquivo que contém as funções descritas na Tabela 7.1,
bem como o arquivo com a imagem a ser processada devem estar no mesmo diretório do
programa fonte (Figura7-13.py).

160
Introdução à Programação com Python

Figura 7.13 - Implementação de um programa para alterar as cores de uma imagem

O arquivo imagens.py importado no início do código mostrado na Figura 7.13


(disponibilizado junto com o roteiro de aulas práticas no servidor do LBI) possui uma
pequena biblioteca com algumas funções de manipulação arquivos de imagens padrão jpg
e png, dentre outros. As funções estão detalhadas na Tabela 7.1.

Tabela 7.1 - Funções do arquivo imagens.py


Nome da função Parâmetro de Tarefa realizada Valor retornado
entrada

Imagem() nome do arquivo lê o arquivo de imagem e matriz de pixels


com a imagem gera matriz de pixels
RGB

altura nenhum informa o número de número de linhas da


linhas da matriz matriz

largura nenhum informa o número de número de colunas da


colunas da matriz matriz

mostrar() nenhum exibe a imagem na tela nenhum


do computador

O resultado da execução do programa é mostrado na Figura 7.14. Note que a janela


do Shell aparece na parte mais baixa da Figura 7.14, mas nenhum resultado foi impresso
pelo programa. O único resultado visível do programa é a execução da função mostrar(),
aplicada duas vezes na matriz im. Na primeira vez foi gerada a imagem mostrada à
esquerda, que é a imagem original. Na segunda execução foi mostrada a imagem da direita,
que foi modificada pelo programa.

Como pode ser observado na cor da pele, a imagem original possui um tom mais
avermelhado, enquanto que a imagem após o processamento ficou mais amarelada. A cor
de fundo também teve uma alteração substancial pelo processamento feito.

161
Introdução à Programação com Python

Figura 7.14 - Resultado da Execução do programa da Figura 7.13 (Fonte: foto do acervo
pessoal de Paula Cerqueira Goulart)

Uma observação final, apenas para ilustrar, mais uma vez, a importância da
indentação do código Python. Suponha que o programador tivesse alinhado o último
comando com o penúltimo - aliás, este é um erro que acontece muito frequentemente nas
aulas práticas. O efeito desse erro seria exibir a imagem a cada pixel alterado. Isso
provocaria uma demora muito grande para o programa terminar, além de poder utilizar toda
a memória do computador, causando uma pane geral.

7.3. Exercícios

1) Faça um programa que leia um arranjo (ou vetor) de 10 elementos e troque todos os
números negativos por 0, em seguida imprima o vetor modificado.

2) Escreva um programa que leia um vetor X de 10 elementos. Crie um vetor Y, com


todos os elementos de X na ordem inversa, ou seja, o último elemento passará a ser
o primeiro, o penúltimo será o segundo e assim por diante. Escrever todo o vetor X e
todo o vetor Y.

162
Introdução à Programação com Python

3) Escreva um programa que leia um vetor X de 10 elementos. Em seguida, crie um


vetor Y da seguinte forma: os elementos de Y com índice par receberão os
respectivos elementos de X divididos por 2; os elementos com índice ímpar
receberão os respectivos elementos de X multiplicados por 3. Escrever o vetor X e o
vetor Y.

4) Faça um programa que leia um vetor W de 10 elementos, depois receba um valor V.


Em seguida, seu programa deve contar e escrever quantas vezes o valor V ocorre
no vetor W e escrever também em que posições (índices) do vetor W o valor V
aparece.

5) Faça um programa que leia um arranjo de tamanho 10 e escreva o valor do maior


elemento desse arranjo e a respectiva posição que ele ocupa no vetor.

6) Refaça o exercício 2 sem usar um vetor auxiliar (vetor Y). A inversão dos elementos
do vetor X deverá ser feita utilizando uma variável escalar.

7) Escreva um programa para ler um vetor SORTEADOS de 6 elementos contendo os


números sorteados da Mega-Sena. A seguir, ler um vetor ESCOLHIDOS de até 15
elementos contendo uma aposta. Uma aposta pode conter de 6 a 15 dezenas. Todos
os valores devem estar entre 1 e 60. O programa deve garantir que as dezenas
sorteadas sejam distintas, pois no mundo real se uma dezena sorteada for repetida,
ela é descartada. O mesmo vale para as dezenas da aposta do usuário. O
programa deve exibir as dezenas “sorteadas”, as dezenas da aposta e escrever
quais números da aposta correspondem a números sorteados e quantos pontos ele
fez.

8) Refaça o programa anterior usando a função random.randint para sortear as 6


dezenas, que deverão ser exibidas somente depois do usuário fazer a sua aposta.
Nesta versão, o programa deverá informar o valor da aposta feita pelo usuário
considerando que a aposta simples (6 dezenas) é de R$ 4,50 (valor em agosto de
2020) e que os valores de outras apostas é dada pelo número de combinações
possíveis, dada pela expressão:
𝑛!
NúmeroDeCombinações = , onde n = número de dezenas do palpite.
6!(𝑛−6)!

9) Escreva um programa para ler um vetor A de 10 elementos e um valor X. Copie para


um vetor S os elementos de A que são maiores que X. Logo após imprima o vetor S.

10) Faça um programa que leia um vetor e ordene, de modo crescente, o vetor.

163
Introdução à Programação com Python

11) Faça um programa gerar um vetor X de 10 elementos com valores aleatórios entre
10 e 90. Na sequência, o programa deverá exibir os valores do vetor, em uma
mesma linha e solicitar que o usuário forneça um valor P (aceitando apenas valores
entre 0 e 9) que representa a posição de um elemento dentro do vetor X. Imprimir o
valor do elemento que ocupa a posição informada. Logo após excluir esse elemento
do vetor, fazendo com que os elementos subsequentes (se houver) sejam
deslocados uma posição para o início e o valor 0 (zero) seja inserido na última
posição do arranjo contendo elemento válido. O programa deverá exibir o arranjo,
após cada eliminação e ser executado até que todos os elementos sejam
eliminados, imprimindo ao final o arranjo contendo apenas valores 0 (zero). A cada
eliminação, a faixa permitida para o valor P deverá ser compatível com as posições
ocupadas por elementos válidos (diferentes de 0).

12) Criptografia (Do Grego kryptós, "escondido", e gráphein, "escrita") é o estudo dos
princípios e técnicas pelas quais a informação pode ser transformada da sua forma
original para outra ilegível, de forma que possa ser conhecida apenas por seu
destinatário, o que a torna difícil de ser lida por alguém não autorizado
(http://pt.wikipedia.org/wiki/Criptografia).
Uma das mais simples e conhecidas técnicas de criptografia é a Cifra de
César. É um tipo de cifra de substituição na qual cada letra do texto é substituída por
outra. Por exemplo, com uma troca de três posições, A seria substituído por D, B se
tornaria E, e assim por diante. O mesmo se pode aplicar a números, por exemplo,
com uma troca de cinco posições, 0 seria 5, 1 seria 6 e assim por diante. A
criptografia também pode ser representada usando aritmética modular. A criptografia
de um número por uma troca posições pode ser descrita matematicamente como:
En(x) = (x + n)%Y

A decriptografia é feita de modo similar:


D(En(x)) = (En(x) - n)%Y = x

onde, Y é o maior valor dos números que se deseja aplicar a Cifra de César e n é o
valor da distância. O resultado deve estar entre 0 e Y, ou seja, se x+n ou x–n não
estiverem no intervalo 0...Y, deve-se subtrair ou adicionar Y. Obviamente, após a
decriptografia, a informação deve ser igual à original.

Faça um programa que leia o valor de n, o valor de Y, o tamanho e o vetor a ser


criptografado e os elementos deste vetor (a). Em seguida, o programa deverá criar
um arranjo b para receber os elementos criptografados e imprimir o vetor
criptografado. Finalmente, o programa deverá criar um vetor c, para receber os
elementos resultantes da decriptografia dos elementos do vetor b. Veja um exemplo
da execução do programa:

164
Introdução à Programação com Python

13) O algoritmo de criptografia do exercício anterior é muito simples e dá para observar


que um número criptografado é sempre igual. Por exemplo, o 2 que aparece 4 vezes
na sequência original é sempre codificado como 6. Uma forma de tornar o algoritmo
um pouquinho mais robusto é usar a distância (n) diferente a cada cifragem e
decifragem dos valores. Uma possibilidade é fazer um incremento modular do valor
n. Implemente esta alteração no programa do exercício anterior. A Figura abaixo
apresenta uma saída onde o valor inicial de n foi 4 (primeiro valor fornecido pelo
usuário) e a cada novo elemento a ser cifrado o valor de n foi incrementado
(modularmente) de 3 unidades. Observe, que nesta implementação, o valor 2 foi
criptografado como 2 (duas vezes), 9 e 5.

14) Implemente um algoritmo de criptografia para uma string (lembre-se que uma string
é um arranjo de caracteres) fornecida pelo usuário, usando o algoritmo do exercício
12 com as devidas adaptações. Para obter o valor decimal correspondente a um
caracter deve ser usada a função ord() e para transformar um valor decimal para
caractere deve ser usada a função chr(). Ambas são funções primitivas da
linguagem Python e não é necessário importar nenhuma biblioteca para usá-las.
Considere o maior valor (Y definido no enunciado do exercício 12) igual a 256,
considerando que os caracteres ASCII variam de 0 a 255. A figura a seguir mostra
um exemplo execução do programa para a distância (número de troca) igual a 3.

OBS: Teste o programa para as entradas da figura acima, pois dependendo do texto
digitado ou da distância (número de troca) coisas estranhas podem acontecer por
causa dos caracteres de controle do ASCII, tais como os já conhecidos “\n” e “\t” ou
como o “/0” que indica fim de uma string.

15) O algoritmo de criptografia do exercício anterior também tem o ponto fraco de gerar
o mesmo caractere cifrado para um dado caractere original. Verifique que a letra “e”
foi sempre cifrada como “h”. Use a mesma ideia do exercício 13 para fazer um
incremento modular do valor n. Implemente esta alteração no programa do exercício
anterior. A Figura abaixo apresenta uma saída onde o valor inicial de n foi 4 (primeiro
valor fornecido pelo usuário) e a cada novo elemento a ser cifrado o valor de n foi
incrementado (modularmente) de 3 unidades. Observe, que nesta implementação, o
valor “e” foi criptografado como “k”, “t”, “}” e “¹”.

165
Introdução à Programação com Python

OBS: idem à do exercício anterior.

16) Faça um programa que leia o número de alunos de uma turma, em seguida leia a
matrícula e a nota de cada aluno. Após, calcule a média aritmética da turma e
imprima matrícula e a nota dos alunos reprovados, de exame final e aprovados.

17) Implemente o programa discutido na seção 7.1.2 permitindo que o usuário defina o
valor de N. O programa deverá executar e, ao final, solicitar novamente um valor de
N para nova execução. Se o usuário fornecer um valor 0 ou negativo, o programa
deve terminar. Observe que dependendo da quantidade de números gerados na
sequência, a forma de exibição da saída na tela pode ajudar (ou atrapalhar) a sua
visualização por parte do usuário do programa. Tente encontrar uma solução
genérica para se ter sempre uma boa visualização da saída.

18) Escreva um programa para criar uma matriz A de dimensões m x n, definidas pelo
usuário, que também deverá informar os valores dos elementos da matriz. Em
seguida, o programa deverá:
- Calcular a média dos valores da matriz;
- Calcular o desvio padrão dos valores da matriz;
- Gerar um arranjo B de dimensão m, contendo na posição i o produto dos
elementos da linha i da matriz A;
- Gerar um arranjo C de dimensão n, contendo na posição j a soma dos
elementos da coluna j da matriz A.
O programa deverá imprimir a matriz no formato de linhas e colunas, ou seja, em
uma mesma linha na tela deverão estar todos e somente os elementos daquela linha
da matriz. Vide exemplo a seguir.

19) Refaça o exercício anterior com a geração dos elementos da matriz A usando
números inteiros e aleatórios na faixa de -10 a + 10.

20) Implemente o programa da seção 7.2.2.2 de forma eficiente, ou seja, o programa


deverá terminar sempre que um primeiro caso quebre a propriedade que está sendo
investigada (diagonal ou identidade).

21) Escreva um programa para somar duas matrizes A e B, armazenando o resultado


em uma terceira matriz C. O usuário deverá informar o número de linhas e de
colunas, além de todos os elementos das duas matrizes. O programa deve verificar

166
Introdução à Programação com Python

se a soma é possível antes de pedir o valor dos elementos ao usuário. Caso a soma
não seja possível, o programa deverá solicitar novamente ao usuário as informações
das dimensões das 2 matrizes. Ao final, o programa deverá imprimir as matrizes A,
B e C.

22) Altere a solução do exercício anterior com a geração dos elementos das matrizes A
e B usando números reais e aleatórios, na faixa entre 0 e 100.

23) Escreva um programa para multiplicar duas matrizes A e B, armazenando o


resultado em uma terceira matriz C. O usuário deverá informar o número de linhas e
de colunas, além de todos os elementos das duas matrizes. O programa deve
verificar se a multiplicação é possível antes de pedir o valor dos elementos ao
usuário. Caso a multiplicação não seja possível, o programa deverá solicitar
novamente ao usuário as informações das dimensões das 2 matrizes. Ao final, o
programa deverá imprimir as matrizes A, B e C.

24) Refaça o exercício anterior com a geração dos elementos das matrizes A e B
usando números reais e aleatórios, na faixa entre 0 e 100.

25) Modifique o exercício anterior com a geração dos elementos das matrizes A e B
usando números inteiros e aleatórios, na faixa entre 0 e 1.

26) Faça um programa para gerar uma matriz de dimensões n x m, com valores
aleatórios na faixa entre 0 e 255. Os valores m e n deverão ser informados pelo
usuário. Após a geração dos elementos da matriz, o usuário deverá selecionar uma
região indicando um número de linha e um número de coluna válidos. O programa
deverá, então, calcular o valor médio dos elementos pertencentes à região
selecionada pelo usuário e atribuir este valor médio para todos os elementos da
região. Os demais elementos devem permanecer inalterados. O programa deve
mostrar a matriz original e a matriz após a alteração dos valores da região.

27) Jogo da Velha - Use uma matriz 3x3 para para implementar um tabuleiro de jogo da
velha. Inicialmente, todas as posições devem ser preenchidas com o valor 0 (zero),
indicando que a posição está vazia. O jogo será jogado por dois jogadores. A
marcação de uma jogada do jogador 1 será feita atribuindo o valor 1 para a posição
definida. Para o jogador 2, uma jogada será feita atribuindo o valor 2. O programa
deverá exibir inicialmente o tabuleiro vazio na tela e implementar a solução para este
problema considerando:
- o jogador 1 será o primeiro a preencher uma posição;
- os jogadores 1 e 2 vão alternar o preenchimento das posições;
- os números de linha e coluna válidos são de 1 a 3, portanto o programa não
deve aceitar valores fora desta faixa;
- uma posição já preenchida não pode ser usada novamente, por nenhum dos
dois jogadores. Caso um jogador cometa este erro, o programa deverá
solicitar uma nova posição (ou jogada) para o mesmo jogador;

167
Introdução à Programação com Python

- a cada jogada válida, o tabuleiro deverá ser exibido na tela;


- a partir da quinta rodada (ou jogada) o programa deverá verificar se aquela
marcação determinou um vencedor. Em caso afirmativo, o programa deverá
terminar informando o número do jogador vencedor;
- se após a nona jogada não houver vencedor, o programa deverá terminar
informando que “Deu velha”, ou seja, houve empate.

28) Modifique o programa implementado do Jogo da Velha para que o jogador 2 seja o
seu programa. A jogada do programa deverá ser feita escolhendo aleatoriamente
uma posição. Caso a posição esteja ocupada, o programa deverá escolher outra e
repetir o teste de posição ocupada (ou não). A marcação só será efetivada quando a
escolha aleatória for de uma posição válida.

29) Altere a implementação do exercício anterior para que a marcação feita pelo
programa não seja mais aleatória. Ela deverá seguir a seguinte estratégia:
- a primeira marcação do programa deverá ser a posição central (2, 2) ou, se
isso não for possível, a posição deverá ser a do canto superior esquerdo (1,
1);
- a segunda marcação deverá ser feita considerando o sucesso do programa
em ocupar a posição central, na primeira marcação. Em caso positivo, o
programa deverá verificar se o jogador 1 tem duas marcações em uma
mesma linha ou em uma mesma coluna, com a terceira posição vazia e, em
caso afirmativo, o programa deverá marcar esta posição vazia. Caso a
primeira marcação do programa não tenha sido a posição central, a diagonal
secundária também deverá ser verificada e a posição vazia deverá ser
marcada, se as outras duas posições já foram preenchidas pelo jogador 1.
Caso não exista possibilidade do jogador 1 ganhar com o terceiro
movimento, o programa deverá marcar uma posição em uma das
extremidades livres;
- da terceira marcação em diante, o programa deverá verificar se existe
alguma marcação que o faça vencedor e, neste caso, escolher esta
marcação. Caso contrário, deverá verificar se existe alguma opção de
marcação para (tentar) impedir a vitória do jogador 1 e fazer esta marcação.

30) Altere a implementação do programa solução do exercício anterior para que o


computador jogue sozinho. O jogador 1 deverá usar a marcação aleatória e o
jogador 2 deverá utilizar a estratégia definida no exercício anterior. Faça a
implementação para que sejam jogadas N partidas e, ao final o programa informe o
número de vitórias de cada jogador e o número de empates.

31) Campo Minado é um popular jogo de computador para um jogador. Foi inventado
por Phil Spencer em 1989 e tem como objectivo revelar um campo de minas sem
que alguma seja detonada (Fonte: https://pt.wikipedia.org/wiki/Campo_minado).
Implemente um programa do jogo Campo Minado considerando um tabuleiro 10x10
e 10 bombas espalhadas aleatoriamente no tabuleiro, pelo programa. Na exibição do
tabuleiro para o usuário do programa devem ser usados os caracteres “X” para
posição ainda não revelada, “-” para posição revelada e não vizinha a nenhuma
bomba, “B” para posição revelada e com bomba (situação em que o jogador perde)

168
Introdução à Programação com Python

e de “1” a “8” para uma posição revelada e que seja vizinha de pelo menos uma
bomba (o caracter deve representar o número de bombas vizinhas àquela posição).
Portanto, o tabuleiro deve ser exibido inicialmente com todas as posições contendo
“X”. Quando o jogador selecionar uma posição, o caractere verdadeiro (“-”, “B” ou o
caractere representando o número de bombas vizinhas) deverá ser exibido. O
programa deverá controlar o número de posiçẽs reveladas. Quando uma posição
selecionada não for vizinha de bombas, o programa deverá exibi-la e todas as
posições adjacentes a ela que também não forem vizinhas de bombas.

Para os exercícios a seguir será necessário usar a diretiva de importação (import


imagens) para incluir as funcionalidades mostradas na tabela 7.1 de abrir um arquivo
de imagem para posterior manipulação como uma matriz de pixels, pelo seu
programa. O arquivo imagens.py pode ser obtido neste endereço: imagens.py.

32) Implemente um programa para transformar uma foto colorida em uma foto em tons
de cinza. Um algoritmo para fazer tal conversão pode ser a de pegar a intensidade
média de cada pixel RGB e atribuir este valor médio para cada componente RGB. A
figura mostrada a seguir apresenta a foto original à esquerda e a imagem
manipulada, à direita. A foto utilizada neste e em outros exercícios a seguir é do
fotógrafo Christian R. Linder, licenciada pela CC BY-SA 3.0, disponível em
https://pt.wikipedia.org/wiki/Agalychnis_callidryas#/media/Ficheiro:Agalychnis_callidr
yas.jpg. Todos os exercícios seguintes utilizam a mesma foto. Mas, você pode
utilizar qualquer outro arquivo de imagem nos formatos jpg ou png.

33) Usando a imagem original e a imagem gerada pelo processamento do programa do


exercício anterior, faça um programa para combinar as duas imagens, gerando uma
terceira imagem. O programa deve perguntar ao usuário, qual o percentual da foto
ele deseja que seja colorida e o sentido da junção: horizontal ou vertical. A parte
colorida ficará sempre na parte superior ou do lado esquerdo. A figura abaixo mostra
o resultado de duas execuções do programa: na primeira o usuário escolheu 35% e
sentido vertical; na segunda execução ele escolheu 60% e horizont. A foto original é
a mesma do exercício anterior.

169
Introdução à Programação com Python

34) Uma matriz transposta de uma matriz A, é aquela em que as linhas de A viram
colunas na matriz transposta. Se a matriz A tiver dimensões m x n, a matriz
transposta de A terá dimensões n x m. Implemente um programa para pegar um
arquivo de imagem (matriz de pixels) e gerar a matriz transposta (ou imagem
transposta). O resultado, se aplicado na foto da nossa foto de perereca, será como o
mostrado a seguir, com a transposta mostrada no lado direio da figura. OBS: a foto
utilizada é quase quadrada. Possui 480x482 pixels.

35) Faça um programa para inverter horizontalmente uma foto, ou seja, o programa
deve trocar os elementos de primeira coluna com os elementos da última coluna,
trocar os elementos da segunda coluna com os da penúltima e, assim,
sucessivamente, até chegar no meio da foto, quando a inversão estará finalizada. O
resultado da execução deverá ser como o mostrado na figura a seguir.

170
Introdução à Programação com Python

36) Faça um programa para inverter verticalmente uma foto, ou seja, o programa deve
trocar os elementos de primeira linha com os elementos da última linha, trocar os
elementos da segunda linha com os da penúltima e, assim, sucessivamente, até
chegar no meio da foto, quando a inversão estará finalizada. O resultado da
execução deverá ser como o mostrado na figura a seguir.

37) Para proteger a privacidade da nossa perereca, que testemunhou um assassinato


na lagoa, você deve fazer um programa para borrar a região do rosto dela. Para
conseguir este efeito, um algoritmo simples é pegar um ponto da imagem e calcular
a média dos componentes RGB de seus vizinhos (direita, esquerda, acima e abaixo)
e usar este valor médio para alterar o valor do próprio pixel e dos próximos 9 pixels
na mesma linha. Este processo deve ser repetido até chegar no “final” da linha.
Lembre-se que este processo deverá ser feito apenas no entorno do rosto da
perereca.

171
Introdução à Programação com Python

38) Para aumentar a segurança da perereca a sua imagem será toda criptografada para
ser transmitida pela Internet, sendo descriptografada na máquina de destino. O
método de criptografia será o de substituição de César. Cada linha da imagem
original será copiada para uma nova imagem usando um valor de chave definida
pelo usuário, com valor entre 0 e 100. Porém, se a mesma chave for utilizada em
todas as linhas não haverá segurança, pois o resultado seria como o mostrado a
seguir:

Para conseguir uma criptografia mais forte uma pequena alteração pode ser feita,
incrementando modularmente o valor da chave de criptografia a cada linha nova a
ser criptografada. O módulo deve ser o número de colunas da matriz ou o número
de pixels em uma linha. O programa deverá gerar uma terceira imagem, a partir da
imagem criptografada que seja igual à imagem original (lembre-se que no destino só
existirá a imagem criptografada. A chave usada na criptografia será informada por
telefone). As imagens a seguir mostram a imagem criptografada (à esquerda) para
uma chave informada pelo usuário igual a 100 e valor do incremento igual à metade
do valor da chave.

172
Introdução à Programação com Python

39) Redução de Olho vermelho é uma técnica comum desde o surgimento das primeiras
máquinas de fotos digitais, que consiste na identificação de pixels na cor vermelha e
que estejam na área dos olhos e a troca por outra cor, dependendo da cor dos olhos.
Sabendo disso, a rã de olhos vermelhos (Agalychnis callidryas) solicitou a sua ajuda
para ter olhos azuis. Faça um programa para implementar uma solução similar à
mostrada a seguir, onde a foto original está à esquerda e a foto modificada à direita.

40) Altere o programa anterior para que possa ser escolhida uma opção entre olho azul
ou olho verde, bem como diferentes tons (intensidades) de uma destas duas cores.
A figura abaixo mostra o resultado da execução para azul com intensidade 150 e
para verde intensidade 255. Dica: não permita a seleção de intensidades abaixo de
80, pois tanto o azul como o verde começam a ficar muito escuros.

173
Introdução à Programação com Python

174
Introdução à Programação com Python

Capítulo 8 - Funções
Neste capítulo será mostrada a importância do uso de funções e a possibilidade de
criação de novas funções por parte do programador. O uso de funções permite uma melhor
organização do código e reutilização de código, com a criação de bibliotecas próprias.

8.1. Motivação

Na seção 6.3.3 foi discutida a solução para o problema de determinar o valor da raiz
quadrada de um número, utilizando o algoritmo proposto por Heron de Alexandria. Na
solução apresentada o trecho de código que executa o cálculo da raiz quadrada era:

epson = 10e-5
r = x/2
r = (r + x/r)/2
while abs(r**2 - x) > epson:
r = (r + x/r)/2

As cinco linhas de código acima podem ser substituídas por um único comando, se
for utilizada a função sqrt() da biblioteca matemática (math). Esta função calcula a raiz
quadrada de um número x passado como parâmetro e retorna o valor calculado. Assim,
uma maneira correta de usar a função sqrt() é em um comando de atribuição, como
mostrado a seguir:

r = math.sqrt( x )

Obviamente, também deveria ser inserida a linha com a importação da biblioteca


matemática (import math) antes de se utilizar a função sqrt(). Note que o código fica muito
mais compacto e o programador precisa apenas de saber a forma correta de utilizar a
função, sem se importar em como ela foi implementada. Afinal de contas, se ela está na
biblioteca de funções matemáticas da linguagem Python, ela deve estar bem implementada.

Alguns outros exemplos de funções da biblioteca math são: log(x) - logaritmo;


log10(x) - logaritmo base 10; exp(x) - exponencial; tan(x) - tangente; sin(x) - seno; cos(x) -
coseno, etc. A biblioteca math possui uma série de funções hiperbólicas, trigonométricas e
logarítimicas para números reais. Existe ainda a biblioteca cmath que implementa funções
para operar com números complexos.

Um dos benefícios do uso de funções é a possibilidade de reuso de código. Quando


aquele trecho de código precisaria ser repetido várias vezes, em um ou mais programas, ele
pode ser definido como uma função. Sempre que esse código for necessário, ele pode ser
substituído pela chamada à função, ou seja, pelo nome da função.

175
Introdução à Programação com Python

8.2. Funções em Python

A linguagem de programação Python permite a criação de novas funções para


serem usadas posteriormente. Detalhando a frase anterior, os passos para a criação e uso
de funções em Python são: declare a função e defina seu código; chame (use) a função em
outras partes do programa.

Antes de criar uma nova função, é importante que o programador tenha em mente a
resposta para 3 questões fundamentais. Qual a tarefa que será executada pela função? Se
forem necessários parâmetros (dados de entrada), quais são esses parâmetros?
Finalmente, se a função retornar valores, quais são esses valores?

As respostas a essas perguntas irão definir como a função será implementada. A


tarefa a ser executada pela função deve estar bem definida e, idealmente, ser apenas uma
única tarefa. A função sqrt() calcula a raiz quadrada de um número. Este número é a
informação que a função precisa receber (parâmetro de entrada) para executar a sua tarefa.
E a função sqrt() retorna um valor de ponto flutuante. O fato da função retornar um valor
obriga que ela seja usada em um comando de atribuição (como no exemplo da seção 8.1)
ou em uma expressão ou em um comando de impressão, pois o valor retornado precisa ser
usado.

A forma geral de definição de uma função na linguagem Python é a mostrada a


seguir:

def nome(<lista de parâmetros>):


comandos
return <lista de valores retornados>

A definição da função é iniciada com a palavra reservada def seguida do nome da


função. O nome pode ser qualquer um escolhido pelo programador, mas deve seguir as
mesmas restrições aplicadas à definição de nomes de variáveis. Mas, é altamente
recomendado que o nome da função ajude a lembrar a tarefa que a função faz. Por
exemplo o nome sqrt() é uma abreviatura de square root (raiz quadrada em inglês).

A lista de parâmetros é corresponde aos dados passados para a função executar a


sua tarefa. Quando existem dois ou mais parâmetros, os nomes devem ser separados por
vírgulas. Existem funções em que a lista de parâmetros pode ser vazia. E existem, ainda,
funções nas quais o número de parâmetros pode ser variável. Por exemplo, a função print()
que está sendo utilizada em quase todos os exemplos de programas. O cabeçalho da
função é terminado com o caractere ‘:’.

176
Introdução à Programação com Python

O corpo da função, representado por comandos na forma geral, corresponde ao


conjunto de comandos para implementar a tarefa da função. Observe a indentação dos
comandos. Eles devem estar deslocados à direita em relação à palavra reservada def. Uma
linha de código alinhada com a palavra reservada def não faz parte da função.

O comando return é obrigatório para as funções que retornam valores. Quando a


função retorna dois ou mais valores, estes valores devem ser separados por vírgulas. Um
return sem lista de valores retornados, indica um ponto de término da execução da função
ou ponto de retorno. Isso significa que a execução da função terminou e a execução
continuará na instrução seguinte à instrução que fez a chamada da função. Uma função
sem o return terá o retorno feito pelo interpretador após executar o último comando da
função.

A utilização da função, conforme visto na apresentação da função sqrt() na seção


8.1 consiste em escrever o nome da função em uma linha de código. Para uma função que
não retorna valores, basta escrever o nome da função como um comando do programa.
Quando a função retorna valor o seu uso deve ser em um comando de atribuição ou em
uma expressão ou em um comando de impressão, pois o valor retornado pela função
substituirá o seu nome na linha de código do programa.

Quando o interpretador Python encontra o nome de uma função, ele procura a


função (palavra reservada def) em que foi usado aquele nome. É por isso que a definição
da função tem que ser feita antes de sua utilização. Ao encontrar a função chamada, o
interpretador passa a executar os comandos daquela função, até que seja encontrado um
return ou após a execução do último comando (quando ela não tem um return).

8.2.1. Identificando candidato a virar função

Uma tarefa importante a ser feita para implementar funções é justamente a


identificação de trechos de código candidatos a virarem função. A característica principal é
que o código implemente uma tarefa que seja comum a vários programas e, eventualmente,
seja usada mais de uma vez no mesmo programa.

Considere um trecho de código para determinar o dia do mês em que foi ou será o
domingo de páscoa, para um período, por exemplo de 1980 a 1991. O algoritmo só funciona
para o intervalo de 1582 a 2499. O trecho de código implementado para obter o perído çe
mostrado a seguir:

ano1 = int( input('Digite o ano inicial (1582 a 2499): '))


while ano1 < 1582 or ano1 > 2499:
ano1 = int( input('Digite o ano inicial (1582 a 2499): '))

print()

177
Introdução à Programação com Python

ano2 = int( input('Digite o ano final (1582 a 2499) : '))


while ano2 < 1582 or ano2 > 2499:
ano2 = int( input('Digite o ano final (1582 a 2499) : '))
...

Observe que os trechos destacados em negrito executam exatamente a mesma


tarefa: lê um número inteiro e verifica se o valor está entre 1582 e 2499. A única diferença é
a mensagem exibida que pede “ano inicial” no primeiro trecho e “ano final” no segundo.
Então, poderia ser implementada uma função para ler um número e fazer este teste, com
um parâmetro que seria a mensagem de texto a ser impressa. A primeira tentativa de criar a
função e usá-la no programa é mostrada a seguir:

def leiaInt(msg):
v = int( input( msg ))
while v < 1582 or v > 2499:
print('Valor deve estar entre 1582 e 2499’)
v = int( input( msg ))
return v

#programa principal
ano1 = leiaInt('Digite o ano inicial (1582 a 2499): ')

print()

ano2 = leiaInt( ‘Digite o ano final (1582 a 2499) : ')


...

Um outro programa feito para ler as notas de uma turma de alunos, também precisa
de executar a tarefa de ler um valor inteiro e testar se o valor se encontra em uma
determinada faixa. Inicialmente, o programa lê a quantidade de alunos e só aceita valores
entre 2 e 50. Depois, o programa lê as notas de cada um do alunos, em um comando
repetitivo, e estas notas devem estar no intervalo de 0 a 100. Finalmente, a média das notas
é calculada, após o comando repetitivo. O programa está mostrado a seguir:

while True:
n = int( input('Entre com a quantidade de alunos: '))
if n < 2 or n > 50:
print('Valor deve estar entre 2 e 50')
else:
break
soma = 0
for i in range(0, n):
while True:
x = int( input('Entre com a nota do próximo aluno: '))
if x < 0 or x > 100:

178
Introdução à Programação com Python

print('Valor deve estar entre 0 e 100')


else:
break
soma = soma + x
media = soma / n
print('Média das notas:', media )

Note que não é possível utilizar a função leiaInt() definida anteriormente porque ela é
específica para testar se o valor está no intervalo 1582 a 2499. Neste último programa é
necessário testar 2 intervalos diferentes. Mas é possível modificar a função leiaInt() para
que ela fique mais genérica, definindo novos parâmetros definindo o valor mínimo e o valor
máximo da faixa de interesse. A segunda versão da função e a sua utilização no segundo
programa são mostrados a seguir:

def leiaInt(msg, vmin, vmax):


v = int( input( msg ))
while v < vmin or v > vmax:
print('Valor deve estar entre %d e %d’ %(vmin, vmax))
v = int( input( msg ))
return v

#programa principal
n = leiaInt('Entre com a quantidade de alunos: ', 2, 50)
soma = 0
for i in range(0, n):
x = leiaInt('Entre com a nota do próximo aluno: ', 0, 100)
soma = soma + x
media = soma / n
print('Média das notas:', media )

A utilização no primeiro exemplo mostrado nesta subseção seria o mostrado a


seguir:

def leiaInt(msg, vmin, vmax):


v = int( input( msg ))
while v < vmin or v > vmax:
print('Valor deve estar entre %d e %d’ %(vmin, vmax))
v = int( input( msg ))
return v

ano1 = leiaInt('Digite o ano inicial (1582 a 2499): ', 1582, 2499)

print()

ano2 = leiaInt( ‘Digite o ano final (1582 a 2499) : ', 1582, 2499)

179
Introdução à Programação com Python

O código da definição da função deve aparecer no início de cada programa, ou se


for implementada como uma função de uma biblioteca, tal biblioteca deverá ser importada
no início do programa. Depois da função ter sido implementada e testada, com a certeza de
que está correta o programador poderá usar o seu código sempre. O que é necessário
saber é: o que a função faz; o que ela precisa receber para executar a sua tarefa; e o que
ela retorna. Ou seja, as mesmas questões que o programador levou em conta para criar a
função.

A documentação de uma função costuma ter estas informações escritas logo após o
cabeçalho e antes do corpo da função. Para esta função, um conjunto de comentários
possíveis seria como o mostrado a seguir, na próxima versão de implementação da função.

Outra observação importante é que o conjunto de comandos que implementa a


função pode ser alterado, sem que isso implique em modificação no programa que utiliza a
função, desde que o cabeçalho da função se mantenha. Ou seja, o nome da função tem
que ser mantido e a lista de parâmetros também. Na verdade é necessário manter o
número de parâmetros e a ordem de aparecimento destes parâmetros na lista. Uma
alteração no nome dos parâmetros também não interfere no uso da função.

Com as alterações no código da função, na versão mostrada a seguir, a utilização


nos programas seria mantida exatamente do mesmo jeito. E, se a implementação desta
função estivesse em uma biblioteca, o usuário da função provavelmente nunca saberia que
ela foi alterada:

def leiaInt(mensagem, lim_inf, lim_sup):


# lê um valor inteiro e testa se está no intervalo [lim_inf, lim_sup]
# mensagem: texto a ser exibido para o usuário
# lim_inf: limite inferior do intervalo
# lim_sup: limite superior do intervalo
# retorna o valor lido
while True:
x = int( input('mensagem: '))
if x < lim_inf or x > lim_sup:
print('Valor deve estar entre %d e %d' %(lim_inf, lim_sup))
else:
return x

O return funcionará de maneira similar ao break para quebrar o loop infinito. Porém,
além de forçar o término do comando repetitivo ele também termina a função. Se fosse
mantido o break na cláusula else, o comando return x deveria ser escrito após o while.

8.2.2. Função que retorna dois (ou mais) parâmetros

180
Introdução à Programação com Python

Às vezes uma função precisa retornar dois ou mais valores. A linguagem Python
resolve este problema de maneira muito simples, bastando informar a lista de valores,
separados por vírgula, em um comando return. O comando de atribuição deverá usar um
número de variáveis à esquerda do operador de atribuição, separadas por vírgula, igual ao
número de valores retornados pela função. A primeira variável receberá o primeiro valor da
lista de valores retornados, a segunda variável receberá o segundo valor, e assim por
diante.

Suponha uma função para ordenar 2 valores. A função precisa receber como
parâmetros os dois valores a ser ordenados, proceder à ordenação e retornar os valores
ordenados. A função ordena(x, y) e seu uso são ilustrados a seguir:

def ordena( x, y ):
if (x <= y):
return x, y
else:
return y, x

# programa principal
a = float( input('Digite um número: '))
b = float( input('Digite outro número: '))
a, b = ordena( a, b ) # chamada da função ordena
print( a, '<=', b )

E quando o número de valores que a função precisa retornar for muito grande, por
exemplo, um arranjo. Este caso será tratado na seção 8.4.

8.3. Escopo de Variáveis

Em um programa escrito com uso de funções aumenta consideravelmente a


probabilidade de aparecerem variáveis com nomes repetidos, principalmente quando se tem
o hábito de utilizar nomes muito genéricos como a, b, i, j, etc. Por isso é importante
conhecer o escopo de uma variável, que nada mais é do que os locais de um programa em
que uma variável é conhecida.

Em Python existe o conceito de variáveis globais que são aquelas compartilhadas


com todas funções do programa. Toda variável definida no programa principal é global. As
variáveis locais são aquelas definidas dentro de uma função. Os parâmetros de uma função
tem o mesmo escopo, ou visibilidade, das variáveis locais da função. Considere o programa
mostrado a seguir:

def f( x, y ):
k = 2*x + y
return k

181
Introdução à Programação com Python

# programa principal
z=2
w=1
print( f( 2*z, w ))

A execução do programa começa com o comando z = 2 e antes da chamada da


função f() existem na memória apenas as variáveis z e w, que são variáveis globais, com os
valores 2 e 1, respectivamente.

Somente quando a função f() é chamada no programa principal, é que o


interpretador Python cria espaço para os parâmetros x e y, que recebem os valores 4 e 1,
que foram os valores passados na chamada da função (2*z, w). Quando o primeiro
comando de f() é executado, o interpretador avalia a expressão e o valor resultante é
guardado na posição que o interpretador acabou de criar para a variável local k. Então, k
receberá o valor 9 e no comando seguinte, o valor de k é retornado para o programa
principal. O valor retornado aparecerá no lugar do nome da função f() no programa principal.
Portanto, será impresso o valor 9 pelo comando print().

As variáveis locais são internas a cada função bem como os seus parâmetros. Eles
só podem ser usados dentro da função. Os parâmetros passados por valor são
independentes das variáveis, expressões etc. que geraram os valores passados para a
função. Considere este segundo exemplo:

def f( x, y ):
z = 2*x + y
return z

# programa principal
z=2
w=1
print( z )
print( f( 2*z, w ))
print( z )

Neste segundo exemplo existe uma variável z definida no programa principal e uma
variável local de mesmo nome z na função f(). A função f() é a mesma do primeiro exemplo
e, como ela recebeu os mesmos valores, ela retornará novamente o valor 9 (segundo valor
impresso). Quando isso acontece, toda referência ao nome z dentro do código da função f()
diz respeito à sua variável local z. Portanto, o comando de atribuição não altera a variável z
do programa principal. A saída gerada pelo programa será:

2
9
2

182
Introdução à Programação com Python

Neste próximo exemplo, uma variável do programa principal (z) é utilizada em uma
expressão da função f(). O programa imprimirá o valor 11, já que se trata da mesma
expressão acrescida de “ + z” e o valor de z é igual a 2.

def f( x, y ):
k = 2*x + y + z
return k

# programa principal
z=2
w=1
print( f( 2*z, w ))

Embora este uso seja permitido, ele não é recomendado. A ideia é que as variáveis
definidas no programa principal sejam utilizadas apenas no programa principal, criando um
escopo local para o programa principal.

Além disso, pode ocorrer uma ambiguidade se um comando de atribuição for feito
para uma variável global dentro da função como mostrado a seguir:

def f( x, y ):
k = 2*x + y + z
z=1
return k

# programa principal
z=2
w=1
print( f( 2*z, w ))

Este código ao ser analisado pelo interpretador Python gerará uma mensagem de
erro, pois será considerado pelo interpretador que a variável z usada na expressão k = 2*x +
y + z é a variável local definida no comando seguinte (z = 1). O interpretador Python está
entendendo que os dois comandos citados anteriormente estão em ordem trocada, que a
variável local z deveria ter sido definida antes de ser usada.

Uma solução para este problema seria dizer explicitamente que a variável z, usada
na função f() usando o comando global, antes de atribuir valor para z:

global z # informa para o interpretador que z é global


z=1

Mas, ao usar esta solução uma atribuição feita para a variável global na função será
refletida na variável global do programa principal. Por exemplo, se houvesse um comando
para imprimir o valor de z no programa principal, após a chamada da funçao f(), o valor
exibido seria 1.

183
Introdução à Programação com Python

8.4. Passagem de arranjos como parâmetro

Na linguagem Python ao passar um arranjo como parâmetro, o programa não faz


uma cópia do arranjo para dentro da variável local no escopo da função, como se faz como
uma variável escalar. Isso seria muito custoso, pois a quantidade de memória alocada pode
ser muito grande, em função da dimensão do arranjo.

Em vez disso, ele só passa o endereço da memória onde esse arranjo está
armazenado. Assim, qualquer alteração feita ao arranjo altera a própria variável passada
como parâmetro, e não uma cópia dessa variável. Considere o pequeno programa mostrado
a seguir:

def dobra( vetor ):


for i in range( 0, len( vetor )):
vetor[i] = vetor[i] * 2

#programa principal
a = numpy.array([4, 3, 2, 1])
print( a )
dobra( a )
print( a )

A execução do programa irá gerar a seguinte saída:

[4 3 2 1]
[8 6 4 2]

Sim. A linguagem Python permite imprimir um arranjo inteiro usando apenas seu
nome. A primeira linha é o resultado do primeiro comando print() que foi usado antes da
função dobra() ter sido chamada. E a segunda linha foi gerada pelo segundo print() e, como
era de se esperar, cada elemento do arranjo teve o seu valor dobrado pela função dobra().

8.5. De volta aos algoritmos

A utilização de funções permite fazer uma melhor organização do código. Por


exemplo, o programa principal poderia se resumir à definição das estruturas de dados
necessárias e chamadas para funções que executarão cada uma das tarefas para resolver
o problema.

Em projetos de software mais complexos, onde o número de funções tende a ser


grande, o trabalho em equipe é favorecido com este tipo de organização do código em

184
Introdução à Programação com Python

funções. O ponto chave é um projeto com a definição precisa dos requisitos de cada função:
a tarefa que ela deve implementar; os parâmetros que devem ser passados para a função;
e os valores que a função deve retornar.

Tendo feito esta definição, equipes diferentes podem trabalhar na elaboração do


código de diferentes subconjuntos do total de funções. Desta forma, o projeto pode ser
implementado em um tempo mais curto. Bom, mas isso é assunto da área de engenharia de
software. Nesta disciplina, a ideia é mostrar como os conceitos de algoritmo podem ser
mapeados na implementação usando funções.

O programa principal pode ser visto como um algoritmo de alto nível, onde cada
comando seria uma chamada para a função que detalhará a execução daquele passo. Para
ilustrar, será utilizado um exemplo já apresentado na seção 7.2.2 no programa que verifica
as propriedades de uma matriz quadrada.

O algoritmo de alto nível que considerava o caso da matriz não ser quadrada era o
seguinte:

m = Leia(‘Número de linhas da matriz: ‘)


n = Leia(‘Número de colunas da matriz: ‘)
A = arranjo(m, n)
“Leia os elementos da matriz”
se m != n:
Escreva(‘A matriz não é quadrada’’)
senão:
“Verifique se a matriz é uma matriz diagonal”
Se “diagonal”
“Verifique se a matriz é uma matriz identidade”
Se “identidade”
Escreva(‘matriz é identidade’)
Senão
Escreva(‘matriz é diagonal’)
Senão:
Escreva(‘matriz não é diagonal’)

E esta pode ser a estrutura utilizada no programa principal do programa. Com a


vantagem de poder economizar algumas variáveis que foram usadas na solução da seção
7.2.2.2. Na solução que será apresentada em seguida, o número de linhas e colunas da
matriz deve estar entre 2 e 100, mas considerando que a entrada de dados será manual, na
execução é recomendável usar um valor pequeno. O programa principal poderia ser escrito
como mostrado na Figura 8.1.

185
Introdução à Programação com Python

Figura 8.1 - Programa principal

Observe que o programa principal utiliza a função leiaInt() que já foi apresentada
neste capítulo (reuso de código). Além dela, precisam ser definidas as seguintes funções:

Nome: leMatriz.
Tarefa: ler os elementos da matriz, solicitando valores ao usuário.
Parâmetros: Matriz (arranjo), número de linhas e número de colunas do arranjo.
Valor retornado: nenhum.

Nome: ehDiagonal.
Tarefa: verificar se a matriz é diagonal (todos os elementos fora da diagonal principal
devem ser iguais a zero).
Parâmetros: Matriz (arranjo), dimensão da matriz*
Valor retornado: Booleano (True se a matriz for diagonal).
(*) só faz sentido testar se a matriz é diagonal quando ela é quadrada (o número de
linhas é igual ao número de colunas). Dimensão é o número de linhas (ou de colunas) da
matriz quadrada.

Nome: ehIdentidade.
Tarefa: verificar se a matriz é identidade (todos os elementos da diagonal principal
são iguais a 1).
Parâmetros: Matriz (arranjo), dimensão do arranjo**.
Valor retornado: Booleano (True se a matriz for identidade).
(**) também só faz sentido testar se a matriz é identidade quando ela é quadrada.
Dimensão é o número de linhas (ou de colunas) da matriz quadrada.

Nome: imprimeMatriz.
Tarefa: imprimir os elementos da matriz, organizados por linha e coluna.
Parâmetros: Matriz (arranjo)***.
Valor retornado: nenhum.

186
Introdução à Programação com Python

(***) nesta função foi definido apenas 1 parâmetro, apenas para mostrar a função
shape da biblioteca numpy, que retorna 2 valores: o número de linhas e o número de
colunas de um arranjo bidimensional.

A implementação das cinco funções usadas pelo programa principal são mostradas
na Figura 8.2.

Figura 8.2 - Implementação das funções

Os comentários inseridos no código da Figura 8.2 foram bem sucintos porque o


detalhamento de cada função já havia sido apresentado no texto. Mas para uma boa
documentação do código isso deveria ser feito.

8.6. Jogo da Velha

O jogo da velha é um jogo de tabuleiro bastante conhecido e na sua versão mais


simples pode ser implementado com um arranjo 3x3. O objetivo do jogo é fazer uma

187
Introdução à Programação com Python

marcação vencedora, que consiste de um jogador conseguir escrever a sua marca em 3


posições consecutivas, em uma mesma linha ou em uma mesma coluna ou em uma mesma
diagonal. Os jogadores fazem marcações de maneira alternada, podendo usar apenas
posições ainda não utilizadas. A Figura 8.3 apresenta três configurações possíveis para um
tabuleiro de Jogo da Velha.

X O X X X O

O X O O X X

X X O O
Figura 8.3 - Representação esquemática de um tabuleiro de Jogo da Velha

À esquerda é mostrado um tabuleiro no início de um jogo, ainda sem nenhuma


marcação. Na parte central da Figura 8.3 tem-se um tabuleiro no qual o jogador com a
marcação ‘X’ venceu o jogo, por ter colocado 3 marcas consecutivas na diagonal
secundária. E do lado direito temos um final em que houve empate. É possível afirmar que o
jogador com a marcação ‘X’ foi o primeiro a jogar, pois ele tem uma marcação feita a mais
do que o jogador com a marcação ‘O’.

Vamos escrever um algoritmo para controlar o andamento de um jogo da velha no


qual o primeiro jogador será o de número 1 e usará a marcação ‘X’. Consequentemente o
jogador da marcação ‘O’ será chamado de jogador 2.

O algoritmo de um jogo poderia ser descrito da seguinte forma:

1. Criar o tabuleiro Tab com todas as posições vazias


2. Imprime o tabuleiro inicial
3. Definir Jogador 1 como primeiro a jogar
4. Inicializar um contador de jogadas
5. Criar uma variável para informar se “alguém venceu”
6. Loop para controlar as jogadas (máximo de 9 jogadas, no caso de empate)
6.1. Jogador da vez faz a sua marcação
6.2. Incrementa o contador de jogadas
6.3. Exibe o tabuleiro atualizado
6.4. Testa se a jogada foi vencedora e atualiza a variável “alguém venceu”
6.5. Se ninguém venceu
6.5.1. troca o jogador e a marcação
7. se alguem_venceu :
Informa o número do jogador vencedor
senão :
Informa que deu Empate

O mapeamento do algoritmo para um programa Python pode ser feito de forma


direta, considerando que os comandos em alto nível serão implementados como funções.

188
Introdução à Programação com Python

Obviamente, que nem sempre se consegue esse mapeamento sai na primeira tentativa,
principalmente com relação a quantos e quais parâmetros serão necessários em cada uma
das funções. A Figura 8.4 mostra o código Python do programa principal da implementação
do Jogo da Velha.

Todas as funções foram implementadas em um outro arquivo de nome auxiliar.py,


que está sendo apelidado de aux no comando de importação, na primeira linha do código.
Assim, todas as funções usadas no arquivo de implementação do Jogo da Velha (programa
principal) devem usar o prefixo aux. antes do nome da função, como aparece na 3a. linha
de código (Tab = aux.inicalizaTabuleiro(l, c)).

Figura 8.4 - Programa Principal do Jogo da Velha

Resta agora detalhar a implementação de cada uma das funções usadas pelo
programa principal e codificadas no arquivo auxiliar.py. Pode ser observado que algumas
funções são bem simples e que, em uma primeira análise, talvez nem demandassem uma
implementação como função. Porém, será detalhado como é possível modificar a
implementação de uma função para tornar o programa mais genérico e funcional, sem a
necessidade de mexer no código do programa principal, desde que o nome da função, o
número e ordem dos parâmetros não sejam alterados.

A Figura 8.5 apresenta algumas das funções implementadas no arquivo auxiliar.py.


A função inicializaTabuleiro(l, c) simplesmente usa a função full da biblioteca numérica

189
Introdução à Programação com Python

numpy. Ao contrário da função empty que não define nenhum valor para um arranjo, a
função full define todos os valores iguais ao valor passado como parâmetro (caractere ‘-’).
Ela retorna o arranjo criado. E, por se tratar de um arranjo, o valor retornado é o endereço
do arranjo criado dentro da função, que continua existindo após a função terminar.

Figura 8.5 - Primeiras funções do arquivo auxiliar.py

A função imprimeTabuleiro(A) nada mais é do que a função que já foi vista aqui para
imprimir os elementos de um arranjo bidimensional no formato visto nos livros de
matemática. Note que como o único parâmetro da função é o nome do arranjo, ela usa a
função shape da biblioteca numpy para descobrir o número de linhas e o número de
colunas do arranjo.

Em seguida, a função inicializaJogo() não tem nenhum parâmetro de entrada e


define que a marcação será o caractere ‘X’ e o número do primeiro jogador será 1. Ou seja,
é uma função que retorna 2 valores. Note que esta função poderia ser modificada para
sortear o número 1 ou 2, usando a função randint() e, dependendo do número sorteado
poderia retornar ‘X’ e 1 ou retornar ‘O’ e 2. Dessa forma, o jogador 2 teria chance de ser o
primeiro a jogar de vez em quando.

A função leiaInt() dispensa apresentações pois já foi vista em mais de uma


oportunidade ao longo deste texto. Note que a leiaInt() não foi usada no programa principal,

190
Introdução à Programação com Python

mas apenas dentro do arquivo auxiliar.py. E, não custa ressaltar, mais uma vez a
importância da reutilização de código (que também ocorreu no caso da imprimeTabuleiro()).

A Figura 8.6 apresenta as outras funções implementadas no arquivo auxiliar.py.

Figura 8.6 - Outras funções implementadas no arquivo auxiliar.py

A função fazMarcação(T) recebe como parâmetro o arranjo bidimensional que


representa o tabuleiro do Jogo da Velha. Ela usa a função leiaInt() para garantir que o valor
inteiro será validado no intervalo 1 a 3, que são os valores válidos para número de linha e
coluna. Porém, mesmo com uma posição válida é necessário testar se a posição escolhida
está vazia. No caso de estar vazia, o loop pseudo infinito é quebrado e os valores de linha e
de coluna escolhidos pelo jogador são retornados pela função. Caso a posição esteja
ocupada, a mensagem de erro será impressa e o jogador terá que escolher novamente uma
nova posição, até que seja escolhida uma posição vazia.

A função vencedor() recebe como parâmetros de entrada o arranjo representando o


tabuleiro, a posição (número de linha e de coluna) da marcação feita e a marcação usada.
O teste verifica se há 3 marcações consecutivas na linha da marcação, na coluna da
marcação e no caso da posição pertencer à uma das diagonais (ou às duas - caso da linha
2 coluna 2 - para o jogador) a diagonal (ou as diagonais) será(ão) verificada(s).

Finalmente, a função trocaJogador(j) recebe como parâmetro de entrada o número


do jogador que fez a última marcação e faz a troca do número do jogador e da marcação
usada, retornando estes dois valores.

191
Introdução à Programação com Python

Em algumas situações pode haver o encapsulamento ou aninhamento de uma


função dentro de outra função. É o caso da função leiaInt() que no caso deste programa do
jogo da velha só é utilizada pela função fazMarcacao(). Isso mudaria o escopo da função
leiaInt() que, ao ser definida dentro da função fazMarcacao(), passaria a ser visível apenas
dentro desta função. A Figura 8.7 mostra como ficaria o código com leiaInt() encapsulada
dentro de fazMarcacao().

Figura 8.7 - Mudança de escopo da função leiaInt()

Do ponto de vista de considerar o arquivo auxiliar.py como uma biblioteca genérica


que pudesse ser utilizada em outros projeto, o tornaria mais restrito. Para o programa do
Jogo da Velha não faz diferença e o programa continuaria funcionando normalmente.

8.6. Exercícios

1) Implemente uma função que receba 2 números e retorne o maior. Mostre como usar
a função definida no programa principal.

2) Implemente uma função para o cálculo do fatorial de um número inteiro. A função


não precisa testar se o valor é válido e deve retornar o fatorial do número passado
como parâmetro.

3) Mostre como utilizar a função leiaInt() apresentada neste capítulo, para garantir que
o programa principal passará somente valores válidos quando a função do exercício
2 for chamada.

192
Introdução à Programação com Python

4) Palíndromo é uma sequência de caracteres que lida de trás para frente ou na


sequência correta, apresenta a mesma ordem de caracteres. Ex: ANA, 123321,
SOCORRAMESUBINOONIBUSEMMARROCOS, etc. Implemente uma função que
receba um arranjo de caracteres e informe se trata-se de um palíndromo ou não.

5) Implemente uma função que receba um arranjo de números inteiros e faça a


ordenação dos elementos do arranjo em ordem crescente (ou não decrescente, caso
haja valores iguais).

6) Modifique a função do exercício anterior para que a função possa colocar os valores
em ordem crescente ou decrescente. A função deverá receber um valor booleano
como parâmetro e, se o valor for verdadeiro, a ordenação deverá ser crescente.
Caso contrário, a ordenaç!ão deverá ser decrescente.

7) Refaça o exercício 12 do capítulo 7 utilizando funções, de forma que o programa


principal seja organizado com as funções: leiaInt() para ler os valores de n e Y (deve
ser chamada 2 vezes); uma função para criar o vetor A e ler seus valores; uma
função para criar e criptografar o vetor B; uma função para criar o vetor C que
receberá os elementos de B descriptografados por esta função; uma função
exibeVetor() que receberá como parâmetro o nome de um vetor e o exibirá na tela.

8) Reescreva o programa da Figura 7.8 utilizando funções. O programa principal


deverá ter a estrutura similar ao algoritmo apresentado (e reproduzido a seguir).
Cada linha no programa principal deve executar uma tarefa ou chamar uma função
para implementar a tarefa definida naquela linha do algoritmo. Ou seja, o número de
linhas de código do programa principal não deve ser maior do que o número de
linhas do algoritmo.

m = Leia(‘Número de linhas da matriz: ‘)


n = Leia(‘Número de colunas da matriz: ‘)
A = arranjo(m, n)
“Leia os elementos da matriz”
x = Leia(‘Entre com o valor a ser pesquisado”)
“Pesquise x na matriz e informe a posição quando encontrar”
Se “não achou”
Escreva(‘x não está presente na matriz’)

9) De maneira similar ao que foi feito no exercício anterior, implemente uma solução
para o código apresentado na Figura 7.10 utilizando as mesmas funções, quando
possível, e a implementação da novas funções para determinar se a matriz é
diagonal e para determinar se a matriz é diagonal. A lógica do programa principal
pode seguir a mesma estrutura do programa da figura 7.10

10) Reescreva o programa do exercício 8, do capítulo 7, usando diferentes funções para


realizar cada uma das tarefas (sorteio das dezenas, leitura do palpite, etc.).
Lembre-se que o referido exercício é uma complementação do exercício 7 do
mesmo capítulo 7.

193
Introdução à Programação com Python

11) Reescreva o código da solução do exercício 19 do capítulo 7 usando uma função


leiaLC() que usará a função leiaInt() para solicitar ao usuário o número de linhas e o
número de colunas da matriz. A função leiaLC() deverá retornar dois valores
referentes ao número de linhas e ao número de colunas da matriz, nesta ordem. O
programa deverá implementar ainda uma função para gerar os números aleatórios
para os valores da matriz e uma função para implementar cada uma das tarefas
especificadas: calcular a média dos valores da matriz; calcular o desvio padrão dos
valores da matriz; gerar um arranjo B de dimensão m, contendo na posição i o
produto dos elementos da linha i da matriz A; gerar um arranjo C de dimensão n,
contendo na posição j a soma dos elementos da coluna j da matriz A; fazer a
impressão da matriz; e fazer a impressão de um arranjo (a mesma função deve ser
usada 2 vezes para imprimir os arranjos B e C.

12) Escreva um programa para implementar as tarefas feitas nos exercícios 21 a 25 do


capítulo 7 usando funções. Cada uma das tarefas deverá ser implementada em uma
função. O programa principal deverá, inicialmente, solicitar ao usuário o tipo de
matriz que ele pretende utilizar. Menu 1:
1. Matriz de números inteiros
2. Matriz de números reais
3. Matriz de números binários
4. Sair do programa.
O menu 1 deverá ser exibido por uma função que retornará o número da opção
escolhida para o programa principal. De acordo com a resposta do usuário a matriz
deverá ser criada pelo programa (usando uma função). Na sequência uma outra
função exibirá um outro menu para o usuário informar que tipo de geração dos
elementos ele deseja. Menu 2:
1. Geração de Valores aleatórios
2. Entrada manual dos valores
3. Modificar o tipo de dados das matrizes
4. Sair do Programa
O programa poderá voltar para o primeiro menu 1 (opção 3), ou então, deverá
prosseguir com a geração dos elementos e depois perguntar que tipo de operação
ele deseja realizar, através de outra função. Menu 3:
1. Soma das matrizes
2. Multiplicação das matrizes
3. Entrar com outras valores para matrizes de mesmas dimensões.
4. Modificar o tipo de dados das matrizes
5. Sair do Programa
Após selecionar a operação desejada o programa deverá chamar a função
correspondente que a executa. A opção 3 corresponde a voltar ao menu 2. No caso
da seleção das opções 1 ou 2 do menu 3, o programa deverá exibir novamente o
menu 3.

13) Implemente um programa para juntar todas as operações de processamento de


imagem feito nos exercícios 21 a 25 do capítulo 7. O programa deverá solicitar o
nome do arquivo com a foto a ser processada. Após abrir o arquivo com sucesso, o
programa deverá exibir o seguinte menu de opções de processamento da imagem,

194
Introdução à Programação com Python

uma opção para trocar o arquivo de foto e uma opção para encerrar a execução do
programa.
1. Definir o arquivo com a foto a ser processada
2. Transformar em tons de cinza
3. Gerar imagem transposta
4. Inverter na horizontal
5. Inverter na vertical
6. Borrar uma região da imagem
7. Criptografar a imagem
8. Descriptografar uma imagem já criptografada
9. Redução de olho vermelho
10. Sair do programa

Cada operação deverá ser implementada em uma função diferente. Eventualmente,


no caso de uma função implementar parte da tarefa de outra função, ele deverá ser
usada por esta outra função. As funções para implementar as opções 6 e 9 do menu
devem solicitar ao usuário a região retangular (linha inicial, linha final, coluna inicial e
coluna final). Dica: utilize valores percentuais ao invés do número da linha e coluna.
Ex: inha inicial = 0, linha final = 50, coluna inicial = 0, coluna final = 10, pegaria uma
região no canto superior esquerdo da imagem com largura igual a 10% do tamanho
da imagem e altura de 50% do tamanho da imagem.

195

Você também pode gostar