Escrevendo Funções

Visão Geral

Perguntas
  • Como eu posso criar minhas próprias funções?

Objetivos
  • Explique e identifique a diferença entre a definição da função e a chamada da função.

  • Escreva uma função que receba um número fixo de argumentos e produza um único resultado.

Organize programas em funções para que sejam mais fáceis de entender.

Defina uma função usando def com um nome, parâmetros, e um bloco de código.

def imprimir_saudacao():
    print('Olá!')

Definir uma função não roda ela.

imprimir_saudacao()
Olá!

Argumentos em uma chamada correspondem aos parâmetros na definição.

def imprimir_data(ano, mes, dia)
    data_formatada = str(ano) + '/' + str(mes) + '/' + str(dia)
    print(data_formatada)

imprimir_data(2021, 3, 19)
2021/3/19

Ou, podemos nomear os argumentos quando chamamos a função, o que nos permite especificá-los em qualquer ordem:

imprimir_data(mes=3, dia=19, ano=2021)
2021/3/19

Funções podem retornar um resultado para quem está chamando usando return.

def calcular_media(valores):
    if len(valores) == 0:
        return None
    return sum(valores) / len(valores)
a = calcular_media([1, 3, 4])
print('Média de valores reais:', a)
Média de valores reais: 2.6666666666666665
print('Média de uma lista vazia:', calcular_media([]))
Média de uma lista vazia: None
resultado = imprimir_data(2021, 3, 19)
print('O resultado da chamada é:', resultado)
2021/3/19
O resultado da chamada é: None

Identificando erros de sintaxe

  1. Leia o código abaixo e tente identificar o que os erros são sem rodá-lo.
  2. Rode o código e leia a mensagem de erro. É do tipo SyntaxError ou IndentationError?
  3. Conserte o erro.
  4. Repita os passos 2 e 3 até que consertar todos os erros.
def outra_funcao
  print("Erros de sintaxe são irritantes.")
   print("Mas pelo menos o Python nos avisa sobre eles!")
  print("Então não são muito difíceis de consertar.")

Solução

def outra_funcao():
  print("Erros de sintaxe são irritantes.")
  print("Mas pelo menos o Python nos avisa sobre eles!")
  print("Então não são muito difíceis de consertar.")

Definição e Uso

O que o programa a seguir imprime?

def relatorio(consumo):
    print('consumo é', consumo)

print('chamando', relatorio, 22.5)

Solução

chamando <function relatorio at 0x7fd128ff1bf8> 22.5

Uma chamada de função sempre precisa de parênteses, caso contrário você recebe o endereço de memória do objeto função. Então, se queremos chamar a função chamada relatorio, e dar o valor 22.5 para ser reportado, podemos fazer nossa chamada de função assim:

print("chamando")
relatorio(22.5)
chamando
consumo é 22.5

Ordem das Operações

  1. O que há de errado nesse exemplo?

     resultado = imprimir_tempo(11, 37, 59)
    
     def imprimir_tempo(hour, minute, second):
        time_string = str(hour) + ':' + str(minute) + ':' + str(second)
        print(time_string)
    
  2. After fixing the problem above, explain why running this example code:

     resultado = imprimir_tempo(11, 37, 59)
     print('resultado of call is:', resultado)
    

    gives this output:

     11:37:59
     resultado of call is: None
    
  3. Por que o resultado da chamada é None?

Solução

  1. O problema no exemploe é que a função imprimir_tempo() é definida após a chamada ser feita. O Python não sabe como resolver o nome imprimir_tempo já que não foi definido e vai retornar um error NameError como NameError: name 'imprimir_tempo' is not defined

  2. A primeira linha da saída 11:37:59 é impressa pela primeira linha de código, resultado = imprimir_tempo(11, 37, 59) que assinala o valor retornado por imprimir_tempo a variavel resultado. A segunda linha linha de c´dogio é o resultado do segundo print, que imprime o conteúdo da variável resultado.

  3. imprimir_tempo() não retorna um valor explicitamente com return, então automaticamente retorna None.

