Subprogramação Loana Tito [email protected] O que vimos até agora Programas usam apenas sequência, repetição e decisão Capacidade de resolver diversos problemas, mas difícil de resolver problemas grandes } } } 2 Em diversas situações, é necessário repetir o mesmo trecho de código em diversos pontos do programa Exemplo 1 a = [1, 2, 3, 4, 5] soma = 0 for i in range(len(a)): soma = soma + a[i] media = soma/len(a) print(media) b = [10, 20, 30, 40] soma = 0 for i in range(len(b)): soma = soma + b[i] media = soma/len(b) print(media) 3 Exemplo 1 a = [1, 2, 3, 4, 5] soma = 0 for i in range(len(a)): soma = soma + a[i] media = soma/len(a) print(media) b = [10, 20, 30, 40] soma = 0 for i in range(len(b)): soma = soma + b[i] media = soma/len(b) print(media) 4 Trecho se repete 2 vezes Problemas desta “repetição” Programa muito grande, porque tem várias “partes repetidas” Erros ficam difíceis de corrigir (e se eu esquecer de corrigir o erro em uma das N repetições daquele trecho de código?) } } 5 Solução: subprogramação } } } Definir o trecho de código que se repete como uma “função” que é chamada no programa A função é definida uma única vez, e chamada várias vezes dentro do programa Antes: um programa gigante Programa Principal } Depois: vários programas menores Programa Principal Função A Função C Função B Voltando ao Exemplo 1 def calcula_media(v): soma = 0 for i in range(len(v)): Definição da soma = soma + v[i] função media = soma/len(v) return media a = [1, 2, 3, 4, 5] print(calcula_media(a)) Chamada da função b = [10, 20, 30, 40] print(calcula_media(b)) Chamada da função Vantagens Economia de código } } Quanto mais repetição, mais economia Facilidade na correção de defeitos } } Corrigir o defeito em um único local Legibilidade do código } } } Podemos dar nomes mais intuitivos a blocos de código É como se criássemos nossos próprios comandos Melhor tratamento de complexidade } } } 8 Estratégia de “dividir para conquistar” nos permite lidar melhor com a complexidade de programas grandes Abordagem top-down ajuda a pensar! Fluxo de Execução ... ... a() ... ... ... c() ... ... def a(): ... ... b() return ... def c(): ... ... return ... def b(): ... ... return ... Fluxo de Execução ... ... a() ... ... ... c() ... ... def a(): ... ... b() return ... def c(): ... ... return ... def b(): ... ... return ... Fluxo de Execução ... ... a() ... ... ... c() ... ... def a(): ... ... b() return ... def c(): ... ... return ... def b(): ... ... return ... Fluxo de Execução ... ... a() ... ... ... c() ... ... def a(): ... ... b() return ... def c(): ... ... return ... def b(): ... ... return ... Fluxo de Execução ... ... a() ... ... ... c() ... ... def a(): ... ... b() return ... def c(): ... ... return ... def b(): ... ... return ... Fluxo de Execução def calcula_media(v): soma = 0 for i in range(len(v)): soma = soma + v[i] media = soma/len(v) Execução começa no primeiro return media comando que a = [1, 2, 3, 4, 5] está fora de print(calcula_media(a)) uma função b = [10, 20, 30, 40] print(calcula_media(b)) Fluxo de Execução def calcula_media(v): soma = 0 for i in range(len(v)): soma = soma + v[i] media = soma/len(v) return media a = [1, 2, 3, 4, 5] print(calcula_media(a)) b = [10, 20, 30, 40] print(calcula_media(b)) Fluxo de Execução def calcula_media(v): soma = 0 for i in range(len(v)): soma = soma + v[i] media = soma/len(v) return media a = [1, 2, 3, 4, 5] print(calcula_media(a)) b = [10, 20, 30, 40] print(calcula_media(b)) Fluxo de Execução def calcula_media(v): soma = 0 for i in range(len(v)): soma = soma + v[i] media = soma/len(v) return media a = [1, 2, 3, 4, 5] print(calcula_media(a)) b = [10, 20, 30, 40] print(calcula_media(b)) Fluxo de Execução def calcula_media(v): soma = 0 for i in range(len(v)): soma = soma + v[i] media = soma/len(v) return media a = [1, 2, 3, 4, 5] print(calcula_media(a)) b = [10, 20, 30, 40] print(calcula_media(b)) Fluxo de Execução def calcula_media(v): soma = 0 for i in range(len(v)): soma = soma + v[i] media = soma/len(v) return media a = [1, 2, 3, 4, 5] print(calcula_media(a)) b = [10, 20, 30, 40] print(calcula_media(b)) Fluxo de Execução def calcula_media(v): soma = 0 for i in range(len(v)): soma = soma + v[i] media = soma/len(v) return media a = [1, 2, 3, 4, 5] print(calcula_media(a)) b = [10, 20, 30, 40] print(calcula_media(b)) Fluxo de Execução def calcula_media(v): soma = 0 for i in range(len(v)): soma = soma + v[i] media = soma/len(v) return media a = [1, 2, 3, 4, 5] print(calcula_media(a)) b = [10, 20, 30, 40] print(calcula_media(b)) Declaração de Função def nome_funcao (parametro, parametro, ..., parametro): <comandos> [return <variável ou valor>] Exemplo: def calcula_media(v): soma = 0 for i in range(len(v)): soma = soma + v[i] media = soma/len(v) return media Exemplo def calcula_tempo(velocidade, distancia): tempo = distancia/velocidade return tempo def calcula_distancia(velocidade, tempo): distancia = velocidade * tempo return distancia t = calcula_tempo(10, 5) print(t) d = calcula_distancia(5, 4) print(d) 23 Importante lembrar 24 Escopo de Variáveis } Variáveis podem ser locais ou globais } Variáveis locais } } } } Declaradas dentro de uma função São visíveis somente dentro da função onde foram declaradas São destruídas ao término da execução da função Variáveis globais } } Declaradas fora de todas as funções São visíveis por TODAS as funções do programa Exemplo: variáveis locais def calcula_tempo(velocidade, distancia): tempo = distancia/velocidade return tempo def calcula_distancia(velocidade, tempo): distancia = velocidade * tempo return distancia t = calcula_tempo(10, 5) print(t) d = calcula_distancia(5, 4) print(d) 26 Exemplo: parâmetros também se comportam como variáveis locais def calcula_tempo(velocidade, distancia): tempo = distancia/velocidade return tempo def calcula_distancia(velocidade, tempo): distancia = velocidade * tempo return distancia t = calcula_tempo(10, 5) print(t) d = calcula_distancia(5, 4) print(d) 27 Exemplo: variáveis globais def calcula_tempo(velocidade, distancia): tempo = distancia/velocidade return tempo def calcula_distancia(velocidade, tempo): distancia = velocidade * tempo return distancia t = calcula_tempo(10, 5) print(t) d = calcula_distancia(5, 4) print(d) 28 Uso de Variáveis Globais x Variáveis Locais } Cuidado com variáveis globais } } Dificultam o entendimento do programa Dificultam a correção de erros no programa } } Se a variável pode ser usada por qualquer função do programa, encontrar um erro envolvendo o valor desta variável pode ser muito complexo Recomendação } Sempre que possível, usar variáveis LOCAIS e passar os valores necessários para a função como parâmetro Uso de Variáveis Globais } } Variáveis globais podem ser acessadas dentro de uma função Se for necessário altera-las, é necessário declarar essa intenção escrevendo, no início da função, o comando global <nome da variável> 30 Exemplo: variáveis globais acessadas na função def maior(): if a > b: return a else: return b a = 1 b = 2 m = maior() print(m) 31 Péssima prática de programação! Exemplo: variável global modificada na função def maior(): global m if a > b: m = a else: m = b m = 0 a = 1 b = 2 maior() print(m) 32 Péssima, péssima, péssima prática de programação! Sem uso de variáveis globais: muito mais elegante! def maior(a, b): if a > b: maior = a else: maior = b return maior a = 1 b = 2 m = maior(a, b) print(m) 33 Vejam que agora a e b são parâmetros. Os parâmetros também poderiam ter outros nomes (exemplo, x e y) Passagem de Parâmetro } } Quando uma função é chamada, é necessário fornecer um valor para cada um de seus parâmetros Isso por ser feito informando o valor diretamente } } t = calcula_tempo(1, 2) ou; Usando o valor de uma variável } t = calcula_tempo(v, d) Passagem de Parâmetro def calcula_tempo(velocidade, distancia): tempo = distancia/velocidade return tempo velocidade distancia tempo def calcula_distancia(velocidade, tempo): distancia = velocidade * tempo return distancia velocidade tempo distancia v = 10 t = calcula_tempo(v, 5) print(t) d = calcula_distancia(v, t) print(d) v t d Passagem de Parâmetro def calcula_tempo(velocidade, distancia): tempo = distancia/velocidade return tempo def calcula_distancia(velocidade, tempo): distancia = velocidade * tempo return distancia v = 10 t = calcula_tempo(v, 5) print(t) d = calcula_distancia(v, t) print(d) 10 v t d Passagem de Parâmetro def calcula_tempo(velocidade, distancia): tempo = distancia/velocidade 10 return tempo 5 velocidade distancia tempo def calcula_distancia(velocidade, tempo): distancia = velocidade * tempo return distancia v = 10 t = calcula_tempo(v, 5) print(t) d = calcula_distancia(v, t) print(d) 10 v t d Passagem de Parâmetro def calcula_tempo(velocidade, distancia): tempo = distancia/velocidade 10 return tempo 5 0.5 velocidade distancia tempo def calcula_distancia(velocidade, tempo): distancia = velocidade * tempo return distancia v = 10 t = calcula_tempo(v, 5) print(t) d = calcula_distancia(v, t) print(d) 10 0.5 v t d Tipos de passagem de Parâmetro } Por valor: o valor da variável na chamada é copiado para a variável da função } } Alterações não são refletidas na variável original Por referência: o endereço de memória é copiado para a variável da função } Alterações são refletidas na variável original Passagem de Parâmetro por Valor } Python usa passagem de parâmetro por valor } } } Faz cópia do valor da variável original para o parâmetro da função Variável original fica preservada das alterações feitas dentro da função Contudo vetores (ou objetos) funcionam de forma diferente, pois o que é copiado é o endereço do vetor, e portanto qualquer alteração é refletida no programa principal 40 Exemplo def calcula_tempo(velocidade, distancia): tempo = distancia/velocidade velocidade = 0 return tempo def calcula_distancia(velocidade, tempo): distancia = velocidade * tempo return distancia v = 10 t = calcula_tempo(v, 5) print(v) print(t) d = calcula_distancia(v, t) print(d) O valor impresso por print(v) será 10 ou 0? Exemplo def maior(vetor): vetor.sort() return vetor[len(vetor)-1] v = [5, 4, 3, 2, 1] print(v) m = maior(v) print(m) print(v) 42 O que será impresso na tela? Exemplo de função sem retorno def imprime_asterisco(qtd): for i in range(qtd): print(’*********************’) imprime_asterisco(2) print(’PROGRAMAR EH LEGAL’) imprime_asterisco(2) Chamada de função } Se a função retorna um valor, pode-se atribuir seu resultado a uma variável m = maior(v) } Se a função não retorna um valor (não tem return), não se deve atribuir seu resultado a uma variável (se for feito, variável ficará com valor None) imprime_asterisco(3) Função sem parâmetro } } } Nem toda função precisa ter parâmetro Nesse caso, ao definir a função, deve-se abrir e fechar parênteses, sem informar nenhum parâmetro O mesmo deve acontecer na chamada da função 45 Exemplo def menu(): print('***************************') print('1 - Somar') print('2 - Subtrair') print('3 - Multiplicar') print('4 - Dividir') print('***************************') menu() opcao = eval(input('Digite a opção desejada: ')) 46 Parâmetros default } Em alguns casos, pode-se definir um valor default para um parâmetro. Caso ele não seja passado na chamada, o valor default será assumido. } Exemplo: uma função para calcular a gorjeta de uma conta tem como parâmetros o valor da conta e o percentual da gorjeta. No entanto, na grande maioria dos restaurantes, a gorjeta é sempre 10%. Podemos então colocar 10% como valor default para o parâmetro percentual_gorjeta 47 Exemplo da gorjeta def calcular_gorjeta(valor, percentual=10): return valor * percentual/100 gorjeta = calcular_gorjeta(400) print('O valor da gorjeta de 10% de uma conta de R$ 400 eh', gorjeta) gorjeta = calcular_gorjeta(400, 5) print('O valor da gorjeta de 5% de uma conta de R$ 400 eh', gorjeta) Quando a gorjeta não é informada na chamada da função, o valor do parâmetro gorjeta fica sendo 10 48 Colocar funções em arquivo separado } } } } Em alguns casos, pode ser necessário colocar todas as funções em um arquivo separado Nesse caso, basta definir todas as funções num arquivo .py (por exemplo funcoes.py). Quando precisar usar as funções em um determinado programa, basta fazer import <nome do arquivo que contém as funções> Ao chamar a função, colocar o nome do arquivo na frente 49 Exemplo Arquivo util.py Arquivo teste.py def soma(v): soma = 0 for i in range(len(v)): soma += v[i] return soma import util def media(v): return soma(v)/len(v) v = [1, 3, 5, 7, 9] print(util.soma(v)) print(util.media(v)) OU from util import soma, media v = [1, 3, 5, 7, 9] print(soma(v)) print(media(v)) 50 Exercícios 1. O professor deseja dividir uma turma com N alunos em dois grupos: um com M alunos e outro com (N-M) alunos. Faça o programa que lê o valor de N e M e informa o número de combinações possíveis } Número de combinações é igual a N!/(M! * (N-M)!) 2. Faça uma função que informe o status do aluno a partir da sua média de acordo com a tabela a seguir: } } } 51 Nota acima de 6 à “Aprovado” Nota entre 4 e 6 à “Verificação Suplementar” Nota abaixo de 4 à “Reprovado” Exercícios 3. Faça uma calculadora que forneça as seguintes opções para o usuário, usando funções sempre que necessário. Cada opção deve usar como operando um número lido do teclado e o valor atual da memória. Por exemplo, se o estado atual da memória é 5, e o usuário escolhe somar, ele deve informar um novo número (por exemplo, 3). Após a conclusão da soma, o novo estado da memória passa a ser 8. Estado da memória: 0 Opções: (1) (2) (3) (4) (5) (6) Somar Subtrair Multiplicar Dividir Limpar memória Sair do programa Qual opção você deseja? 52 Exercícios 4. Refaça o programa anterior para adicionar uma opção para escrever um número por extenso, agora aceitando números de até 9 dígitos e usando funções para as traduções 53 Exercícios 5. Faça um programa que, dado uma figura geométrica que pode ser uma circunferência, triângulo ou retângulo, calcule a área e o perímetro da figura } O programa deve primeiro perguntar qual o tipo da figura: } } } } } (1) circunferência (2) triângulo (3) retângulo Dependendo do tipo de figura, ler o (1) tamanho do raio da circunferência; (2) tamanho de cada um dos lados do triângulo; (3) tamanho dos dois lados retângulo Usar funções sempre que possível 54 Exercícios 6. Refaça o exercício 1 da aula de manipulação de listas, usando uma função para calcular o total de faltas do campeonato, outra para calcular o time que fez mais faltas, e uma terceira para calcular o time que fez menos faltas. Antes de chamar essas funções, o programa deve permitir que o usuário adicione mais jogos ao campeonato. 55 Referências } Slides feitos em conjunto com Aline Paes e Vanessa Braganholo 56 Subprogramação Loana Tito [email protected]