capÍtulo 3 variáveis - eu-ireland-custom-media … · capÍtulo 4 repetição de comandos um...

12
CAPÍTULO 3 Variáveis Neste capítulo apresentaremos um dos conceitos mais fundamentais em programação que é o conceito de variável. Veremos como atribuir valores a variáveis, tanto na forma de expressões nu- méricas em programas como também através de entrada direta do usuário pelo teclado do com- putador. Neste capítulo também aprofundaremos um pouco mais os conceitos de precedência de operadores e apresentaremos novos comandos. 3.1 Significado de uma variável Quando Charles Babbage (Inglaterra, 1791-1871) concebeu o primeiro computador durante a primeira metade do século XIX, ele já criou o conceito de variável em computação. Só que, muito diferentemente dos computadores de hoje, a máquina de Babbage era totalmente mecânica, ba- seada em engrenagens, e suas variáveis eram componentes físicos, formados por torres de discos, cada disco com algarismos de 0 a 9 escritos nele. Essas torres de discos formariam assim, núme- ros com 40 dígitos cada. A Figura 3-1. mostra um detalhe de três torres numéricas para a máqui- na diferencial, que precedeu o projeto da máquina analítica, considerada o primeiro computador, ambas projetadas por Babbage. Figura 3-1: Parte da máquina diferencial de Babbage. 1 1 By Woodcut after a drawing by Benjamin Herschel Babbage – Google books, Public Domain, https://commons.wikimedia. org/w/index.php?curid=25778944

Upload: hadieu

Post on 24-Sep-2018

238 views

Category:

Documents


0 download

TRANSCRIPT

CAPÍTULO 3

Variáveis

Neste capítulo apresentaremos um dos conceitos mais fundamentais em programação que é o conceito de variável. Veremos como atribuir valores a variáveis, tanto na forma de expressões nu-méricas em programas como também através de entrada direta do usuário pelo teclado do com-putador. Neste capítulo também aprofundaremos um pouco mais os conceitos de precedência de operadores e apresentaremos novos comandos.

3.1 Significado de uma variável

Quando Charles Babbage (Inglaterra, 1791-1871) concebeu o primeiro computador durante a primeira metade do século XIX, ele já criou o conceito de variável em computação. Só que, muito diferentemente dos computadores de hoje, a máquina de Babbage era totalmente mecânica, ba-seada em engrenagens, e suas variáveis eram componentes físicos, formados por torres de discos, cada disco com algarismos de 0 a 9 escritos nele. Essas torres de discos formariam assim, núme-ros com 40 dígitos cada. A Figura 3-1. mostra um detalhe de três torres numéricas para a máqui-na diferencial, que precedeu o projeto da máquina analítica, considerada o primeiro computador, ambas projetadas por Babbage.

Fi gura 3-1: Parte da máquina diferencial de Babbage.1

1 By Woodcut after a drawing by Benjamin Herschel Babbage – Google books, Public Domain, https://commons.wikimedia.org/w/index.php?curid=25778944

CAPÍTULO 4

Repetição de Comandos um Número Fixo de Vezes

Neste capítulo vamos aprender a escrever programas nos quais um ou mais comandos são repe-tidos um número fixo de vezes. Com isso já seremos capazes, entre outras coisas, de calcular fa-toriais, somatórios, médias, além de progressões aritméticas e não aritméticas. Também seremos capazes de programar simuladores de relógios digitais e calendários e resolveremos um antigo pro-blema relacionado ao jogo de xadrez. A possibilidade de repetir comandos inúmeras vezes é o que torna os computadores tão úteis para nós: cálculos que humanos levariam anos para realizar, os computadores conseguem fazer em um piscar de olhos.

4.1 Fundamentos: Contagem simples e variável de iteração

Você provavelmente já ouviu falar que os computadores fazem o nosso trabalho repetitivo. Isso é a mais absoluta verdade. Se você disser para um ser humano escrever um milhão de vezes uma de-terminada frase, ele não vai querer fazer (não vai nem começar, se for esperto), mas se você instruir o computador para escrever uma frase um milhão de vezes, ele fará isso para você, sem discutir.

