Escolar Documentos
Profissional Documentos
Cultura Documentos
PRÁTICA DE LABORATÓRIO
EM PYTHON
BELEM - PA
2020
© E.L.Favero Algoritmos em Python 2
SUMÁRIO
Prefácio
Este texto surgiu como um material de apoio a um curso de tele-ensino de uma
disciplina de Algoritmos de 60 a 68 horas. O texto foi elaborado para contemplar a
metodologia de ensino descrita a seguir.
Cada capítulo compreende um módulo, tema, de 4 horas aula. São 15 capítulos
principais e 3 opcionais. A metodologia é mais assíncrona, porém com encontros síncronos.
O essencial de uma disciplina de algoritmos é a prática do estudante, que deve ser
verificada, checada a cada módulo, com a correção dos exercícios propostos.
Nos encontros síncronos, os temas e conceitos são apresentados em aulas de 45
min de exposição e um tempo posterior de discussão para tirar dúvidas, respondendo
perguntas.
Nas atividades assíncronas, o estudante lê o material dos módulos e resolve os
exercícios. No ambiente virtual é feita a postagem de cada módulo. Cada módulo é
associado com uma atividade de resolução de exercícios práticos e/ou teóricos. Neste
ambiente, o estudante posta a sua resolução dos exercícios e o professor avaliando-os tem
feedback para tirar dúvidas e/ou redirecionar os exercícios do próximo módulo.
Os comandos condicionais, de repetição, etc. são inicialmente apresentados através
de fluxogramas e pseudocódigo. A seguir, exemplos de usos dos comandos são traduzidos
para a linguagem Python e são animados no ambiente Python Tutor. Após o estudante
compreender o comportamento do comando apresentado, ele é convidado a executá-los no
ambiente de programação da linguagem Python, IDLE.
Segue a lista dos módulos:
1 INTRODUÇÃO & PYTHON TUTOR
2 TIPOS DE DADOS INT E FLOAT
3 TIPO DE DADOS STRING
4 COMANDOS DE ENTRADA E SAÍDA
6 COMANDOS DE DECISÃO (IF)
7 RE-FATORANDO O CÓDIGO
8 LISTA E FAIXA DE VALORES
9 COMANDO DE REPETIÇÂO: FOR
10 COMANDO DE REPETIÇÃO: WHILE
11 FUNÇÕES
12 MÉTODOS DE BUSCA E ORDENAÇÃO
13 VETORES E MATRIZES
14 DICIONÁRIOS E CONJUNTOS: SET E DICT
15 PERFORMANCE DE FUNÇÕES
Capítulo
O gráfico abaixo mostra uma lista de valores plotados a partir de um programa Python.
X = list(range(0,20))
Y = [x*x+3*x-4 for x in X]
plt.scatter(X,Y)
plt.show()
print(X)
print(Y)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,..., 18, 19]
[-4, 0, 6, 14, 24, 36, 50, 66, 84, 104, 126,...
, 374, 414]
Com este exemplo se entende porque se chamam variáveis, porque os valores variam.
Neste exemplo, as variáveis nomeiam valores inteiros ou vetores de valores inteiros.
© E.L.Favero Algoritmos em Python 9
Observação: o programa acima não precisa ser compreendido agora. Foi apresentado só
para motivar a introdução do conceito de variável. O que é necessário compreender neste
módulo é como práticar os exercícios apresentados no final do módulo, sobre o conceito de
variável.
a=1
b=2
c=a
c=c+1
print(a)
print(a+b)
print(a+c)
linhas de código
Print output (drag lower right corner to resize) :Escreva saída (araste canto direito
inferior para mudar o tamanho)
Frames, Objects: Memorias, Objetos
(known limitations) : limitações conhecidas
line that just executed: linha recém executada
next line to execute: próxima linha a executar
Edit this code: edite este código
First, Prev, Next, Last: primeiro, prévio, próximo, último
Global Frame: Memoria Global
© E.L.Favero Algoritmos em Python 11
Agora com dois next chegamos na situação abaixo, onde na memória global é mostrado que
as variáveis possuem os valores a=1 e b=2.
Com mais um next c=1, e com mais um next c=2 no Global Frame. Podemos executar
também para trás com o botão prev. Assim vamos executanto para frete ou para trás o
código, até entendermos o que o programa esta fazendo, compreendendo o comportamento
da execução do algoritmo.
© E.L.Favero Algoritmos em Python 12
Nos passos 5, 6,e 7 ocorrem as impressões dos valores na tela de saída, respectivamente
os valores 1, 3, 3.
O nome de uma variável sempre começa por uma letra ou pelo _. Depois do primeiro
caractere podemos ter também números. A linguagem é case sensitive, isto é, nomes com
maiúscula e com minúsculas são diferentes, x ≠ X. Os comentários de linha em Python são
iniciados pelo símbolo #, e vão até o final da linha. Seguem alguns exemplos de declarações
de variáveis em comandos de atribuição.
# exemplos de variáveis
A1 = 76
a1 = 12 # comentario
aa_1 = a1+A1
zero = 0
O tradutor do google pode nos auxiliar na identificação do erro, mas é bom depois
voltar para o idioma inglês.
© E.L.Favero Algoritmos em Python 14
E1.1 a=1
b=2
c=a
c=c+1
print(a)
print(a+b)
print(a+c)
>>>
1
3
3
E1.2 # exemplos de variáveis & comentários
A1 = 76
a1 = 12
aa_1 = a1+A1 # o valor de aa_1 é 88
zero = 0
a=3
b=5
res=2*a * 3*b
print(res)
>>>
90
E1.4 Escreva o resultado de 2a x 3b. Onde a=7 e b=11.
a=3
b=5
c=11
abc=a+b+c
print(abc)
>>>
19
E1.7 Seja um salário (sal) de 1000. Como dar um aumento de 15%. Qual o valor do
aumento e do novo salário.
sal=1000
percent=15
aumento=sal*percent/100
novosal=sal+aumento
© E.L.Favero Algoritmos em Python 15
print(aumento, novosal)
>>>
150.0 1150.0
E1.8 Seja um salário (sal) de 1500. Como dar um aumento de 20%. Qual o valor do
aumento e do novo salário.
sal=1500
percent=20
aumento=sal*percent/100
novosal=sal+aumento
print(aumento, novosal)
>>>
300 1800
E1.9 Seja um salário (sal) de 1500. Como dar um aumento de 10%. Qual o valor do
aumento e do novo salário.
E1.10 Seja um salário (sal) de 1800. Como dar um aumento de 1%. Qual o valor do
aumento e do novo salário.
RESUMO
= comando de atribuição
+ - * / operadores aritméticos
print() comando de impressão
variável
nomes de variáveis
algoritmo é uma sequênciade comandos
© E.L.Favero Algoritmos em Python 16
Capítulo
sal = 1500
percent = 20
aumento = sal*percent/100
novosal = sal+aumento
print(aumento, novosal)
Interface do IDLE
Acima, no lado esquerdo criamos o programa meu.py. Depois de digitar estas linhas de
código o ambiente pede para salvarmos (save) o arquivo antes de executarmos (run) o
código. O resultado da execução é mostrado na tela Shell do IDLE, no lado direito. No topo
da tela, encima, no lado esquerdo, aparece o caminho (path) da pasta onde está o arquivo
do programa. Na tela da direita novamente o caminho é repetido dizendo RESTART (re-
iniciado, ou re-executado). No lado esquerdo da IDLE temos várias opções de menu: file,
edit, format, run, etc.
No file é importante saber: new (novo arquivo), open (abrir), recent files (abrir um
recente), save (salva), save as (salvar como, com novo nome).
No edit é importante saber: undo (ctr-z, desfazer um erro de edição), replace
(substituir um nome de variável por outro); além disso usa-se muito copiar e colar.
No format é importante saber: indent (fazer uma indentação) e dedent (tirar a
indentação). Quando o ambiente diz que tem problema de indentação, uma forma de
corrigir é remover toda indentação e criar uma indentação nova e correta, com estes
dois comandos.
No Run é importante saber: run module (F5) rodar o código.
a = float(22/5)
b = int(4.5)
c = int(3)
d = int(0xff563)
print(a,b,c,d)
>>>
4.4 4 3 1045859
Esta notação acima, com várias linhas de comandos deve ser digitada no lado esquerdo; em
new file cria-se uma nova janela *untitled*; depois copia-se e cola-se, não incluir o prompt
>>>.
Quando pedimos para rodar (run) o ambiente pede para darmos um nome para o programa
ser salvo.
© E.L.Favero Algoritmos em Python 19
Quando é forçado o run, vemos o efeito do código que é o print mostrado depois do prompt.
A variável a representa um valor decimal 22/5 = 4.4. A variável b recebe a parte inteira do
valor 4.5 que é 4. Em d o valor hexadecimal FF563 equivale ao valor inteiro 1045859.
e = float(int(3.9))
f = int(float(3.9))
g = int(float(3))
h = round(3.9)
i = round(3.49)
j = round(3.5)
print(e,f,g,h,i,j)
>>>
3.0 3 3 4 3 4
Em e o valor 3.9 foi convertido para 3 e depois para float 3.0. Em f o 3.9 float é convertido
para o int 3. Em h o valor 3.9 é arredondado para o inteiro mais próximo que é 4. Em i o
valor 3.49 foi arredondado o int mais próximo 3. Em j o valor 3.5 é arredondado para o 4, e
não para o 3. O comando print() imprime os valores das variáveis.
>>> 1/3
0.3333333333333333
>>> 5//2
2
>>> 5%2
1
+ - * / ** // (parte inteira)
% (resto da divisão)
Operadores aritméticos
>>> 10 % 3
1
>>> 8 / 3
2.6666666666666665
>>> 8 % 3
2
>>> 10*2**3
80
>>> (10*2)**3
8000
>>> 10*(2**3)
80
>>> x= 2**3
( ) 0 ( )6 ( )8 ( )9 ( )27
>>> x= 2 % 3
( ) 0 ( )1 ( )2 ( )3 ( )1.5
© E.L.Favero Algoritmos em Python 21
>>> x= float(20 % 3)
( ) 0 ( )1.0 ( )2 ( )2.0 ( )1.5
>>> x= int(20 / 3)
( )6 ( )6.0 ( )6.666 ( )3.333 ( )1.5
>>> x= 3 - 2 * 4
( ) 0 ( )4 ( )-5 ( )4.0 ( )-2
>>> x= 3 * 2 ** 2
( )0 ( )12 ( )36 ( )7 ( )100
>>> 10+2*30
70
>>> 4**2+30
46
>>> (9**4+2)*6-1
39377
E2.1 Seja um salário (sal) de 1000. Como dar um aumento de 15%. Qual o valor do
aumento e do novo salário.
sal=1000
percent=15
aumento=sal*percent/100
novosal=sal+aumento
print(aumento, novosal)
>>>
150.0 1150.0
E2.2 Seja um salário (sal) de 1500. Como dar um aumento de 20%. Qual o valor do
aumento e do novo salário.
sal=1500
percent=20
aumento=sal*percent/100
novosal=sal+aumento
print(aumento, novosal)
>>>
300 1800
© E.L.Favero Algoritmos em Python 22
E2.3 Seja um salário (sal) de 1500. Como dar um aumento de 10%. Qual o valor do
aumento e do novo salário.
E2.4 Seja um salário (sal) de 1800. Como dar um aumento de 1%. Qual o valor do
aumento e do novo salário.
a=3
b=5
res=2*a * 3*b
print(res)
>>>
90
E2.6 Escreva o resultado de 2a x 3b. Onde a=7 e b=11.
a=3
b=5
c=11
abc=a+b+c
print(abc)
>>>
19
E1.9 Seja uma temperatura de 30 graus Celsius; converter para Fahrenheit:
F=(9*C)/5+32.
E1.10 Sejam 28 dias. Quantas horas e quantos minutos tem em 28 dias? Por
exemplo, 2 dias, são 48horas e 48*60=2880 minutos.
BOX: Um byte são oito bits. O valor binário do inteiro em hexa 0xFF é um byte
‘0b11111111’, que é o valor positivo 255. Num byte podemos representar a faixa de
0 até 255, que são 2**8=256 valores.
>>>bin(0xF)
'0b1111'
>>>bin(0xFF)
'0b11111111'
>>>bin(0xF0)
'0b11110000'
>>>int(0xF0080419)
4027057177
>>>bin(0xF0080419)
'0b11110000000010000000010000011001'
Normalmente usa-se valores decimais (de base 10), mas pode-se definir valores octais (de
base 8) e hexadecimais (base 16) ou binários (base 2). Para declarar um inteiro octal,
hexadecimal ou binário usa-se os prefixos, 0o, 0x, 0b. Acima temos um hexa de oito dígitos
0xF0080419 que corresponde a 32 bits.
a = 42 #decimal
b = 0o10 #octal
c = 0xA1 #hexadecimal
d = 0b1010101
print(a,b,c,d)
>>>>
42 8 161 85
informação é o bit. Oito bits formam o byte. Alguns computadores possuem a memória
formada por palavras de 8 bytes, ou 64 bits. Na escrita destes bytes é mais fácil utilizar a
notação hexadecimal, por exemplo, dois dígitos hexa correspondem a um byte ou 8 bits.
dec = 344
print("O decimal",dec,"é:")
print(bin(dec),"em binario.")
print(oct(dec),"em octal.")
print(hex(dec),"em hexadecimal.")
>>>
O decimal 344 é:
0b101011000 em binario.
0o530 em octal.
0x158 em hexadecimal.
A função type() permite testar o tipo de dados de um valor ou de uma variável. Por exemplo,
>>> type(10)
<class 'int'>
>>> type(12.1)
<class 'float'>
Neste caso cada tipo é visto como uma classe de objetos, deste ponto de vista vem a
palavra class. Assim os inteiros, os float e os boolean, são também objetos.
Inteiros são simples e óbvios, mas Float representa números reais com ou sem expoente (e
ou E). Esses números são comumente chamados de floating-point ou números de ponto
flutuante. Por exemplo: 0.0042, .005, 1.14159265 e 6.02e-23 (o mesmo que 6.02 x 10-²³).
Executando os prints abaixo, temos o tipo de dados dos valores numéricos testados,
diferenciando int de float.
print(type(5))
print(type(5.0))
print(type(4.3))
print(type(-2))
print(type(100))
print(type(1.333))
>>>
<class 'int'>
<class 'float'>
<class 'float'>
<class 'int'>
<class 'int'>
<class 'float'>
© E.L.Favero Algoritmos em Python 25
Capítulo
3 TIPO DE DADOS STRING
Este capítulo apresenta o tipo de dados string usado para representar nomes e
textos. Eles são muitos usados nos comandos de entrada e saída. Aqui tratamos de vários
operadores e métodos de manipulação de strings: operadores + % *; métodos lower(),
upper(), split(), strip(). Fatiamento de strings. Composição de strings. Caracteres ascii.
Strings no início de uma linha, sem o comando de atribuição são considerados comentários.
O string com três aspas pode ocupar várias linhas. É útil em programas grandes para
colocar uma parte do código programa como comentário, ou para representar um texto
grande dentro do código do programa.
grande"""
O método Split quebra o string e devolve uma lista, acima temos uma lista de palavras. Litas
só veremos mais adiante, mas aqui vamos nos familiarizando com a notação.
Os strings em python são não mutáveis. Portanto, se temos uma string a fazemos b=a;
serão duas cópias diferentes; se modificamos o a não modifica o b. Para isso acontecer as
variáveis string são referencias (apontam para) os conteúdos. Ver abaixo.
>>> '-'*10
'----------'
© E.L.Favero Algoritmos em Python 27
No exemplo acima o tempo é mostrado apenas com duas casas decimais. 5 casas no total,
duas depois do ponto. Aos poucos vamos introduzindo o uso destes formatos para a
composição de strings.
Além dos operadores (+ % *) para strings temos vários outros métodos tais como
lower(), upper(), split(), strip(), etc. O método startswith(prefixo) retorna True se uma string
começa com o prefixo passado por argumento, e False caso contrário.
O termos lower(), upper(), split(), strip() significam:
Podemos testar como começa o início de um string, no caso o nome1 definido acima.
Depois o método strip() retorna uma cópia da string com os espaços em branco removidos
(antes e depois).
>>> nome1.startswith('lin')
False
>>> nome1.startswith('Lin')
True
© E.L.Favero Algoritmos em Python 28
Duas funções muito úteis são split() e len(). A Split() quebra e retorna uma lista com os
pedaços. A função len() determina o comprimento da string (quantas letras possui).
>>> chr(48)
'0'
>>> chr(49)
'1'
>>> chr(65)
'A'
>>> chr(90)
'Z'
>>> chr(97)
'a'
>>> ord('3')
51
>>> ord('b')
98
Abaixo temos um resumo da tabela Ascii, para os principais grupos de letras. As letras de
controle são utilizadas internamente pelos sistemas computacionais principalmente para
© E.L.Favero Algoritmos em Python 29
E3.2 Seja, a='jhon lenon’ . Imprima o conteúdo da variável todo em caixa alta.
E3.3 Seja, a='jhon lenon’ . A partir de a, imprima “Lenon, Jhon”. Use fatiamento e
capitalize().
a='jhon lenon'
# 0123456789
print(a[5:].capitalize()+ ', ' + a[:4].capitalize())
>>>
Lenon, Jhon
E3.4 Seja, a='jhon lenon’ . A partir de a, imprima “Jhon, Jhon, Jhon, Lenon. Use
também o operador * para string.
E3.5 Seja, a='jhon lenon’ . A partir de a, imprima “----------Jhon---------“. Use também o
operador * para string.
E3.6 Seja, a='jhon lenon’ . A partir de a, imprima “J. Lenon”.
a='jhon lenon'
# 0123456789
print(a[0].upper()+ '. ' + a[5:].capitalize())
>>>
J. Lenon
E3.7 Seja b="tinoco". Escreva "TINoco", pegando fatias da string b.
E3.8 Seja a='jhon \nlenon \n'. Escreva "LENON, JHON", pegando fatias da string a.
C3.2 Qual a diferença entre uma string declarada com aspas (apóstrofos) ou 3 aspas?
RESUMO:
string com um apóstrofo ou aspas
string com três apóstrofos ou aspas (multi linhas)
string no início de linha como comentário
operadores sobre expressões de string: concatenação +, multiplicação *, composição %
lower(), caixa baixa
upper(), caixa alta
split(), quebra
strip(), limpa brancos
startswith(), começa com
len(), (length), comprimento
capitalize(), primeira letra em maiúscula
fatiamento [início:fim]
tabela ascii
ord() valor ascii do caractere
chr() char do valor ascii
3.4 Nerd: Int para string & string para Int (OPCIONAL NUM
COMEÇO)
Por exemplo, '1312'= (((((1*10)+3)*10)+1)*10)+2. Então para pegar o valor 1 a partir do '1'
devemos fazer ord('1')-ord('0’)=49-48=1, pois, em Ascii os números são sequênciais; o valor
7 a partir de '7' devemos fazer ord('7')-ord('0’)=55-48=7.
def str2int(S):
val=0; LEN=len(S)
for i in range(LEN):
dig=ord(S[i])-ord('0')
val = val*10+dig
return val
print(str2int('1312'), str2int('0'), str2int('100'))
print(int('1312'), int('0'), int('100'))
>>>
1312 0 100
Este algoritmo srt2int() simula a função int() do Python, mas nossa versão ainda é limitada,
pois o int() aceita [+-] o sinal na frete do número e aceita colocar caracteres de espaço antes
e/ou depois. Por fim, também se pode trabalhar com bases, 2, 8, 16, e.g., na base 2,
int('10101',2) = int('0b10101',2)=21.
© E.L.Favero Algoritmos em Python 31
A solução abaixo codifica o inverso, int para str, int2str(). Mas vamos fazer sem usar str().
Para um só dígito é simples: str(D) é equivalente a chr(D+ord('0')), por exemplo,
chr(7+ord('0'))='7' e str(7)='7'. Para converter um inteiro, >9, numa sequência de dígitos
fazemos: enquando for maior ou igual a 10, basta pegar sempre o resto da divisão inteira
por 10. Por exemplo, a partir de 312, 312//10 da 31 e 312%10 dá 2; depois a partir de 31,
31 // 10 dá 3 e 31%10 dá 1; depois 3<10, pega-se o 3. Juntando tudo da [2,1,3]. Revertendo
da [3,1,2].
Este algoritmo facilmente pode manipular inteiros negativos, basta guardar o sinal do
número, neg=x<0;x=abs(x), e trabalhar com o valor abs(). No final, se for negativo
acrescentar o sinal no início da string.
Está solução também pode ser generalizada para outras bases, substituído-se o 10
pela base, por exemplo, 2, 8. Para a base 16 a função dig() deve ser ajustada para trabalhar
com os dígitos “0123456789abcdef”.
def str2int(S):
val=0; LEN=len(S)
for i in range(LEN):
dig=ord(S[i])-ord('0')
val = val+dig
if i<LEN-1: val*=10
return val
print(str2int('1312'), str2int('0'), str2int('100'))
>>>
1312 0 100
E3.2 Faça a função dig() que retorna o valor inteiro de um digito char
def dig(x): return chr(x+ord('0'))
© E.L.Favero Algoritmos em Python 32
E3.3 Faça a função int2str que transforma um inteiro para string usando dig()
def int2str(I):
STR=[]
while I>=10:
STR.append( dig(I%10) )
I = I//10
else: STR.append( dig(I) )
return ''.join(reversed(STR))
print(int2str(312), int2str (0), int2str(10000))
>>>
312 0 10000
E3.4 Faça a função int2str generalizada para trabalhar com hexadecimais. Está solução
também pode ser generalizada para outras bases, substituído-se o 10 pela base, por
exemplo, para 16 a função dig() deve ser ajustada para trabalhar com os dígitos
“0123456789abcdef”.
© E.L.Favero Algoritmos em Python 33
Capítulo
Ler duas variáveis a e b do tipo int e imprimir a sua soma. Uma leitura em Python com o
comando input() retorna uma string, por exemplo '12' que pode ser convertido em 12 pela
função int('12'). Assim o programa fica como:
a=int(input('Digite a:'))
b=int(input('Digite b:'))
ab=a+b
print('a+b=',ab)
Vamos agora ler uma velocidade e uma distância e imprimir o tempo necessário para
percorrer a distância.
velo=int(input('Velocidade km/hora:'))
dist=int(input('Distância km :'))
tempo = dist/velo
print('para percorrer %d km numa vel %d km/h precisa %5.2f horas'
% (dist, velo, tempo))
>>>
© E.L.Favero Algoritmos em Python 34
Distância km :500
Velocidade km/hora:70
para percorrer 500 km numa vel 70 km/h precisa 7.14 horas
velo=float(input('Velocidade km/hora:'))
dist=float(input('Distância km :'))
tempo = dist/velo
print('para percorrer %d km numa vel %d km/h precisa %5.2f horas'
% (dist, velo, tempo))
nome=input('digite o Nome:')
print('O nome lido foi: ', nome)
nome=input('digite o nome:')
Nome=nome.capitalize()
print(nome, Nome)
>>>
digite o nome:claudio
claudio Claudio
a=input('digite o nome:')
b=a.capitalize()
print(a, b)
>>>
digite o nome:claudio
claudio Claudio
E4.4 Ler nome, identidade, cpf. Imprimir os dados lidos, um em cada linha.
E4.5 Ler um nome tipo “Paulo dos santos dos deuses”. Usando Split quebre no ‘dos’ em
três partes.
b= input('digite o nome:')
© E.L.Favero Algoritmos em Python 35
print(b.split('dos'))
>>>
digite o nome: Paulo dos santos dos deuses
['Paulo ', ' santos ', ' deuses']
E4.8 Ler um salário (sal). Dar um aumento de 20%. Qual o valor do aumento e do novo
salário.
E4.9 Ler um salário (sal). Dar um aumento de 2%. Qual o valor do sal, do aumento e do
novo salário.
Capítulo
5 EXPRESSÕES LÓGICAS
Este capítulo apresenta as expressões lógicas como uma preparação para vermos os
comandos condicionais e de repetição. São apresentadas as tabelas verdade para os
operadores lógicos: and, or, not. São apresentadas as expressões relacionais de
igualdade, desigualdade e pertinência.
>>> bool(1)
True
>>> bool(-10)
True
>>> bool(10)
True
>>> bool(0)
False
>>> a=True
>>> a and bool(2)
True
>>> True + 1
2
>>> False + 1
1
© E.L.Favero Algoritmos em Python 37
Operadores Lógicos
not and or
Estes três operadores podem ser combinados para fazer expressões lógica complexas,
seguem alguns exemplos.
VF = [v-verdadeiro, f-falso]
para i in VF:
escreva('not', i, '=', not i)
>>>
Tabela Verdade not:
not True = False
not False = True
O pseudo código serve como uma notação informal para representar algoritmos, baseado
numa linguagem próxima da linguagem natural. Este pseudo código pode ser traduzido
para uma lingugem de programação que para nós é Python.
Em Python:
print('Tabela Verdade not:')
TF = [True, False]
for i in TF:
print( 'not', i,'=', not i)
>>>
O and é um operador binário, ocorre entre dois operandos. O and é sempre False exceto
quando o valor dos dois operandos for True então neste caso o valor dele também é True.
O or é sempre True exceto quando o valor dos dois operandos for False então neste caso o
valor dele também é False.
>>> a=1;b=2
>>> a==b
False
>>> a==1
True
>>> a==2
False
>>> a!=2
True
>>> materia1=8;materia2=9;materia3=9.5
>>> materia1>7 and materia2>7 and materia3>7
True
>>> (materia1>7) and (materia2>7) and (materia3>7)
True
>>> x=3
>>> x+7>4
True
>>> (x+7)>4
True
a=4;b=2;c=10;d=5;f=4
© E.L.Favero Algoritmos em Python 41
print('a==c',a==c)
print('a<b' ,a<b)
print('d>b', d>b)
print('c!=f', c!=f)
print('a==b',a==b)
print('c<d',c<d)
print('b>a',b>a)
print('c>=f',c>=f)
print('f>=c',f>=c)
print('c<=c',c<=c)
print('c<=f',c<=f)
>>>
sal=900
salMaiorMil=sal>1000
print('maior que mil: ', salMaiorMil)
>>>
maior que mil: False
E5.2 Seja uma variável sal=2000. Crie uma variável lógica que é verdadeira se
sal>1000. Imprima o valor da variável.
sal=2000
salMaiorMil=sal>1000
print(salMaiorMil)
>>>
True
E5.3 Crie uma variável aprovado que é verdadeira se todas as três matérias
(materia1, materia2 e materia3) são maiores que 7. Inicialize as variáveis
com valor maior que sete.
materia1=8;materia2=9;matateria3=9.5
aprovado=materia1>7 and materia2>7 and materia3>7
print(aprovado)
>>>
True
E5.4 Crie uma variável aprovado que é verdadeira se todas as três matérias
(materia1, materia2 e materia3) são maiores que 7. Inicialize uma das
matérias com valor 6 e as outras com valor > 7. Escreva o valor da variável
aprovado.
materia1=6;materia2=9;matateria3=9.5
aprovado=materia1>7 and materia2>7 and materia3>7
print(aprovado)
>>>
False
E5.5 Seja a atribuição múltipla: A,B,C,D=1,2,True,False. Mostre o valor da
expressão 'A>B and C or D'
© E.L.Favero Algoritmos em Python 42
A,B,C,D=1,2,True,False
print('A>B and C or D =', A>B and C or D)
>>>
A>B and C or D = False
E5.6 Seja a atribuição múltipla: A,B,C,D=10,3,False,False. Mostre o valor da
expressão 'A>B and C or D'
A,B,C,D=10,3,False,False
print('A>B and C or D =', A>B and C or D)
>>>
A>B and C or D = False
E5.7 Seja a atribuição múltipla: A,B,C,D=5,1,True,True. Mostre o valor da
expressão 'A>B and C or D'
A,B,C,D=5,1,True,True
print('A>B and C or D =', A>B and C or D)
>>>
A>B and C or D = True
E5.8 Seja a atribuição múltipla: A,B,C,D=5,1,True,True. Mostre o valor da
expressão 'A>B and C or D'
A,B,C,D=5,1,True,True
print('A>B and C or D =', A>B and C or D)
>>>
A>B and C or D = True
Capítulo
A figura acima ilustra dois fluxogramas do comando if. Um fluxograma representa um fluxo
de execução da sequência de passos de um comando. Um comando if simples, executa
© E.L.Favero Algoritmos em Python 44
6.1 Comando IF
Em Python temos vários usos do comando if/elif/else. Vamos ler um valor e dizer se é
negativo, positivo ou igual a zero. Vamos usar três vezes o if simples, que resulta num if em
cascata. Note que, no código executável, após a leitura do input() o valor é convertido para
inteiro int().
x=ler('Digite x:')
se x>0 então: escreva(x, 'é positivo')
se x==0 então: escreva(x, 'é zero')
se x<0 então: escreva(x, 'é negativo')
x=int(input('Digite x:'))
if x>0: print(x, 'é positivo')
if x==0: print(x, 'é zero')
if x<0: print(x, 'é negativo')
>>>
Digite x:1
1 é positivo
Estes ifs estão em cascata, assim mais de um comando poderia ser executado. Todas as
condições são testadas. Mas os três testes são mutualmente exclusivos, se um é verdade
os outros dois não são. Então só um deles é executado. Este mesmo código pode ser
escrito com if/elif, podem ser vários else/if=elif.
x=ler('Digite x:'))
se x>0 então: escreva(x, 'é positivo')
senão_se x==0 então: escreva(x, 'é zero')
senão_se x<0 então: escreva(x, 'é negativo')
x=int(input('Digite x:'))
if x>0: print(x, 'é positivo')
elif x==0: print(x, 'é zero')
elif x<0: print(x, 'é negativo')
A diferença desta versão para a versão em cascata é que aqui os testes são executados
somente até o primeira condição ser verdadeira. Quando um if ou um elif for verdadeiro
todos os que vem depois não são mais testados.
© E.L.Favero Algoritmos em Python 45
O fluxograma do comando if/else executa uma ação quando a condição é verdadeia e outra
ação quando a condição é falsa.
x=ler('Digite x:'))
se x>=0
então: escreva(x, 'é positivo')
senão: escreva(x, 'é negativo)
x=int(input('Digite x:'))
if x>=0: print(x, 'é positivo')
else: print(x, 'é negativo')
Novamente, codificamos o mesmo algoritmo anterior, agora com dois if/else aninhados. Por
aninhado entende-se um dentro do doutro. Note que não se pode escrever dois ifs na
mesma linha. O segundo tem que ser indentado dentro do bloco do else. Um bloco é uma
sequência de um ou mais comandos como uma unidade, dentro de uma indentação
(vertical) ou dentro de uma linha (horizontal) sequênciados pelo ponto e virgula.
x=int(input('Digite x:'))
if x>0: print(x, 'é positivo')
else:
if x==0: print(x, 'é zero')
else : print(x, 'é negativo')
Suponhamos agora uma conta de celular com diferentes taxas por minuto conforme o
consumo total. Se o usuário aumenta o número de minutos consumidos o valor por minuto
baixa, caindo numa faixa de valor por minuto mais baixa que vale para a conta toda.
if min>400: preco=0.18
elif min>200: preco=0.20
elif min>100: preco=0.25
else: preco=0.30
print('minutos consumidos:',min)
print('preço por minutos :',preco)
print('valor total :',preco*min)
Interpretando esta tabela, vamos considerar que a tarifa baixa é para o valor Kw consumido
dentro daquela faixa. Por exemplo, para um cliente residencial o consumo de 400Kw ele
pagará 200 a 0.40 e 200 a 0.60, que resultará em 200,00.
kw=int(input('quantos Kwh:'))
tipo= input(' tipo conta:')
if tipo not in ['r','i','c']:
print('tipo de conta Invalido:',tipo);
exit(1)
if tipo=='c':
if kw >= 5000: preço = (kw-5000)*0.80 + 5000*0.50
else: preço = kw*0.50
if tipo=='i':
if kw >= 10000: preço=(kw-10000)*0.60 + 10000 * 0.40
else: preço=kw*0.40
if tipo=='r':
if kw >= 5000: preço = (kw-500)*0.70 + 300*0.60 + 200*0.40
elif kw >= 200: preço = (kw-200)*0.60+ 200*0.40
else: preço = kw*0.40
print('pagar para %d valor = %5.2f' % (kw,preço))
>>>
quantos Kwh:400
tipo conta:r
pagar para 400 valor = 200.00
Aqui temos mais algumas construções: o exit(1), sair(1), termina o programa. A expressão
tipo not in ['r','i','c'] checa se o tipo não é uma das três letras válidas; “not in” significa não
pertence.
© E.L.Favero Algoritmos em Python 47
E6.2 Ler um valor de salário, sal, e se for maior que 1000 dar um aumento de 10% senão
dar um aumento de 15%. Imprimir o valor do salário, do aumento e o novo salário.
sal=float(input('sal:'))
if sal>1000:
percent=0.10
else:
percent=0.15
aumento=percent*sal
novoSal=sal+aumento
print('sal atual: R$%6.2f' % sal)
print(' aumento: R$%6.2f' % aumento)
print('novo sal : R$%6.2f' % novoSal)
>>>
E6.4 Leia duas variáveis a, b. Leia o operador aritmético:{+,-,*, /}. Calcule o resultado da
operação. Se o operador não existir exiba operador inválido.
a=float(input('a:'))
b=float(input('b:'))
oper=input('o:')
if oper=='+':val=a+b
elif oper=='-':val=a-b
elif oper=='*':val=a*b
elif oper=='/':val=a/b
elif oper=='^':val=a**b
else:
print('operação invalida (+,-,*,/,^)')
exit
print('o valor de %5.2f %s %5.2f = %5.2f' % (a,oper,b,val))
© E.L.Favero Algoritmos em Python 48
>>>
a:3
b:7
o:+
o valor de 3.00 + 7.00 = 10.00
E6.5 Ler os minutos, min, da conta de celular. Se min for menor que 200 o preço é 0.20
de real; senão se min < 400, o preço é 0.18 ao min; senão o preço é 0.15 ao min;
imprima o valor da conta. Um só valor por minuto para toda a conta.
E6.8 Leia a,b,c três valores inteiros e imprima o intermediário. Se os três são diferentes
então temos menor, intermediário e maior. Podemos ter situações com valores
iguais, então o intermediário pode ser igual a valores das pontas.
Capítulo
7 RE-FATORANDO O CÓDIGO
Apresentamos o conceito de abstração, uso de funções, para organizar e
refatorar o código dos programas. Por fim, apresentamos uma discussão do
pensamento computacional sobre um kit mínimo de comandos necessários
na programação.
Sejam as duas figuras geométricas acima. Qual das duas é mais silenciosa? Figura
tem barulho? Tem. Pense um pouco e encontre uma resposta. Até quando refatorar um
código? Até ele ficar silencioso.
Vamos fazer um programa que lê duas variáveis int e mostra o valor da maior delas
(maior ou igual). Se forem iguais mostre uma delas.
Para dificultar mais, agora vamos fazer o mesmo com 3 valores. Ler os 3 valores e dizer
quem é o menor.
def mini(a,b):
if a<b: return a
else : return b
Para usar esta função apresentamos abaixo um programa que le dois valores e chama a
função mini() para escolher o menor. Def define a função que é chamada neste caso dentro
de um comando de atribuição.
Quanto a escrita do código podemos mudar a posição da função, podemos trazer definição
dela no inicio do código, antes da leitura dos valores, como segue.
Utilizamos 2 linhas, uma para cada chamada, para definir quem é o valor mínimo, mas
poderíamos ter usado uma versão do print mais complexa, com menos linhas:
m=mini(mini(x,y),z). Aqui a função mini() está sendo reusada duas vezes, uma dentro da
outra. Uma das grandes vitórias do pensamento computacional é o reuso de fragmentos de
código, pois com isso os códigos ficam mais compactos, mais coesos e mais simples.
Até quando refatorar? Até que o código tende a ser silencioso. O barulho acontece
na mente. A mente humana divide um objeto maior em objetos menores para conquista-los.
Se tenho um quadrado posso dividir em 4 retas, uma reta é um objeto menor, duas verticais
e duas horizontais, etc. Estes pensamentos de dividir são o barulho: a mente ta tagarelando.
Se tenho um círculo, se corto pela metade ficam dois objetos geométricos mais complexos
que o próprio círculo. Então não posso mais dividir: o circulo já é o limite, já é o silencio das
operações mentais. Quais versões dos códigos são mais silenciosas as que usam funções
ou as sem o uso de funções?
Capítulo
8 TIPO LISTA, TUPLA E FAIXA DE
VALORES
Neste capítulo apresentamos listas e tuplas. São os objetos computacionais que estão
associados a estruturas de dados para representação da repetição de elementos
como vetores da matemática. Mostramos o comando chamado “for” para percorrer as
listas. São introduzidos os conceitos de índices positivos, para caminhar para frente e
índices negativos, para caminhar para trás.
8.1 Listas
Uma lista é um conjunto de valores indexados por um número inteiro chamado de índice,
que se inicia em zero. Os elementos contidos em uma lista podem ser de qualquer tipo, até
mesmo outras listas, e não precisam ser todos do mesmo tipo. len() retorna o tamanho da
lista.
>>>lista= ['a','b','c','d','e','f'
>>>len(lista)
7
>>>lista = [1, 2, 3]
>>>len(lista)
3
O índice permite acesso individual aos elementos, bem como permite trabalhar com as
fatias. Com índices negativos caminhamos na lista de trás para frente, onde -1, -2 são o
índice do último e penúltimo elementos.
>>> lista=[5,10,15]
>>> lista[0]
5
>>> lista[1]
10
>>> lista[-1]
© E.L.Favero Algoritmos em Python 54
15
>>>range(10)
range(0, 10)
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list(range(10,0,-1))
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> list(range(0,10,2))
[0, 2, 4, 6, 8]
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(2,10))
[2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(2,10,2)) # só pares
[2, 4, 6, 8]
>>>list(range(1,10,2)) # só impares
[1, 3, 5, 7, 9]
Fatias são segmentos de sublistas. O segmento é acessado por uma faixa de valores.
Numa lista podemos escrever: lista[início:fim]. Como em range(), do início até o fim,
exclusive o fim. :2 denota, 0:2, então é 0 e o 1. Quando não diz o inico é zero. Quando não
diz o fim é até o último, ex. 1:, é tudo a partir do 1.
>>> lista=[5,10,15]
>>> lista[:2]
[5, 10]
>>> lista[1:]
[10, 15]
>>>lista= ['a','b','c','d','e','f','g']
>>>lista[1:4]
['b','c','d']
>>>lista[-6:-3]
['b','c','d']
© E.L.Favero Algoritmos em Python 55
append anexe
remove remove
>>> lista=[5,10,15]
>>> lista[2]=11
>>> lista.append(20)
>>> lista
[5, 10, 11, 20]
>>> lista.remove(10)
>>> lista
[5, 11, 20]
Listas são facilmente percorridas com o comando for. A primeira forma é ver a lista como um
conjunto e com o operador in (pertence) os elementos são acessados: elemento in lista. O
end=' ' dentro do print() diz para colocar um branco depois de cada impressão.
>>>lista = [1, 2, 3]
>>>for i in lista: print(i, end=' ')
1 2 3
A segunda forma de acessar os elementos e a partir de seus índices, extraídos de uma faixa
de valores, range(), que também é como uma lista de indices. Sempre use len(lista) para
definir o fim da lista.
>>>lista = [1, 2, 3]
>>>for i in range(len(lista)): print(lista[i], end=' ')
1 2 3
Estes comandos de linha também podem ser agrupados num programa como ilustrado
abaixo. O print() vazio envia o cursor para a próxima linha.
lista = [1, 2, 3]
for i in lista: print(i, end=',')
print()
for i in range(len(lista)): print(lista[i], end=' ')
>>>
1,2,3,
© E.L.Favero Algoritmos em Python 56
1 2 3
8.5 Tuplas
O tipo tupla é similar a uma lista, mas é imutável, não podemos mudar o valor de seus
elementos. Sintaticamente, uma tupla é similar a uma lista de valores separados por
vírgulas, mas a tupla é delimitada por parênteses. Na tupla, o acesso aos elementos e o
fatiamento segue a mesma sintaxe da lista.
>>>tupla = [1, 2, 3]
>>>len(tupla)
3
>>> tupla1=(20,40,60)
>>> for t in tupla1: print(t, end=' ')
20 40 60
Também o commando for permite percorrer uma tupla, usando a mesma notação que
apresentamos para listas.
>>> tupla1=(20,40,60)
>>> tupla1[2]=0
TypeError: 'tuple' object does not support item assignment
>>> str='abc'
>>> str[1]='B'
TypeError: 'str' object does not support item assignment
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
95, 96, 97, 98, 99]
E8.2 Usando range() defina uma lista com os valores de 80 até 100, inclusive os
extremos.
>>> list(range(80,101))
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
95, 96, 97, 98, 99, 100]
E8.3 Usando range() defina uma lista com os valores de 100 até 80, inclusive os
extremos, em ordem decrescente.
E8.4 Usando range() defina uma lista com os valores de 80 até 100, só os valores
pares.
E8.5 Usando range() defina uma lista com os valores de 80 até 100, só os valores
impares.
E8.6 Usando range() defina uma lista com os valores de 80 até 100, só os valores
pares. E usando um comando for imprima a lista gerada por range().
E8.7 Usando range() defina uma lista com os valores de 80 até 100, só os valores
impares. E usando um comando for imprima a lista gerada por range().
E8.8 Ler um número e imprimir todos os pares até o número lido. Use o comando for.
x=int(input('dig X:'))
for i in range(0,x+1,2):
print(i, end=' ')
print()
>>>
E8.9 Ler um número e imprimir todos os impares até o número lido. Use o comando for.
Capítulo
9 COMANDO DE REPETIÇÃO: FOR
for i in range(0,10):
print ("i=", i, end=' ')
© E.L.Favero Algoritmos em Python 59
print()
>>>
i= 0 i= 1 i= 2 i= 3 i= 4 i= 5 i= 6 i= 7 i= 8 i= 9
No comando for abaixo o laço é interrompido com break: quando o j==7 o break (parar) é
ativado e o comando pára a sua execução. Aqui testamos se o j%2!=0 então o valor é impar.
Note que só os impares são impressos.
for j in range(0,10):
if j % 2!=0: print(j, 'é impar')
if j==7: break
>>>
1 é impar
3 é impar
5 é impar
7 é impar
Idem acima, mas com o novo comando continue. Se j%2==0: continue volta para o início do
laço então não imprime 'é impar'. O break sai totalmente do laço.
for j in range(0,10):
if j>7: break
if j % 2==0:continue
print(j, 'é impar')
>>>
1 é impar
3 é impar
5 é impar
7 é impar
soma=0
for i in range(0,21):
soma = soma+i
print(soma)
>>>
210
Para os próximos exercícios vamos aprender a trabalhar com uma string de dígitos. Por
exemplo, vamos aprender a utilizar a função split(). Aqui introduzimos outra notação
chamada de compreensão de lista, que é baseada numa versão do comando for: y=[int(i)
for i in x]. Todos os strings de x são transformados em int() em y.
A lista de string foi convertida numa lista de int. Int pode ser somado algebricamente. O
split() pode também quebrar na vírgula. Quando usamos soma += i leia-se soma = soma+i.
Este comando += evita de repetirmos o nome da variável soma, para acumular algo com o
comando de atribuição.
Ler uma lista de valores int e somar os valores lidos. Neste caso vamos usar uma função
split() para quebrar o string em valores. E cada valor em dígito deve ser convertido para
numérico.
conta=0
for x in range(0,21):
if x%3==0:
conta = conta+1
print(conta)
>>>
Ler uma lista de valores int e contar quantos são impares. Mostrar a lista lida e a quantidade
de impares. No exemplo abaixo, o '\n’ denota o carctere quebra de linha.
a=int(input('a:'));b=int(input('b:'))
mult=0
print('o resultado de %d * %d=' % (a,b), end=' ' )
for i in list(range(a)):
print('+',b, end=' ')
mult=mult+b
print('é igual:', mult)
>>>
a:4
b:7
o resultado de 4 * 7= + 7 + 7 + 7 + 7 é igual: 28
E9.2 Ler um número e imprimir todos os impares até o número lido. Use o comando for.
x=int(input('dig X:'))
for i in range(1,x+1,2):
print(i, end=' ')
print()
>>>
E9.3 Ler um número e imprimir todos os pares até o número lido. Use o comando for.
for i in range(9,-1,-1):
print(i, end=' ')
>>>
9 8 7 6 5 4 3 2 1 0
E9.5 Imprima a soma dos múltiplos de 7 entre 0 e 1000.
n=int(input('tabua do n:'))
x=1
for x in range(0,11):
print("%d x %d = %d" % (n,x, n*x))
>>>
tabua do n:3
3 x 0 = 0
3 x 1 = 3
3 x 2 = 6
© E.L.Favero Algoritmos em Python 62
3 x 3 = 9
3 x 4 = 12
3 x 5 = 15
3 x 6 = 18
3 x 7 = 21
3 x 8 = 24
3 x 9 = 27
3 x 10 = 30
E9.7 Escreva todos valores de 51 até 100 com quebra linha de 10 em 10 valores. Use
for.
for x in range(51,101):
print(x, end=' ')
if x % 10 ==0: print()
>>>
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100
E9.8 Ler uma lista de supermercado com o produto, a quantidade e o tipo "a2, f6, b20,
c2". Onde produtos são letras de a..f e os valores são desta tabela: {a:10, b:60,
c:40, d:70, e:15, f:100}. Imprimir o boleto na seguinte forma (use um comando
while):
"""
Item qty preço subtotal
a 2 10 20
f 6 100 600
b 20 60 1200
c 2 40 80
___________________
Total 1900 """
for i in range(len(itens)):
subtotal = qti[i]*preco(itens[i])
print(itens[i],qti[i],preco(itens[i]),subtotal)
total += subtotal
print('total:', total)
>>>
['a2', 'f6', 'b20', 'c2']
['a', 'f', 'b', 'c'] [2, 6, 20, 2]
item qti preço subtotal
a 2 10 20
f 6 100 600
b 20 60 1200
c 2 40 80
total: 1900
Três apóstrofos ou três aspas neste programa, delimitam comentários que podem
ser de múltiplas linhas.
Capítulo
10 COMANDO DE REPETIÇÃO: WHILE
Segue abaixo o pseudo código do comando while, aqui chamado de “faça enquanto”.
Diferente do for o programador tem que inicializar a variável de controle do laço (i=0) e
também lembrar de incrementa-la dentro da indentação do laço (i=i+1).
© E.L.Favero Algoritmos em Python 65
Segue abaixo o while definido no Python. O laço de repetição while tem uma estrutura mais
simples que a do comando for. Seu bloco de contexto é definido pela indentação. O que
diferencia o for do while é que o for automaticamente executa uma inicialização e um
incremento. No while fica para o programador fazer a inicialização (i=0) e o incremento
(i=i+1). Um erro comum é esquecer o incremento e então o algoritmo entra em looping (laço
infinito).
i=0
while i<10:
print ("i=", i, end=' ')
i=i+1
print()
>>>
i= 0 i= 1 i= 2 i= 3 i= 4 i= 5 i= 6 i= 7 i= 8 i= 9
O segundo exemplo de while é um laço com True, isto é, “faça enquanto é verdade”, que
roda sempre, neste caso o break é necessário para a parada do laço.
j=0
while True:
if j % 2!=0: print(j, 'é impar')
if j==7: break
j=j+1
>>>
1 é impar
3 é impar
5 é impar
7 é impar
soma=0;i=0
while i <=20:
soma = soma+i
i=i+1
print(soma)
>>>
© E.L.Favero Algoritmos em Python 66
conta=0;i=0
while i<=20:
if i%3==0:
conta = conta+1
i=i+1
print(conta)
>>>
7
Idem mas agora reescrevendo com o comando continue. A estrutura do algoritmo muda um
pouco. Se i%3!=0, for diferente de 0, então não conta. O continue permite executar somente
uma parte dos comandos do bloco.
conta=0;i=0
while i<=20:
i=i+1
if i%3!=0: continue
conta = conta+1
print(conta)
>>>
7
a=int(input('a:'));b=int(input('b:'))
mult=0
print('o resultado de %d * %d=' % (a,b), end=' ' )
while a>0:
print('+',b, end=' ')
mult=mult+b
a=a-1
print('é igual:', mult)
>>>
a:4
b:7
o resultado de 4 * 7= + 7 + 7 + 7 + 7 é igual: 28
a=int(input('a:'));b=int(input('b:'))
conta=0
© E.L.Favero Algoritmos em Python 67
E3.2 Ler um número e imprimir todos os impares até o número lido. Use o comando
while.
x=int(input('dig X:'))
y=1
while y<=x:
print(y, end=' ')
y=y+2
print('fim')
>>>
dig X:9
1 3 5 7 9
E3.3 Ler um número e imprimir todos os pares até o número lido. Use o comando while.
x=9
while x>=0:
print(x, end=' ')
x=x-1
>>>
9 8 7 6 5 4 3 2 1 0
n=int(input('tabua do n:'))
x=0
while x<=10:
print("%d x %d = %d" % (n,x, n*x))
x=x+1
>>>
tabua do n:3
3 x 0 = 0
3 x 1 = 3
3 x 2 = 6
© E.L.Favero Algoritmos em Python 68
3 x 3 = 9
3 x 4 = 12
3 x 5 = 15
3 x 6 = 18
3 x 7 = 21
3 x 8 = 24
3 x 9 = 27
3 x 10 = 30
E3.7 Escreva todos valores de 51 até 100 com quebra linha de 10 em 10 valores. Use
while.
x=51
while x<=100:
print(x, end=' ')
if x % 10 ==0: print()
x=x+1
>>>
51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100
E3.8 Ler uma lista de supermercado com o produto, a quantidade e o tipo "a2, f6, b20,
c2". Onde produtos são letras de a..f e os valores são desta tabela: {a:10, b:60,
c:40, d:70, e:15, f:100}. Imprimir o boleto na seguinte forma:
"""
Item qty preço subtotal
a 2 10 20
f 6 100 600
b 20 60 1200
c 2 40 80
___________________
Total 1900 """
i=0
while i<len(itens):
subtotal = qti[i]*preco(itens[i])
print(itens[i],qti[i],preco(itens[i]),subtotal)
total += subtotal
i=i+1
print('total:', total)
>>>
['a2', 'f6', 'b20', 'c2']
['a', 'f', 'b', 'c'] [2, 6, 20, 2]
item qti preço subtotal
a 2 10 20
f 6 100 600
b 20 60 1200
c 2 40 80
total: 1900
Capítulo
11 FUNÇÕES
Este capítulo aprofunda o conceito de funções, como objetos computacionais.
Apresentamos funções recursivas.
def potencia(base,exp=2):
''' função potencia com exp int opcional '''
if exp==0: return 1
pot=base
for i in range(1,exp): pot=pot*base
return pot
pot=potencia
print(pot(2)) # 4
print(potencia(2,8)) # 256
print(pot(4,3)) # 4*4*4
print(pot.__doc__)
print(pot.__name__)
>>>
4
256
64
função potencia com exp int opcional
potencia
O poder das funções é abstrair fragmentos de cógigo, numa espécie de caixa preta. É dado
um nome para uma sequência de comandos que executa uma funcionalidade.
© E.L.Favero Algoritmos em Python 71
V=[1,2,7,11,23,6]
# Defina a soma dos elementos do vetor use for, sem usar índices
def soma(v):
soma=0;
for i in v:soma = soma+i
return soma
# Defina a soma dos elementos do vetor use for,
# acessando os elementos com índices
def soma1(v):
soma=0;
for i in range(len(v)):soma = soma+v[i]
return soma
Podemos fazer vários aprimoramentos nos códigos, um deles é usar o operador +=. Assim
soma=soma+v, fica soma +=v. Podemos também somar usando while.
Uma função parente da média é o desvio padrão. Seja SS o somatório da diferença de cada
elemento com a média elevada ao quadrado. Assim SS = somatório de (V[i]-med)**2. O
desvio é a raiz(SS/(len(V)).
print(' desv:',desvio(V))
>>>L=list("afghtlmedk")
>>>L
>>> ['a', 'f', 'g', 'h', 't', 'l', 'm', 'e', 'd', 'k']
>>>int('1')
1
>>> str(1)
'1'
Agora vamos devolver dois objetos de uma função, dois vetores. Vamos primeiro mesclar
dois vetores, da forma que se A=list("abcdefg") e B=list("1234567") então
AB=list("a1b2c3d4e5f6g7"). Já a função separa faz o trabalho contrário, neste caso ela
separa as duas listas, o A e o B. Note que o *separa(AB) remove a tupla.
A=list("abcdefg")
B=list("1234567")
AB=list("a1b2c3d4e5f6g7")
print('mescla AB:', mescla(A,B))
print('mescla BA:', mescla(B,A))
Uma forma simples de inverter uma lista é pela manipulação de fatias, assim
reverso(x) = x[::-1]. Mas vamos programar outras formas para exercitar a solução do
problema:
i) rev: iniciar no índice len()-1, até 0, diminuindo de 1; fica range(len(s)-1,-1,-1)
ii) rev1: percorrer a lista com for tirando da cabeça e colocando na cauda
iii)rev2: idem com recursividade, sem o for
def rev(s):
REV=[]
for i in range(len(s)-1,-1,-1):
REV.append(s[i])
return REV
print('rev abcdef:',rev(list('abcdef')))
O append sempre acrescenta um elemento no final da lista. Mas o + é mais flexível podendo
concatenar quaisquer duas listas, assim podemos percorrer a lista do início para o fim e
sempre ir acrescentando na frente. Por fim, vamos fazer uma versão rev2() recursiva.
def rev1(s):
REV=[]
for i in range(len(s)):REV=[s[i]]+REV
return REV
def rev2(s):
if s!=[]: return rev2(s[1:])+[s[0]]
else: return []
Uma função é recursiva se ela se chama a si mesma: na linha do def, ela é definda, e
dentro do seu corpo, ela já é chamada.
Abaixo no Python Tutor vemos que primeiro a função vai se chamando e a lista de
entrada diminui até ficar vazia. As funções recursivas vão se empilhando dentro da maquina
abstrata de execução do Python. Depois de chegar no vazio da lista da entrada as funções
vão gerando o retorno, com as listas parciais invertidas.
© E.L.Favero Algoritmos em Python 74
Com mais dois passos next, vemos o retorno da lista parcial [c,d] invertida, agora [d,c].
Continuando com next as funções são removidas da pilha de execução e o resultado vem
sendo motado, até se chegar em [d,c,b,a]. Para animar funções recursivas no Python Tutor
utilize entradas pequenas de no máximo 5 elementos.
Abaixo temos um teste comparando as três versões de reverse, para mostar que elas geram
o mesmo reultado.
print('rev1 abcdef:',rev1(list('abcdef')))
print('rev2 abcdef:',rev2(list('abcdef')))
li=list("123456")
print(rev(li), '\n', rev1(li),'\n', rev2(li) )
© E.L.Favero Algoritmos em Python 75
Agora com várias versões de reverse vamos programar duas versões da função palíndromo,
a primeira mais fácil de ler, x==rev(x) e a segunda um pouco mais abstrata x==x[::-1].
print(palindromo(list('abcdeedcba')))
print(palindromo(list('12321')))
print(palindromo1(list('12321')))
print(palindromo1(list('123X21')))
As folhas da Bromélia são formadas por espirais, cujos raios pertencem a série de
Fibonacci. A Sequência de Fibonacci é uma série numérica descoberta pelo matemático
Fibonacci: 1, 1, 2, 3, 5, 8, 13, 21, 34, ... Ele mostrou a serie com o exemplo do crescimento
acelerado da população de coelhos, com a fórmula recursiva:
Fo= F1 = 1
Fn = Fn - 1 + Fn - 2
def fibo(n):
if n<=1: return n
else: return fibo(n-1)+fibo(n-2)
E11.1 Faça a função potencia para valores inteiros de base e expoente, use um for
E11.2 Defina a soma dos elementos do vetor, use for, sem usar índices
def soma(v):
soma=0;
for i in v:soma = soma+v
return soma
E11.3 Defina a soma dos elementos do vetor use for, acessando os elementos com índices
def soma1(v):
soma=0;
for i in range(len(v)):soma = soma+v[i]
return soma
E11.5 Defina a função soma dos elementos do vetor use while, sem usar índice, usando
pop().
v=[1,5,7]
print(v); print(v.pop()); print(v)
def soma2(v):
soma=0;
while v: soma += v.pop()
return soma
V=[3,6,9,1,1,3,8]; print(' soma2:',soma2(V))
E11.7 Defina a função média, med1, sem utilizar a função soma (sum)
def med1(v):
s=0;
for i in range(len(v)): s=s+v[i]
return s/len(v)
V=[3,6,9,1,1,3,8]; print(' med1:',med1(V))
def mescla(A,B):
AB=[]
for i in range(len(A)):
AB.append(A[i])
AB.append(B[i])
return ''.join(AB)
A=list("abcdefg")
B=list("1234567")
print('mescla AB:', mescla(A,B))
print('mescla BA:', mescla(B,A))
E11.11 Faça a função reverse usando um for e range: iniciar no índice len()-1, até 0,
diminuindo de 1; fica range(len(s)-1,-1,-1)
def rev(s):
REV=[]
for i in range(len(s)-1,-1,-1):
REV.append(s[i])
return REV
print('rev abcdef:',rev(list('abcdef')))
E11.12 Faça a função reverse: percorrer a lista com for tirando da cabeça e colocando na
futura cauda
def rev1(s):
REV=[]
for i in range(len(s)):REV=[s[i]]+REV
return REV
print('rev abcdef:',rev1(list('abcdef')))
E11.13 Faça a função reverse com recursividade: percorrer a lista tirando da cabeça e
colocando na cauda
def rev2(s):
if s!=[]: return rev2(s[1:])+[s[0]]
else: return []
print('rev abcdef:',rev2(list('abcdef')))
E11.16 Faça a função palindromo sem usar uma lista invertida. Comparando sempre os dois
extremos, em direção ao meio.
Capítulo
12 MÉTODOS DE BUSCA E
ORDENAÇÃO
Estas duas funções existem na linguagem: vi= [4,5,3,7]; 3 in vi; vi.index(3). Mas cuidado que
se perguntamos >>>vi.index(10) resulta em ValueError: 10 is not in list. Vamos reescreve-las
como in1() e index1()
def in1(x,v):
for i in v:
if x==i:return True
return False
def index1(x,v):
for i in range(len(v)):
if x==v[i]:return i
return None
V=[1,3,7,11,23,6]
print('busca 3:',busca(3,V))
print('busca 8:',busca(8,V))
print('busca1 3:',busca1(3,V))
print('in1 3:',in1(3,V))
print('index1 23:',index1(23,V))
>>>
busca 3: True
busca 8: False
busca1 3: 1
in1 3: True
index1 23: 4
def troca1(v,a,b):
temp=v[a];v[a]=v[b];v[b]=temp
return
Note que na troca() temos um return vazio, pois o efeito da troca ocorre sobre a própria lista.
Poderíamos ter colocado return None. Troca atua sobre um vetor, que é mutável, assim o
efeito fica gravado no vetor.
Em algumas linguagens de programação existe uma diferença entre uma função e
procedimento. A função recebe parâmetros e retorna valores ou objetos. Um procedimento
deixa o seu efeito sobre algumas estruturas de dados como no exemplo da troca, sem
retorno de valores.
Agora compreendendo como se troca dois elementos de um vetor podemos fazer um dos
métodos de ordenação chamado bubble sort ou método da bolha. Este método consiste
em testar dois elemento contíguos de um vetor se V[i]>V[i+1] então troca-se o conteúdo
destas duas posições. Varrendo-se o vetor do início até o fim sempre fazendo estas trocas
aos poucos os valores maiores vão para o final e os menores ficam no início. Quando é
possível percorrer o vetor e não for feita nelhuma troca então parar.
def bolhaOrd(V):
trocaOK=True
while trocaOK:
trocaOK=False
for i in range(len(V)-1):
if V[i]>V[i+1]:
V[i],V[i+1]=V[i+1],V[i];
trocaOK=True
return V
S1='blagla';
V=list(S1)
print(''.join(bolhaOrd(V)))
Rodando o método da bolha sobre a lista “blagla” a primeira troca será das letras “la” por
“al”, como ilustrado abaixo no python tutor, ficando “balgal”; depois “lg” por “gl”, etc.
© E.L.Favero Algoritmos em Python 82
Na primeira passage o l que estava na segunda posição vai sendo levado para a 5 posição.
No total são 88 passos (ver abaixo). No passo 61 a lista tá quase ordenada, só falta uma
troca.
print('troca 3 x 4:',troca(V,3,4))
V=[1,3,7,11,23,6]
V1=list(V) # copia da lista V
V2=V[:] # idem, copia a lista V
V3=V[:]
print(' ordena:', ordena(V1))
print('ordena1:', ordena1(V2))
print('ordena2:', ordena2(V3))
Em Python existe a função del V[i] que deleta o elemento i de V. Podemos fazer uma função
ordenad() que pega o imax(), deleta-o, e coloca ele noutra lista aux, que cria a nova lista
ordenada.
© E.L.Favero Algoritmos em Python 84
def imax(v):
M=0;
for i in range(1,len(v)):
if v[M]<v[i]:M=i
return M
def ordenad(v):
aux=[]
while v!=[]:
m=imax(v); aux.append(v[m])
del v[m]
return aux
def ordenad1(v):
aux=[]
while v!=[]:
m=v.index(max(v));aux.append(v[m]); del v[m]
return aux
V=[1,3,7,11,23,6]
V1=V[:];V2=V[:]
print(' ordenad:', ordenad(V1))
print('ordenad1:', ordenad1(V2))
Existe uma pequena diferença entre ordenad() e ordenad1(). Podemos pensar que a
primeira é um pouco mais eficiente, pois quando encontrou o máximo já memorizou o índice
e a segunda depois de encontrar o máximo ainda busca o índice v.index().
Projeto. Crie um vetor aleatório, de randint(), com tamanho 1000 (ver cap 4). Usando os
recursos de tempo, import time, como ilustrado abaixo, compare o tempo das duas funções.
Quanto por cento a primeira é mais rápida?
import time as t
miliseg=t.time
t0 = miliseg() # inicia a contagem do tempo
for i in range(100000):
x=10+10
t1 = miliseg() #fim da contagem de tempo
print(round(t1-t0,4),"milisegundos para fazer 100k somas")
if v[M]<v[i]:M=i
return M
V=[3,6,9,1,1,3,8]; print(' imax:', imax(V))
E12.7 Defina a função busca, que devolve a posição do elemento que está no vetor
def busca1(x,v):
for i in range(len(v)):
if x==v[i]:return i
return None
V=[1,3,7,11,23,6]
print('busca1 3:',busca1(3,V))
E12.8 Defina uma função busca similar ao in, in1(), que diz o elemento está no vetor, use for
def in1(x,v):
for i in v:
if x==i:return True
return False
E12.9 Defina uma função similar ao index() que retorna o índice do elemento no vetor
def index1(x,v):
for i in range(len(v)):
if x==v[i]:return i
return None
V=[1,3,7,11,23,6]
print('index1 23:',index1(23,V))
E12.12 Defina a função troca, que troca dois elementos de um vetor v, índices a,b com
atribuição múltipla
def troca(v,a,b):
v[a],v[b]=v[b],v[a]
© E.L.Favero Algoritmos em Python 86
return
E12.13 Defina a função que troca dois elementos de um vetor v, índices a,b usando uma
variável temporária
def troca1(v,a,b):
temp=v[a];v[a]=v[b];v[b]=temp
return
E12.15 Defina o método de ordenação por seleção direta, usando imax1(j,V) e fazendo troca
com atribuição múltipla; trazendo sempre o máximo para o início da lista sendo
ordenada
def ordena(v):
for i in range(len(v)):
m=imax1(i,v)
v[m],v[i]=v[i],v[m]
return(v)
V=[1,3,7,11,23,6];V1=list(V)
print(' ordena:', ordena(V1))
E12.16 Defina o método de ordenação por seleção direta, usando imax1(j,V) e troca(),
def ordena1(v):
for i in range(len(v)):m=imax1(i,v);troca(v,i,m)
return v
def ordena2(v):
for i in range(len(v)):troca(v,i,imax1(i,v))
return v
V=[1,3,7,11,23,6];V2=V[:];V3=V[:]
print('ordena1:', ordena1(V2))
print('ordena2:', ordena2(V3))
E12.17 Faça a função ordenad() que pega o imax(), deleta-o, e coloca ele noutra lista aux,
que monta a nova lista ordenada.
def imax(v):
M=0;
for i in range(1,len(v)):
if v[M]<v[i]:M=i
return M
def ordenad(v):
aux=[]
while v!=[]:
m=imax(v); aux.append(v[m])
del v[m]
© E.L.Favero Algoritmos em Python 87
return aux
E12.18 Faça a função de seleção direta, de ordenação, ordenad1() usando max() e index()
primitivas do Python
def ordenad1(v):
aux=[]
while v!=[]:
m=v.index(max(v));aux.append(v[m]); del v[m]
return aux
V=[1,3,7,11,23,6];V2=V[:]
print('ordenad1:', ordenad1(V2))
Projeto Nerd (avançado *complexo). Crie um vetor aleatório, de randint(), com tamanho
1000 (ver próximo capítulo sobre matrizes). Usando os recursos de tempo, import time,
como ilustrado abaixo, compare o tempo das funções de ordenação. Qual delas é mais
rápida?
import time as t
miliseg=t.time
t0 = miliseg() # inicia a contagem do tempo
for i in range(100000):
x=10+10
t1 = miliseg() #fim da contagem de tempo
print(round(t1-t0,4),"milisegundos para fazer 100k somas")
© E.L.Favero Algoritmos em Python 88
Capítulo
13 VETORES E MATRIZES
Neste capítulo apresentamos duas estruturas de dados: vetores e matrizes. Estas
estruturas são generalizações da lista e da tupla. Aqui uma lista de dados numéricos é
vista como um vetor. E uma lista de listas como uma matriz.
A distância Euclidiana é uma medida de uma reta entre dois pontos no espaço. Outra
medida é a distância de Manhattan que consiste em seguir os contornos dos quadrados,
unidades de medida. Assim de (0,0) até (6,6) via distância Eucliadiana temos sqrt( (6-0)**2+(
(6-0)**2)= sqrt(72)= 8.48 unidades; e via distância de Manhattan teremos (6-0)+(6-0)=12
unidades (6 na vertical + 6 na horizontal).
© E.L.Favero Algoritmos em Python 89
Diagrama das ruas de uma cidade: a distancia euclidiana é a reta entre os dois pontos; a
distância de Manhattan segue o contorno dos quadrados
As equações podem ser facilmente codificadas em Python numa programação bem abstrata
como consta no quadro acima, num estilo funcional de programação. Para facilitar o
entendimento vamos codificá-las da maneira convencional, de maneira procedural, com
comandos “for” percorrendo os vetores.
Se temos dois vetores X e Y e se seus elementos são x(i) e y(i), então euclD(X,Y)
é a raiz quadrada do somatório dos valores (x(i)-y(i))**2. O sqrt(), raiz quadrada, está na
biblioteca math, mas também pode ser escrita como x**0.5.
Uma biblioteca de funções é similar a uma coleção de livros, mas neste caso os
objetos armazenados são de programação, são funções e classes. O comando from math
import *, importa tudo da biblioteca math.
A função rootX2() representa a norma de um vetor, que também é o seu comprimento. Esta
norma é usada no denominador do coseno. Se u=(a,b,c,d), a rootX2(u) =
sqrt(a*a+b*b+c*c+d*d).
inf=float(1E-20)
def rootX2(x):
aux=0;
for i in range(len(x)):
aux += (x[i])**2
return sqrt(aux)
def cosV(x,y):
aux=0;
for i in range(len(x)):
aux += (x[i]*y[i])
return aux/(inf+float(rootX2(x)*rootX2(y)))
x=[6,1,3,2]
y=[3,1,1,4] # z=2y
z=[6,2,2,8]
© E.L.Favero Algoritmos em Python 91
a=[1,2,1]
b=[3,1,2]
print('coseno a,b:', round(cosV(a,b),2) )
print('coseno x,x:', round(cosV(x,x),2))
print('coseno x,y:', round(cosV(x,y),2))
print('coseno y,z:', round(cosV(y,z),2))
print('euclidiana x,x:', round(euclD(x,x),2))
print('euclidiana y,z:', round(euclD(y,z),2))
>>>
coseno a,b: 0.76
coseno x,x: 1.0
coseno x,y: 0.82
coseno y,z: 1.0
euclidiana x,x: 0.0
euclidiana y,z: 5.2
Pelos resultados podemos ver que coseno(x,x) é sempre 1, não importa quem é o vetor x.
Agora se criamos um vetor z=2*y, coseno(y,z) continua sendo 1. Pois o vetor 2*y tem a
mesma direção de y. Por outro lado, a distância Euclidiana entre x e x é sempre zero,
euclD(x,x) = 0.
Em Python um vetor (array) é uma lista. Mas o que são vetores ou matrizes
multidimensionais? São listas de listas.
Agora que sabemos como gerar uma lista de valores aletórios vamos preencher uma matriz
com valores aletórios. Abaixo criamos uma matriz de 3 linhas por 4 colunas.
Aqui utilizamos outra forma de importação pois vamos utilizar apenas a função
randint. Nesta forma de importação não é necessário o prefixo.
Para efeito didático, cada célula da matriz armazena uma tripla (linha, coluna, valor
aleatório). O valor aleatório é gerado com randint(1,100). Cada linha compreende 4 valores
aleatórios. Mostra-se toda a matriz com um comando for; com outro comando for, mostra-se
como acessar só a diagonal.
Python tem algumas funções poderosas, por exemplo, com zip(*) podemos transpor a
matriz: as linhas viram colunas e vice versa. O resultado do zip(*) são tuplas, cada linha é
uma tupla; com list(zip(* matriz)) as tuplas são convertidas em listas. Com o comando for, a
forma de manipular listas e tuplas é a mesma.
inv=list(zip(* matriz))
for i in range(col):print(inv[i])
>>>
((0, 0, 15), (1, 0, 72), (2, 0, 37))
((0, 1, 91), (1, 1, 33), (2, 1, 17))
((0, 2, 88), (1, 2, 87), (2, 2, 43))
© E.L.Favero Algoritmos em Python 93
Vamos ilustrar o funcionamento do zip(), fecha o zíper. Suponha a e b duas listas. zip
emparelha as duas em duplas, fecha o zíper. O unzip, zip(* ) faz o efeito ao contrário, abre o
zíper. O * transforma uma lista em elementos como argumentos.
>>> a=[1,2,3,4]
>>> b=[7,8,9,10]
>>> list(zip(a,b))
[(1, 7), (2, 8), (3, 9), (4, 10)]
>>> cd=list(zip(a,b))
>>> cd
[(1, 7), (2, 8), (3, 9), (4, 10)]
>>> list(zip(* cd))
[(1, 2, 3, 4), (7, 8, 9, 10)]
Zipper de listas
import random as rd
rd.seed(15)
L=[x for x in range(12)]
print(L)
>>>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Primeiro geramos uma lista L com 12 valores. Agora vamos pegar duas amostra aleatórias
de 3 elementos desta lista L. O zero aleatoriamente foi selecionado nas duas amostras.
>>> rd.sample(L,3)
[3, 0, 8]
>>> rd.sample(L,3)
[11, 0, 2]
© E.L.Favero Algoritmos em Python 94
Agora vamos embaralhar a lista toda. O suffle() destrói a lista original L enquanto que o
sample() não afeta ela. Para mostrar o resultado do shuffle() é necessário mostrar o
conteúdo da lista L. Note que as duas embaralhadas são bem diferentes.
>>> rd.shuffle(L)
>>> L
[7, 6, 4, 11, 8, 9, 1, 5, 2, 10, 0, 3]
>>> rd.shuffle(L)
>>> L
[5, 2, 7, 10, 4, 6, 0, 11, 9, 3, 1, 8]
Capítulo
Neste capítulo apresentamos mais dois tipos de dados do Python: set e dict. Set é
para conjuntos e dict é uma estrutura de dados flexível e sofisticada chamada de
dicionário. Um dict pode ser visto como uma espécie de generalização de listas. Um
dict também pode representar estruturas de dados tipo JSON, que são comuns na
troca de informações, por exemplo, na web.
>>> L=[1,3,1,2,7,1]
>>> len(L)
6
>>> set(L)
{1, 2, 3, 7}
>>> S=set(L)
>>> len(S)
4
>>> S.add(4)
>>> S
{1, 2, 3, 4, 7}
>>> S.remove(3)
>>> S
{1, 2, 4, 7}
>>> 2 in S
True
>>>
>>> S.union({3,8})
{1, 2, 3, 4, 7, 8}
Dicionários e conjuntos são delimitados por {}, mas este símbolo está reservado para
dicionário vazio. Conjunto vazio é igual set(). Os dicionários são estruturas de dados que
permitem mapear uma chave para um valor. Um mapeamento é uma coleção de
associações entre pares de valores, onde o primeiro elemento do par é chamado de chave e
© E.L.Favero Algoritmos em Python 96
DI=dict( [('i', 5), ('c', 7), ('d', 1), ('a', 9), ('n', 5)] )
DI.items()
dict_items([('i', 5), ('c', 7), ('d', 1), ('a', 9), ('n', 5)])
>>> sorted(DI.items())
[('a', 9), ('c', 7), ('d', 1), ('i', 5), ('n', 5)]
>>>DI['c']
7
Podemos também imprimir os itens ordenados pelo valor da chave. Dicionários são
acessados como listas, DI['c'], devolve o valor associado a chave 'c'. Vamos nos aprofundar
num exemplo prático, como calcular a moda de uma lista de itens.
© E.L.Favero Algoritmos em Python 97
D=list('xxaaabbbakjjakjjsjs')
S=set(D)
print('d:',D,'\ns:',S)
>>>
d: ['x', 'x', 'a', 'a', 'a', 'b', 'b', 'b', 'a', 'k', …, 'j', 's']
s: {'j', 'b', 'x', 'k', 's', 'a'}
FD= { 5, 3, 2, 2, 2, 5 }
índice ('j', 'b', 'x', 'k', 's', 'a’)
D=list('xxaaabbbakjjakjjsjs')
S=set(D)
FD={}
for i in S: FD[i]=0
for i in D: FD[i]+=1
print('FD:',FD)
>>>
FD: {'j': 5, 'x': 2, 'k': 2, 's': 2, 'a': 5, 'b': 3}
Esta estrutura resultante FD chama-se dicionário, como uma lista de itens, pares
(chave:valor), (key:value). Neste FD para pegar a moda, o item mais frequente, ou um dos
itens mais frequentes, podemos, por exemplo, ordenar os pares (key:valor) pelo campo
valor. Segue três opções de ordenar um dicionário com sorted(). Na primeira só utilizamos
as chaves; na segunda os itens são ordenados pelo primeiro campo, a chave; na terceira os
itens ordenados pelo campo valor.
>>> sorted(FD)
['a', 'b', 'j', 'k', 's', 'x']
>>>sorted(FD.items())
[('a', 5), ('b', 3), ('j', 5), ('k', 2), ('s', 2), ('x', 2)]
>>>sorted(FD.items(), key=lambda x: x[1])
[('x', 2), ('k', 2), ('s', 2), ('b', 3), ('j', 5), ('a', 5)]
A função lambda x:x[1] pega de cada tupla o valor do índice 1, e.g. em x=('k', 2) x[0]='k' e
x[1]=2.
BOX: Uma função lambda é bem similar a uma função def, mas ela é uma espécie
de mini função, que pode ser definida dentro de uma expressão, dentro de parte de
© E.L.Favero Algoritmos em Python 98
um comando. Uma função def deve ser definida dentro de um bloco de comandos,
numa indentação. Acima exemplificamos a definição de uma função lambda dentro
do argumento de sorted(). Abaixo exemplificamos como podemos definir uma
mesma função, com lambda e com def.
soma=lambda x,y:x+y
mult=lambda x,y:x*y
print(soma(3,5), mult(7,9))
print(soma1(3,5), mult1(7,9))
>>>
8 63
8 63
A função lambda não tem o return; o retorno dela é a expressão após os dois
pontos. Podemos aplica-la diretamente nos argumentos, usando-se ela entre
parênteses:
>>> s = {1,2,4,5,6}
>>> dict.fromkeys(s, 0)
{1: 0, 2: 0, 4: 0, 5: 0, 6: 0}
Agora vamos codificar uma função freq() que calcula a frequência dos elementos de uma
lista. A função moda() faz uso da freq().
>>> D=list('xxaaabbbakjjakjjsjs')
>>> moda(D)
'j'
>>> moda(list("abcccdddkkkkkiijjj"))
'k'
acesso direto aos elementos, é eficiente. Como estrutura de dados, o poder de astração
do dicionário foi ilustrado na programação da função moda: usa uma função auxiliar freq(),
com duas linhas de código; na primeira linha, inicializa todos os itens do dicionário com zero
frequência; na segunda linha, com um comando for acumula as frequências; por fim, a
função moda ordena o dicionário das frequências dos termos e pega o último elemento que
contém o valor da moda. Solução simples e elegante.
Um dicionário pode ser salvo num arquivo texto como um objeto JSON-
JavaScript Object Notation. Esta notação é muito usada para intercambio de dados entre
diferentes plataformas de computação. O uso do JSON é exemplificado abaixo.
"""
Item qty preço subtotal
a 2 10 20
f 6 100 600
b 20 60 1200
c 2 40 80
___________________
Total 1900 """
Vamos tira o if/elif/else e colocar um dicionário. Então a função preço se rescreve com o
dicionário preço.
def preco(x):
'''{a:10, b:60, c:40, d:70, e:15, f:100}'''
if x=='a': p=10
elif x=='b': p=60
elif x=='c': p=40
elif x=='d': p=70
elif x=='e': p=15
elif x=='f': p=100
else: p=None
return p
total = 0
A estrutra de dicionário permite retornar o preço de cada item a partir da chave, do código,
que é a letra do produto. Agora temos que usar assim preco[itens[i]] antes era preco(itens[i]).
A função é com parênteses e o dicionário com colchete.
print(itens,qti)
total = 0
print('item qti preço subtotal')
for i in range(len(itens)):
subtotal = qti[i]*preco[itens[i]]
print(itens[i],qti[i],preco[itens[i]],subtotal)
total += subtotal
print('total:', total)
>>>
['a2', 'f6', 'b20', 'c2']
['a', 'f', 'b', 'c'] [2, 6, 20, 2]
item qti preço subtotal
a 2 10 20
f 6 100 600
b 20 60 1200
c 2 40 80
total: 1900
Três apóstrofos ou três aspas neste programa, delimitam comentários que podem ser de
múltiplas linhas.
import json
carro = {}
carro['marca'] = 'Global'
carro['modelo'] = 'Fechado'
carro['ano'] = 1978
print(carro)
str_carro=json.dumps(carro)
print(repr(str_carro))
carro1=json.loads(str_carro)
print(carro1)
>>>
{'marca': 'Global', 'modelo': 'Fechado', 'ano': 1978}
'{"marca": "Global", "modelo": "Fechado", "ano": 1978}'
{'marca': 'Global', 'modelo': 'Fechado', 'ano': 1978}
Acima, no primeiro print temos a saída do dict do Python. No segundo print usando
json.dumps() convertemos o carro (dict) num string, por exemplo, para ser gravado num
arquivo ou enviado via web. repr mantém os apóstrofos na escrita. json.loads() transforma o
string num objeto dict. No terceiro print, carro1 foi carregado a partir do string. loads pode
ser usado, por exemplo, quando lemos um json como string de um arquivo para ser
trabalhado como dict.
© E.L.Favero Algoritmos em Python 101
Nesta estrutura existem dois campos txt. O primeiro txt: 'O valor da expressão:' é valido para
todas as questões. O segundo é especifico de cada uma delas, definindo o final do
enunciado, e.g. txt:'>>> 2**3'. O campo alter define as alternativas de respostas para a
múltipla escolha (4 opções), sendo que a última opção é a resposta correta. Os dados de
QUE1 são acessados via chaves QUE1[chave][chave], por exemplo, QUE1[meta][cap]= '2',
seguem alguns testes.
>>>print(QUE1[meta])
{'tipo': 'MM', 'cap': '2', 'grau': 'F', 'tema': 'expressões
aritméticas'}
>>>print(QUE1[meta][cap])
2
>>>print(QUE1[que][4])
{'txt': '>>> float(2 // 3)', 'alter': [0.0, 6.0, 8, 27, 0.0]}
Note que no print todos os nomes de campos são apostrofados. Foi por isso que no início do
código fizemos um mapeamento key='key', meta='meta', etc. visando não precisar escrever
tantos apóstrofos no código da programação.
© E.L.Favero Algoritmos em Python 102
Para facilitar a manipulação dos dados vamos definir duas funções, temaQQ() e renderQQ().
A primeira simplesmente devolve o tema de QUE1; enquanto que a segunda renderiza,
transforma QUE1 numa lista de questões.
Com estas questões renderizadas podemos aplicar diferentes mini provas para diferentes
usuários, tipo 3 questões por prova.
Projeto. Faça um programa a partir do código acima que exiba a prova com três questões
aleatórias mostrando as opções; peça para entrar as três respostas, no formato ‘1b 2d 3e’,
quebre a string e cheque o número de respostas corretas, comparando a opção com alter[-
1]. Defina algumas funções auxiliares, como escreveQue(prova1[1]) que escreve uma das
três questões de uma prova; escreveAlter(prova1[1][1][:-1]) para escrever as alternativas de
uma questão, etc. Assim o código ficará limpo e organizado.
Capítulo
15 PERFORMANCE DE FUNÇÕES
Mostramos várias alternativas de codificação da função fatorial e como escolher a
melhor delas. Com comandos for, while, com recursividade e com reduce.
L=[0,1,2,6,8,20]
def fatf(n):
if n==0: return 1
res=1
for i in range(2,n+1):
res=res*i
return res
print('fatorial com for:')
for i in L: print('Fat de %d é %d' % (i,fatf(i)))
def fatw(n):
num = 1
while n >= 1:
num = num * n
n = n - 1
return num
print('fatorial com while:')
for i in L: print('Fat de %d é %d' % (i,fatw(i)))
def fatr(n):
if n==0: return 1
return n*fatr(n-1)
print('fatorial com recursividade:')
for i in L: print('Fat de %d é %d' % (i,fatr(i)))
>>>
fatorial com for:
© E.L.Favero Algoritmos em Python 105
Fat de 0 é 1
Fat de 1 é 1
Fat de 2 é 2
Fat de 6 é 720
Fat de 8 é 40320
Fat de 20 é 2432902008176640000
…
Temos mais três versões. Estas são para quem gosta do paradigma de programação
funcional, as três usam a função reduce(). Na primeira colocamos uma função mult()
definida com def; na segunda mult() é definida como uma função lambda() e na terceira
mult() vem de uma biblioteca de operadores, codificada em C.
Para entender como funcionam estas diferentes formas de fazer a multiplicação, vamos
inspecionar o código assembler, código da maquina vitual do Python, byte code. Usa-se a
função dis() (disassembler). Podemos ver que as duas funções def mult() e lambda x,y: x*y,
produzem o mesmo código assember (byte code).
tudo até para colecionar nomes de funções, que são objetos de trabalho dos
programadores.
import time as t
miliseg=t.time
def testa(f):
t0 = miliseg()
for i in range(100000): f(40)
t1 = miliseg()
print (round(t1-t0,4), "mili seg:", f, f(7))
for f in [fatf,fatw,fatr,fatt, fatt2,fatt3]: testa(f)
>>>>
0.469 mili seg: <function fatf at 0x03E12660> 5040
0.7979 mili seg: <function fatw at 0x0406A078> 5040
1.2064 mili seg: <function fatr at 0x0406A0C0> 5040
0.8138 mili seg: <function fatt at 0x0406A150> 5040
0.8138 mili seg: <function fatt2 at 0x0406A198> 5040
0.4867 mili seg: <function fatt3 at 0x0406A1E0> 5040
A função testa() executa o código 100.000 vezes para dar mais estabilidade no tempo
medido. Pois, se medimos com tempos pequenos a precisão diminui. A versão de pior
desempenho foi a recursiva. As melhores foram a primeira e a última, com for e a funcional
com a multiplicação codificada na biblioteca de operadores.
Capítulo
16 APLICAÇÃO DE CÁLCULO
NUMÉRICO
Esta série pode ser escrita como h(n)=sum([1/i for i in range(1,n+1)]); para range(1,n+1),
pois o intervalo final é aberto. Vamos apresentar três versões: com sum() sobre uma lista,
com for e com while.
print('h1(10**7)=', h1(10**7))
print('h2(10**7)=', h2(10**7))
>>>
h(10**4)= 9.787506036044348
h1(10**7)= 16.69531126585727
h2(10**7)= 16.69531126585727
Logo:
A equação de aproximação dos termos é dada acima. Ela pode ser codificada como x1=x0-
f(x0)/df(x0). Devemos notar aqui a elegância da definição da função f e de sua derivada df
como duas funções lambda.
erro=1e-10
f =lambda x,y: x**2-y
df=lambda x: 2*x
def raiz2(N):
x0 = N/2
delta=1000
while delta>erro:
x1 = x0-f(x0,N)/df(x0)
delta= abs(x1-x0)
print(x1, delta)
x0=x1
return x1
6.014705882352941 2.485294117647059
5.501240471738818 0.5134654106141232
5.477277991889814 0.023962479849004126
5.477225575302472 5.241658734167487e-05
5.477225575051661 2.5081092758227896e-10
5.477225575051661 0.0
raiz de 30 5.477225575051661 5.477225575051661
'''
Esta fórmula pode ser escrita como a1=(ao+N/a0)/2. Vamos assumir que o valor inicial é
N/2. Assim na primeira iteração a0=N/2. Depois a0=a1, prosseguindo até a convergência
com dez casas decimais, um erro=1e-10.
erro=1e-10
def raiz(N):
a0 = N/2
delta=1000
while delta>erro:
a1=(a0+N/a0)/2
delta=abs(a0-a1)
print(a1, delta)
a0=a1
return a1
def fat(n):
ft=1;
for i in range(2,n+1): ft *= i;
return ft
def e(x):
XYZ=[]
erro=1e-10
e0=1+x;i=2
delta=1000
while delta>erro:
e1= e0 + pow(x,i)/fat(i)
i+=1
delta=abs(e1-e0)
e0=e1
print(e1, delta)
XYZ.append((i,e1,delta))
return e1,XYZ
import math
PI=math.pi
# math.exp(math.pi) : 23.1406926328
print('fat:', fat(2), fat(5), fat(7));
e1,XYZ=e(PI)
print('e(PI):', e1, math.exp(PI))
[X,Y,Z]=list(zip(* XYZ))
>>>
fat: 2 120 5040
9.076394854134472 4.934802200544679
14.244107634184441 5.167712780049969
18.30281976060121 4.0587121264167685
...
23.140692632767177 7.700862170167966e-11
e(PI): 23.140692632767177 23.140692632779267
© E.L.Favero Algoritmos em Python 112
Abaixo temos o gráfico plotado pelas linhas de código do programa. Salvamos na variável
XYZ, lista de triplas, os valores para gerar o gráfico. Com list(zip(*)) eles foram
desempacotados para os três vetores, um para cada dimensão.
© E.L.Favero Algoritmos em Python 113
Capítulo
Nesta tabela temos as operações sobre os bits que são ilustradas com o programa a seguir.
Nele vamos definir duas constantes a e b e exemplificar uma operação para cada operador.
Vamos trabalhar com 8 bits ou um byte para ilustrar as operações. 8 bits é um byte. Temos
algumas funções para imprimir os valores utilizando uma formatação que permite a
visualização das duas listas de bits uma sobre a outra. Para um leitor iniciante, as funções
abaixo são complexas, sugerimos apenas uma leitura superficial; a complexidade vem do
comando de formatação format() que serve para alinhar colunas de números, ver web.
a = int('00111100',2)
b = int('00001101',2)
def bi(x):
if x>=0: return '{:>0{}b}'.format(x,8)
else : return '{:>0{}b}'.format( abs(abs(x)-(1<<8)),8)
© E.L.Favero Algoritmos em Python 114
prt('a',a);prt_('b',b);prt('and a&b',a&b);print()
prt('a',a);prt_('b',b);prt('or a|b',a|b);print()
prt('a',a);prt_('b',b);prt('xor a^b',a^b);print()
prt_('a',a);prt('not ~a',~a);print()
prt_('a',a);prt('a << 2',a<<2);print()
prt_('a',a);prt('a >> 2',a>>2);print()
O efeito das operações binárias (& | ^) é fácil de visualizar quando os dois operandos são
mostrados um em cima do outro. O and só é 1 se ambos os bits são 1. O or é 1 se um deles
é 1. O and busca zerar e o or ao contrário tenta fazer tudo 1. O xor é 1 somente onde os bits
são diferentes.
a= 00111100 60
______b= 00001101 13
and a&b= 00001100 12
a= 00111100 60
______b= 00001101 13
or a|b= 00111101 61
a= 00111100 60
______b= 00001101 13
xor a^b= 00110001 49
As operações unarias (~ >> <<) tem um só operando, neste caso estamos exemplificando
com o operando a. O not simplesmente inverte os bits. Como valor inteiro ele troca de sinal.
Nesta situação foi necessário fazer alguns ajustes em bi() para acomodar a impressão de
valores negativos como complemento de 2´s. O deslocamento para esquerda multiplica por
2, se for duas vezes multiplica por 4 e para a esquerda divide por 2, se for duas vezes divide
por 4.
______a= 00111100 60
not ~a= 11000011 -61
______a= 00111100 60
a << 2= 11110000 240
______a= 00111100 60
a >> 2= 00001111 15
def primo(n):
PRI =[True]*n
PRI[0:2]=[False,False]
for i in range(2,n):
if PRI[i]:
for j in range(i*i,n,i):PRI[j]=False
return [i for i in range(len(PRI)) if PRI[i]==True]
#
>>> primo(100)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, …, 79, 83, 89, 97]
>>> 23<<1
46
>>> 23*2
46
>>> bin(1)
'0b1'
>>> bin(1<<5)
'0b100000'
>>> 1<<5
32
bin(1<<2)
'0b100'
© E.L.Favero Algoritmos em Python 116
Aqui podemos ver como funcionam as operações sobre bits. O shift left <<1 de uma posição
equivale a multiplicar por 2: 23<<1=46=23*2. O 1<<5 é o mesmo que 2**5, é o mesmo que
ligar o bit na posição 5 (da direita para a esquerda começando por 0). Com este esquema é
fácil ligar somente um bit de uma posição, por exemplo, (1<<32) liga o bit 32. Se fazemos
bin((1<<5)-1) nós ligamos todos os 5 bits – o menos um força todos para 1, na
representação complemento de 2. Se numa lista de uns, fazemos um shift para a esquerda
<< acrescentamos zeros na direita
Aqui estamos trabalhando com inteiros, que são também negativos. Se na
representação binária tem 1 no início são inteiros negativos. Então valem os conceitos
sobre a representação dos valores binários negativos mencionados no capítulo 1, sobre
complemento de 2.
>>> 1<<32
4294967296
>>> bin(1<<32)
'0b100000000000000000000000000000000'
>>> bin((1<<5)-1)
'0b11111'
bin((1<<7)-1)
'0b1111111'
>>> bin(((1<<7)-1)<<3)
'0b1111111000'
O crivo inicialmente assume que todos são primos exceto o 1 e o 2. Podemos inicializar um
vetor de bits, zerando as duas primeiras posições do 1 e do 2. Usando as técnicas
mostradas vamos criar uma lista de uns, com as duas primeiras posições da direita zeradas.
>>> limit=32
>>> bits = ((1 << (limit - 2)) - 1) << 2
>>> bin(bits)
'0b11111111111111111111111111111100'
A função rangeBit() define um padrão como se fosse um for sobre uma cadeia de bits,
ligando só os correspondentes, só os pares, só os múltiplos de 3, 5, 7 etc. O objetivo é
eliminar os múltiplos de um número primo. nZeros indica quantos zeros a direita devem ser
preenchidos.
print(bin(rangeBit(10,2,40))[-40:])
print(bin(rangeBit(20,2,40))[-40:])
print(bin(rangeBit(10,4,40))[-40:])
>>>
0101010101010101010101010101010000000000
0101010101010101010100000000000000000000
0100010001000100010001000100010000000000
© E.L.Favero Algoritmos em Python 117
for i in [2,3,5,7]:
bi=rangeBit(i,i,32)
print(i, bin(bi)[-32:])
>>>
2 01010101010101010101010101010100
3 01001001001001001001001001001000
5 01000010000100001000010000100000
7 00010000001000000100000010000000
A nova solução primoBit envolve um misto de operações aritméticas com operações sobre
bits. Com rangeBit() pode-se recodificar a função que gera os primos pelo crivo de
Eratostenes. Aqui o vetor de True e False é um vetor de bits simulado sobre um valor inteiro
com precisao “infinita”. O infinita está entre aspas pois na prática sempre será finita, mas em
Python um inteiro pode ser muito longo.
Um bit para cada primo é muito menos espaço. Se um Bool for 4 bytes, 32 bits, a
economia de espaço e de 32 vezes.
import time as t
miliseg=t.time
def testa(fun,I):
t0 = miliseg()
print(list(fun(100000))[-10:]) # escreve os 10 ultimos
#print(max(fun(I))) # escreve o último
t1 = miliseg()
print ('tempo:',round(t1-t0,4),fun)
def primoBit(limit=10000):
PRI=[2]
raiz_limit = int(limit**0.5)
vetBits = ((1 << (limit - 2)) - 1) << 2
# caminha sobre os impares
for i in range(3, limit, 2):
if not (vetBits & (1 << i)):continue
PRI.append(i)
# exclui todos os múltiplos de um primo i
if i <= raiz_limit:
vetBits &= ~rangeBit(i * i, i*2, limit)
return PRI
testa( primoBit, 100000)
testa( primo, 100000)
>>>
[99877, 99881, 99901, 99907, 99923, 99929, 99961, 99971, 99989,
99991]
tempo: 0.3005 <function primoBit at 0x03DB52F8>
[99877, 99881, 99901, 99907, 99923, 99929, 99961, 99971, 99989,
99991]
tempo: 0.066 <function primo at 0x03DB5220>
A mais convencional primo foi mais eficiente em termos de tempo, 5x mais rápida.
Mas ganhou em espaço. Neste caso economizamos de colocar todos os primos a
serem gerados numa lista, que também ocuparia muito espaço. Rodando a função
primoBit() para 100000 ela retorna que o max() primo é 99991.
© E.L.Favero Algoritmos em Python 118