Encapsulação

Preencha os brancos para criar uma função que recebe um único nome de arquivo como argumento, carrega os dados do arquivo, e retorna o comprimento da maior linha.


def detectar_tamanho_linha(____):
    with open(____) as f:
        dados = f.readlines()

    comprimentos = []
    for linha em dados:
        comprimentos.append(____)

    maior_comprimento = max(____) 
    return maior_comprimento

Solução

def detectar_tamanho_linha(arquivo):
    with open(arquivo) as f:
        dados = f.readlines()

    comprimentos = []
    for linha em dados:
        comprimentos.append(len(linha))

    maior_comprimento = max(comprimentos) 
    return maior_comprimento

Encontre o Primeiro

Preencha os brancos para criar uma função que receba uma lista de números como argumento e imprima o primeiro valor negativo na lista. O que a sua função faz se a lista estiver vazia? E se a lista não tiver números negativos?

def primeiro_negativo(valores):
    for v in ____:
        if ____:
            return ____

Solução

def primeiro_negativo(valores):
    for v in valores:
        if v < 0:
            return v

Se uma lista vazia ou uma lista só com valores positivos for passada para essa função, ela retorna None:

minha_lista = []
print(primeiro_negativo(minha_lista))
None

Encapsulando um bloco If/Else

O código abaixo vai imprimir etiquetas para ovos de galinha. Uma balança digital vai reportar a massa de um ovo (em gramas) para o computador e o computador precisa imprimir uma etiqueta.

Por favor reescreva o código abaixo para que o bloco de if seja dobrado em uma função.

import random
for i in range(10):

    # simulando a massa de um ovo de galinha
    # o valor (aleatório) será de 70 +/- 20 gramas
    massa = 70 + 20.0 * (2.0 * random.random() - 1.0)

    print(massa)
   
    # a maquinaria de pesos de ovos imprime um valor
    if massa >= 85:
       print("jumbo")
    elif massa >= 70:
       print("grande")
    elif massa < 70 and massa >= 55:
       print("médio")
    else:
       print("pequeno")

O programa simplificado está a seguir. Que definição de função o tornará funcional?

# versão revisada
import random
for i in range(10):

    # simulando a massa de um ovo de galinha
    # o valor (aleatório) será de 70 +/- 20 gramas
    massa = 70 + 20.0 * (2.0 * random.random() - 1.0)

    print(massa, calcular_etiqueta(massa))    

  1. Crie uma definição de função para calcular_etiqueta() que vai funcionar com o programa revisado acima. Note que o valor de retorno da função calcular_etiqueta() será importante. Um exemplo de saída desse programa seria 71.23 grande.
  2. Um ovo sujo pode ter uma massa de mais de 90 gramas, e um ovo podre ou quebrado provavelmente vai ter uma massa menor que 50 gramas. Modifique sua função calcular_etiqueta() para levar em conta essas condições de erro. Uma saída de exemplo poderia ser 25 muito leve, algo de errado.

Solução

def calcular_etiqueta(massa):
    # egg sizing machinery prints a label
    etiqueta_ovo = "sem etiqueta"
    if massa >= 90:
        etiqueta_ovo = "aviso: o ovo pode estar sujo"
    elif massa >= 85:
        etiqueta_ovo = "jumbo"
    elif massa >= 70:
        etiqueta_ovo = "grande"
    elif massa < 70 and massa >= 55:
        etiqueta_ovo = "médio"
    elif massa < 50:
        etiqueta_ovo = "muito leve, algo de errado"
    else:
        etiqueta_ovo = "pequeno"
    return etiqueta_ovo

Pontos-chave

  • Organize programas em funções para que sejam mais fáceis de entender.

  • Defina uma função usado def com um nome, parâmetros, e um bloco de código.

  • Definir uma função não roda ela.

  • Argumentos em uma chamada correspondem aos parâmetros na definição.

  • Funções podem retornar um resultado para quem está chamando usando return.