Embora o conceito de repetição de sequências de comandos em um computador tenha sido inicialmente idealizado e descrito por Ada Lovelace em 1842, ele foi implementado pela primei-ra vez em 1944 no computador Harvard Mark I, também conhecido como IBM ASCC, um dos primeiros a ser construído no mundo. Esse computador lia seus programas em uma fita de papel perfurado mostrada na Figura 4-1.

Fi gura 4-1: Detalhe da fita perfurada do Harvard Mark I ou IBM ASCC.1

1 By Arnold Reinhold – Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=34872964

CAPÍTULO 5

Comandos de Seleção

Neste capítulo veremos como usar estruturas de seleção para fazer o computador tomar decisões sobre qual caminho seguir em um programa. A partir de agora, além dos operadores aritméticos, que já vimos, veremos também operadores lógicos, que são usados para escrever expressões em ló-gica que permitem ao computador tomar decisões sobre quais comandos executar em quais situa-ções. Veremos aqui como comparar dois valores numéricos para verificar se são iguais ou se um é maior do que outro. Veremos também como utilizar variáveis booleanas para ajudar a tomar de-cisões em programas.

5.1 Fundamentos: Decisão e condição

Até aqui vimos como fazer um programa repetir uma sequência de comandos variando alguns as-pectos associados a variáveis. Outra estrutura importante e necessária quando se escreve progra-mas é a estrutura de seleção. Uma estrutura de seleção é baseada em uma decisão que consiste em dizer ao computador, através de comandos específicos, que se uma determinada condição for ver-dadeira ele deve fazer uma coisa, senão deve fazer outra coisa.

Considere o exemplo em que um número, correspondendo à idade de uma pessoa é digitado pelo usuário. O computador não sabe, a priori, que número é este, mas podemos programar uma decisão para fazer coisas diferentes conforme o seu valor. Vamos fazer o seguinte: se o número di-gitado for maior ou igual a 18 vamos imprimir “maior de idade”. Se o número for menor do que 18 vamos imprimir “menor de idade”. O comando de seleção é representado pela estrutura “if--else”. A seguir apresentamos um programa que implementa o exemplo citado:

x = int(input('Idade:'))if x >= 18: print('maior de idade')else: print('menor de idade')

Agora teste o programa pelo menos duas vezes: uma com um número maior ou igual a 18 e outra com um número menor do que 18. Veja o resultado. Parece que o computador ficou inte-ligente, não? Mas é só o seu programa sendo executado.

A estrutura de seleção mostrada tem três partes:

a) A condição, no caso, x >= 18, que aparece logo após o “if ”, a qual é testada pelo programa para verificar se é verdadeira ou falsa.

b) O comando que é executado se a condição for verdadeira, o qual aparece endentado logo após a linha que contém o comando “if ”.

c) O comando que é executado se a condição for falsa, o qual aparece endentado logo após a linha que contém o comando “else”.

Note que a estrutura “if-else” consiste em um comando composto. O “else” só pode existir se houver imediatamente antes, na mesma coluna de endentação, um “if ”.

Similarmente à estrutura “for”, o “if ” e o “else” aceitam vários comandos subordinados, o que deve ser definido com o uso da endentação.

CAPÍTULO 6

Repetição Condicionada

Neste capítulo veremos como trabalhar com estruturas de repetição nas quais não sabemos, a priori, quantas vezes deve haver a repetição: é o caso de problemas nos quais a repetição deve ser feita apenas enquanto uma determinada condição for verdadeira. Isso diferencia esses problemas daqueles que resolvemos usando a estrutura “for” porque quando se usa um “for”, a princípio, o número de repetições já está previamente definido.

6.1 Fundamentos

No Capítulo 4 foi visto que um programa pode executar um comando ou lista de comandos um determinado número de vezes. Foi mostrado também que o número de repetições pode tanto ser uma constante como 10, 50 ou 10000, como um valor previamente desconhecido, como “x”, que é lido pelo teclado ou obtido a partir de cálculos, e usado para delimitar o final da repetição.

Mas, em todos os casos, o número de repetições é determinado antes da estrutura de repetição iniciar. Então, se você quiser fazer um programa que lerá “n” números e calcular a média deles, a primeira coisa que precisa fazer é informar o valor de “n”, ou seja, quantos são os números que vão ser lidos. Por isso que nos exercícios dos capítulos anteriores os enunciados eram do tipo “faça um programa que leia 10 números”.

Existem situações, porém, em que não sabemos, a priori, quantas repetições serão necessárias até que o processo repetitivo esteja acontecendo. Imagine, por exemplo, que você foi sorteado e ganhou 1000 reais para gastar no supermercado local. Você pode comprar 1000 reais em produ-tos. Mas você não sabe quantos produtos poderá comprar a princípio. O que você vai saber é que, depois de cada produto comprado, resta um saldo que você pode gastar. Assim, se você de cara já pegar um produto de 1000 reais, será só isso. Mas se você começar com um produto de 10 reais, ainda terá um saldo de 990 reais para outros produtos. Assim, a lógica para essa compra é ir com-prando enquanto houver saldo:

enquanto ainda existe saldo para gastar: compre algum produto que não custe mais do que o saldo

Pressupõe-se então que a repetição do comando deverá ocorrer enquanto a condição “existe saldo para gastar” for verdadeira. Depois de comprar um produto que custe exatamente o valor do saldo, a condição se torna falsa e, assim, o comando deixa de ser executado.

Essa estrutura, em Python, é realizada pelo comando “while”, que é a tradução para o inglês da expressão “enquanto”. A estrutura “while” tem a seguinte forma geral:

while condição: comandos

Os comandos subordinados à estrutura “while” serão repetidos enquanto a condição booleana indicada for verdadeira. Cada vez que os comandos forem executados a condição estabelecida no “while” é testada novamente. Quando a condição se tornar falsa os comandos deixam de ser repe-tidos. Por exemplo, o programa a seguir terá o comando de divisão inteira e o comando “print” repetidos até que o valor da variável “x” se torne zero:

x = int(input('Digite um número:'))while x > 0: x //= 2 print(x)

CAPÍTULO 7

Funções

Neste capítulo veremos como usar funções predefinidas e bibliotecas de funções em Python. Além dis-so, veremos como criar novas funções e bibliotecas que podem ser usadas em nossos programas. Fun-ções são importantes porque permitem que os programadores abstraiam certas sequências de coman-dos que são utilizadas com muita frequência. Uma função consiste em um nome que é dado a uma sequência de comandos de forma que, quando os programas correspondentes necessitem dela, basta chamá-la pelo seu nome em vez de se ter que programá-la totalmente do início ou copiar seu código. O capítulo também discute alguns tópicos importantes em programação como escopo de variáveis, re-cursividade e otimização de código.

7.1 Fundamentos

Uma importante forma de abstração em programação de computadores é o uso de funções. As funções em linguagens de programação são inspiradas e parecidas com as funções matemáticas. Cada função tem um nome e um conjunto de argumentos.

Assim como as funções matemáticas, as funções em computação também representam um cál-culo que é feito sobre valores passados como argumento. Quando em uma expressão matemática você escreve sen(π), isso significa que a função “sen” (seno), retorna um valor que corresponde ao seno do número π, passado como argumento. Considerando que π é um número igual a 3.14159..., seu seno, por definição é zero. Assim, matematicamente dizemos que sen(π) é igual a 0; mas em computação, como estamos lidando com máquinas que executam comandos, diríamos talvez que a função sen(π) produz ou retorna o valor 0. Isso é assim porque a função matemática é puramen-te abstrata, enquanto a função em programação é a descrição de um procedimento, ou seja, uma sequência de comandos que usualmente calcula um valor a partir dos argumentos.

Funções podem ser usadas em programação para realizar uma computação predefinida, como por exemplo, executar um cálculo sobre certos números passados como argumentos. Vamos con-siderar, por exemplo, a fórmula matemática para calcular arranjos. Imagine que em uma turma com 20 alunos haverá uma eleição para presidente e vice-presidente de turma. Queremos saber quantas diferentes chapas é possível formar com essa turma. A situação aqui corresponde a um

arranjo de 20 elementos tomados 2 a 2. Segundo os livros de matemática, esse valor pode ser cal-

culado da seguinte forma: , onde n é o número de alunos na turma e p o número de alu-

nos na chapa. No caso, teremos que calcular .

Com o que aprendeu até aqui, você já seria capaz de fazer um programa para calcular arranjos, pois já sabe como escrever um programa para calcular um fatorial. Assim, bastaria fazer o progra-ma ler os valores de “n” e de “p” e em seguida, calcular o fatorial de “n”, e depois calcular o fatorial de “n” menos “p”. No final, bastaria dividir os dois valores.

Se não existisse o conceito de “função” em programação, você teria que escrever o programa que faz o cálculo do fatorial duas vezes no seu código: a primeira vez para calcular o fatorial de “n” e uma segunda vez para calcular o fatorial de “n” menos “p”, como no programa a seguir:

print('Cálculo de arranjos A(n, p)')n = int(input('Quantos elementos no total (n)?'))

CAPÍTULO 8

Desenvolvimento Dirigido

por Teste

Neste capítulo apresentamos noções de tratamento de exceções e TDD (Test-Driven Develop-ment), ou Desenvolvimento Dirigido por Teste, que é uma boa prática de programação especial-mente para o desenvolvimento de funções. Com esta técnica, o programador vai primeiro pensar nos resultados da função antes de começar a programá-la. Desta forma, erros são evitados bem cedo e se adquire uma maior segurança de que programas modificados a qualquer momento con-tinuarão funcionando. São apresentadas também as técnicas de classe de equivalência e análise de valor limítrofe, que ajudam a decidir quais valores de argumentos devem ser usados para testar uma função.

8.1 Tratamento de exceções

Nos capítulos anteriores nós propositalmente consideramos que o usuário dos nossos programas seria bem-comportado, isto é, ele não iria, por exemplo, digitar uma letra quando nosso programa estivesse esperando um número. Se ele fizesse isso, o programa iria parar com uma mensagem de erro.

Porém, chegou a hora de começarmos a pensar em fazer programas mais amigáveis. Um pro-grama é considerado amigável se ele responder aos erros do usuário de forma controlada. Por exemplo, em vez de terminar abruptamente a execução do programa com uma mensagem de erro, o programa poderia, caso o usuário digitasse uma letra no lugar de um número, exibir uma mensagem avisando que o valor que ele digitou é inválido e solicitando que ele o digite novamen-te. Um possível diálogo entre um usuário e o programa poderia acontecer mais ou menos assim:Digite um número: abcIsso não é um número válido!Digite um número: 23aIsso não é um número válido!Digite um número: *Isso não é um número válido!Digite um número: 123Ok!

Vamos então definir uma função de entrada de números inteiros que tem esse comportamen-to. A ideia é que ao invés de escrever x = int(input('Mensagem:')), que é um comando que pode fazer o programa parar, caso algo diferente de um número inteiro seja digitado, vamos escrever algo como x = ler_int('Mensagem:', 'Mensagem de erro!').

Essa função, “ler_int” vai exibir a mensagem passada como primeiro argumento ao usuário e aguardar que ele digite um número inteiro. Se ele digitar um número inteiro, a função retorna esse número e, no exemplo, o atribui a “x”. Mas se o usuário digitar um valor inválido, a função vai exibir a mensagem de erro passada como segundo argumento e solicitar novamente que o usuá-rio digite um número, exibindo novamente a primeira mensagem.

Essa função precisa então, dada a sua definição, de uma estrutura do tipo “while” que repita o co-mando de entrada de dados enquanto não tiver obtido um número válido. Somente depois que o usuário digitar um número inteiro válido a repetição deste “while” poderá cessar.

Nossa proposta é implementar esse comportamento usando um comando “while” que só é in-terrompido pelo “return” se um número inteiro válido for digitado. A estrutura da função seria, então, mais ou menos assim:

CAPÍTULO 9

Estruturas de Dados Primitivas

em Python

Neste capítulo veremos como utilizar as principais estruturas de dados que Python fornece como primitivas da linguagem, isto é, estruturas às quais você tem acesso sem precisar importar biblio-tecas ou definir por conta própria. Estas estruturas são: as listas, tuplas e dicionários. Estruturas de dados podem ser usadas para resolver com mais facilidade novos tipos de problemas que seriam extremamente difíceis se contássemos apenas com variáveis simples. Veremos vários tipos de ope-rações com listas, tuplas e dicionários. No capítulo seguinte, para complementar, veremos outras estruturas derivadas que podem ser concebidas a partir dessas primitivas.

9.1 Listas

Até aqui, vimos o conceito de variável e as principais estruturas de controle de fluxo de execução de programas: seleção e repetição. Porém, ainda existem problemas muito simples que não po-dem ser adequadamente resolvidos apenas com essas estruturas. Nas próximas subseções, veremos exemplos desse tipo de problemas e ferramentas para resolvê-los.

9.1.1 Fundamentos: Iteração simples em listas

Considere o seguinte problema: ler uma lista de números e depois imprimir esta lista na ordem inversa à que foi lida. Por exemplo, suponhamos que foram lidos cinco números, 23, 45, 19, 922 e 50, nesta ordem. O programa deveria imprimir a sequência: 50, 922, 19, 45 e 23. Como resol-ver este problema com os conceitos que vimos até agora?

Uma solução simplista consistiria em usar 5 variáveis. O programa poderia ser feito assim:

a = input("a:")b = input("b:")c = input("c:")d = input("d:")e = input("e:")print(e, d, c, b, a)

Você consegue pensar em outra forma de resolver este problema com as estruturas vistas até agora? Possivelmente serão variantes da mostrada anteriormente. Essa solução é desajeitada por-que até funciona bem para uma lista de 5 números. Mas, e se fossem 500? E se fossem, 500 mil números? Nestes casos precisaríamos de alguma outra forma de programação.

Bem, uma outra estrutura então que pode nos ajudar a resolver esse problema é a lista ou “list” de Python que já vimos brevemente em capítulos anteriores. Quando uma variável contém uma lista, então ela contém não apenas um número ou string, mas toda uma sequência de números, strings ou outros tipos de elementos, inclusive outras listas.

Uma lista pode ser criada simplesmente com uma sequência de valores entre colchetes e sepa-rados por vírgulas. Já vimos, no Capítulo 4 um pequeno exemplo com uma lista:

for i in [1, 2, 3, 4]: print(i)

Também podemos ter listas que contenham objetos heterogêneos, ou seja, de tipos diferentes, e podemos atribuir essas listas a variáveis, conforme mostrado a seguir:

minha_lista = [4, 5, 3.8, 'texto']

CAPÍTULO 10

Estruturas de Dados Derivadas

Neste capítulo veremos que podemos, a partir das estruturas de dados de Python, trabalhar com diferentes disciplinas de programação, interpretando essas estruturas primitivas como estruturas derivadas com comportamento especial. No caso, mostraremos como trabalhar com listas como se fossem pilhas ou filas e também como usar listas ou dicionários para lidar com problemas que exigem tabelas ou matrizes.1

10.1 Pilhas

Pilhas e filas são duas formas bem-comportadas de usar listas. Há muitas situações em compu-tação nas quais elas podem ser muito úteis, o gerenciamento da memória do computador é uma delas. Outro exemplo é exatamente o primeiro que apresentamos no capítulo anterior onde que-ríamos inverter as posições dos valores em uma lista. Aquela lista na qual inserimos os elementos no início para depois retirá-los também a partir do início se comportou como uma pilha.

Pilhas também são conhecidas como estruturas LIFO (Last In First Out), ou seja, o último a entrar é o primeiro a sair. Assim, pode-se fazer a famosa analogia com uma pilha de pratos na qual um novo prato sempre é colocado sobre os demais e se um prato for retirado da pilha será sempre o do topo em primeiro lugar.

A pilha em Python, então, pode ser representada por uma lista normal. Para evitar que os ele-mentos fiquem trocando de posição a cada movimentação, como no caso da pilha de números do exemplo do capítulo anterior, não vamos adicionar e retirar os elementos do início da lista, mas do seu final. Assim, enquanto novos elementos são adicionados e posteriormente retirados, os elementos que não são afetados pela operação de inserção ou remoção ficam com suas posições inalteradas. Nós então nos comprometemos a alterar seus valores com somente duas mensagens:

"append" que, como já vimos, adiciona um elemento ao final da lista, que corresponde ao topo da pilha. Dizemos que o "append" então "empilha"."pop", uma mensagem que remove um elemento do final da lista, que corresponde ao topo da pilha. Assim, se o "append" empilha, o "pop" desempilha. Além de remover o elemento da lis-ta, a mensagem "pop", como já vimos, também retorna esse elemento.

A função “pop”, por default, remove o elemento do final da lista. Mas, como já vimos, ela tam-bém pode ser usada com um parâmetro inteiro. Com essa opção o “pop” pode ser usado para re-mover qualquer elemento de uma lista. Por exemplo, [3, 5, 4, 8].pop() retorna o 8 e o remove da lista, que fica [3, 5, 4]. Já [3, 5, 4, 8].pop(1) retorna o 5 (elemento na posição 1), e o retira da lis-ta, que fica [3, 4, 8]. Se queremos que a estrutura se comporte como pilha, então devemos usar apenas o “pop” sem parâmetros.

Vamos exemplificar o uso de pilhas desenvolvendo um jogo de cartas. O jogo em questão se chama “batalha” e cada jogador recebe uma pilha de cartas correspondendo à metade do baralho.

1 Com a orientação a objetos, que será vista no Capítulo 13, será possível inclusive criar novas estruturas com a forma e com-portamento que se queira. Mas como esse tópico ainda não foi visto, trabalharemos aqui apenas com o uso das estruturas ori-ginais de forma disciplinada para que se comportem como estruturas derivadas. Além disso, muitas destas estruturas derivadas já podem ser encontradas em bibliotecas Python; mas o objetivo aqui é entender como elas podem ser concebidas a partir das estruturas mais básicas, especialmente a lista.

CAPÍTULO 11

Arquivos

Neste capítulo veremos como usar programas para criar arquivos no seu computador, bem como o uso destes arquivos para gravar e ler informações. Também veremos adicionalmente, com um pouco mais de detalhes, funções para trabalhar com textos (strings) realizando vários tipos de pro-cessamento com esse tipo de dados, incluindo acesso a caracteres e fatias, transformação de maiús-culas em minúsculas e vice-versa e formatação de strings para apresentação ao usuário.

11.1 Criação de arquivos

Computadores normalmente trabalham com dois tipos de memória: a primária, usualmente com base eletrônica, que normalmente se apaga quando o computador é desligado e a secundária, usual-mente organizada em arquivos em dispositivos de armazenamento persistente e que não se apaga mesmo quando o computador é desligado.

Para que a diferença fique bem clara, imagine que você está editando um texto em um editor. Se você desligar o computador antes de salvar seu texto vai perder as alterações que eventualmen-te tenha feito na tela. Isso ocorre porque essas alterações estão em memória primária e ainda não foram persistidas ou salvas no arquivo correspondente.

O arquivo, então é o lugar na memória secundária onde seu texto fica salvo para que possa ser recuperado em outro momento. Você provavelmente já deu nomes a arquivos que criou com edi-tores de texto, planilhas ou editores de imagens, como “meu_trabalho.doc” ou “minha_imagem.jpg”. Bem, arquivos são isso: são locais na memória secundária persistente do seu computador que são identificados por nomes que você eventualmente pode criar e onde ficam armazenadas infor-mações como imagens ou textos que você pode precisar depois.

Arquivos normalmente se classificam em dois tipos principais: arquivos executáveis, que são seus programas ou aplicativos, e arquivos de dados, que são repositórios de informações que even-tualmente são usadas por programas ou aplicativos. Neste capítulo veremos como usar arquivos de dados com programas Python.

Você também já deve ter reparado que diferentes tipos de arquivos possuem diferentes exten-sões. Por exemplo, os arquivos que contêm programas Python têm a extensão “.py”, como por exemplo, “meu_programa.py”.

Os arquivos de dados com os quais vamos trabalhar neste capítulo são arquivos de texto sim-ples (plain text), cuja extensão usual é “.txt”. Esses arquivos armazenam na memória secundária exatamente os mesmos caracteres que você vê quando os abre com um editor de texto. Outros for-matos como “.docx” ou “.rtf ” não são de texto simples, porque eles vão conter informações que os editores de texto usam para formatar o conteúdo do arquivo. Se você já tentou, por acaso, abrir um arquivo com extensão “.docx” no aplicativo “Bloco de Notas” deve ter visto que há vários ca-racteres estranhos ali: são os caracteres de formatação específicos que o editor de textos usa. Já os arquivos “.rtf ” usam apenas caracteres normais de texto, mas se você abrir um documento “.rtf ” no Bloco de Notas verá que há vários comandos de formatação exibidos antes, durante e depois do texto propriamente dito que é o que você visualiza no editor apropriado. Mas aqui não vamos lidar com isso, vamos usar apenas arquivos de texto simples ou “.txt”.

Vamos inicialmente criar um arquivo de texto para trabalhar com ele. Primeiramente, observe o menu à esquerda do seu editor PyCharm. Ele deve estar apresentando a lista dos programas que você já criou; algo parecido com o que é mostrado na Figura 11-1.

CAPÍTULO 12

Busca e Ordenação

Neste capítulo vamos apresentar os algoritmos mais clássicos sobre estruturas de dados que são a busca e a ordenação. Já vimos anteriormente como fazer uma busca sequencial em uma lista; aqui vamos aprofundar um pouco mais essa discussão. Veremos também como fazer a busca binária que é muito mais rápida que a sequencial, mas que só é possível se a lista estiver ordenada. Tam-bém veremos alguns métodos para ordenar listas, ou seja, reposicionar seus elementos do menor para o maior ou vice-versa. Dentre os métodos escolhidos, optamos por apresentar apenas os de implementação mais simples, já que este é um livro introdutório.

12.1 Busca sequencial

Frequentemente precisamos realizar buscas em listas de valores para verificar se um determinado valor está ou não na lista ou qual a posição dele na lista. Digamos, por exemplo, que temos um arquivo com os nomes e valores de temperatura medidos de um grupo de pacientes. Com base neste arquivo, queremos saber se algum paciente está com febre.

Inicialmente, definimos que cada linha do arquivo contém o nome do paciente nas posições (colu-nas) 0 a 39 e a temperatura medida nas posições 40 em diante. Assumimos que todas as temperaturas são dadas em graus Celsius. O arquivo, “temperaturas.txt”, assim, poderia se parecer com:

Rei Arthur dos Bretões 36.1Patsy 38.2Cavaleiro Negro 37.0Sir Bedevere 36.5Sir Lancelot 39.1casto Sir Galahad 40.0bravo Sir Robin 37.0

Você pode adicionar mais nomes e temperaturas a este arquivo sem problemas, mas estes são suficientes para usar no capítulo.

Cada pessoa será representada em memória principal por um pequeno dicionário com a cha-ve “nome” para conter o nome e a chave “temperatura” para conter a temperatura medida como “float”. A lista de todas as pessoas será então uma lista de dicionários.

Para ler estes valores, podemos fazer um “for” para cada linha do arquivo e, em seguida, fatiar a string que representa a linha em duas partes. A primeira, da posição 0 até 39 contém o nome – podemos usar a mensagem “strip” para obter uma cópia da string sem os espaços em branco des-necessário à direita. Por exemplo, 'abc '.strip() produz a string “abc”. Se houvesse espaços à es-querda eles também seriam eliminados. Mas espaços entre os caracteres não o são. Por exemplo, ' abc def '.strip() produz “abc def”.

Já para obter a temperatura como número de ponto flutuante, faremos o fatiamento da linha da posição 40 até o final e converteremos a substring usando a função “float”. A função “float” ignora o caractere de final de linha e quaisquer espaços que haja na string antes ou depois do nú-mero, então não precisamos nos preocupar em remover esses caracteres antes de aplicá-la.

Defina então em sua biblioteca de funções a função a seguir e crie um arquivo de texto com al-guns nomes e temperaturas, conforme mostrado. Você vai precisar desta função e do arquivo para executar os próximos exemplos:

CAPÍTULO 13

Noções de Programação

Orientada a Objetos

Neste capítulo veremos um tópico que normalmente não é abordado em disciplinas introdutó-rias, que consiste em noções de programação orientada a objetos. Veremos os conceitos de classe e objeto, bem como de atributos, métodos e associações, e mostraremos como programar classes simples baseadas em nosso exemplo de simulação de supermercado.

13.1 História e motivação

Vimos, no Capítulo 10, um programa que simulava caixas de supermercado e clientes, contabili-zando seus tempos de espera e ociosidade. Naquele capítulo comentamos que a estrutura do pro-grama que executava a simulação já começava a ficar complexa, pois o mesmo já tinha algumas dezenas de linhas e mais de 10 pontos de complexidade ciclomática, o que o torna um programa de médio risco em termos de teste.

Agora imagine programas como a maioria dos aplicativos que você conhece; eles podem ter milhões de linhas de código. Organizá-los na forma de algoritmos como vínhamos fazendo até aqui faria com que fossem virtualmente não testáveis.

O fato é que algoritmos e programação com estruturas de repetição e seleção são adequados para o que chamamos de programming in the small, ou seja, para a programação de funções que executam a lógica mais básica de um sistema, como, por exemplo, calcular fatoriais, ordenar lis-tas e fazer buscas em estruturas de dados. Porém, a grande organização de sistemas de informática não pode ser feita dessa forma. Já se tentou no passado (décadas de 1960 e 1970), mas a aborda-gem de decomposição funcional, ou seja, considerar o sistema como uma grande função e depois subdividi-lo recursivamente em funções cada vez menores, apresentou sérias limitações.

A técnica hoje predominante para organização de sistemas ou programming in the large é co-nhecida como programação orientada a objetos. Essa técnica também surgiu nos anos 1960, mas só se consolidou na indústria de software a partir dos anos 1990.

Talvez a primeira vez na história em que um sistema foi desenvolvido com essa técnica tenha sido o Sketchpad de Ivan Sutherland (Estados Unidos, 1938). Ele desenvolveu em 1963 um sis-tema considerado precursor da computação gráfica, no qual, com uma caneta de luz, podia dese-nhar objetos gráficos na tela de um computador e manipulá-los como objetos. Ou seja, ele podia mover círculos, retângulos ou outras figuras geométricas na tela, como uma unidade. Até então, desenhos eram apenas pontos na tela e não podiam ser manipulados dessa forma.

O sistema de Sutherland já possuía muitos dos conceitos que atualmente são considerados como pertencentes à programação orientada a objetos. Mas o sistema não permitia ao usuário programar, apenas desenhar. Assim, embora Sutherland tenha usado os conceitos para produzir o sistema, ele não permitia aos usuários programar com as mesmas técnicas.

A primeira linguagem de programação considerada orientada a objetos foi Simula 67. Ela foi criada por Kristen Nygaard (Noruega, 1926-2002) e Ole-Johan Dahl (Noruega, 1931-2002) em 1967 e seu propósito não era ser uma linguagem de programação de propósito geral, como é o caso de Python, Java, Pascal e outras. Simula era justamente uma linguagem de simulação. Ou seja, era uma linguagem especializada para o desenvolvimento de sistemas de simulação seme-lhantes ao supermercado que desenvolvemos no Capítulo 10. A linguagem permitia a criação de

Este livro é indicado para quem quer aprender ou ensinar programação de

computadores usando a linguagem que nos últimos anos vem se tornando

dominante nesta área: PYTHON.

Ao mesmo tempo em que ensina os fundamentos de algoritmos e programa-

em relação a outras obras, pois introduz ao iniciante os conceitos de DESEN-

VOLVIMENTO DIRIGIDO POR TESTE (TDD) – uma técnica de programação que

produz excelentes resultados ao fazer o programador pensar sobre seu

código antes de produzi-lo e escrever os testes que automaticamente irão

Dezenas de exercícios são propostos e, ao contrário de muitos outros livros,

-

car, antes de conferir os gabaritos online, se o seu programa efetivamente

está correto, desta forma já encaminhando, desde os primeiros exercícios, o

pensamento do aprendiz para o desenvolvimento dirigido por teste.

O livro é altamente recomendado para disciplinas de introdução a algoritmos

e programação em cursos superiores em todas as áreas, e também no

Ensino Médio, mas também pode ser usado por aqueles que querem apren-

der sozinhos (autodidatas).