Pular para o conteúdo principal

05 Aula - Funções

Aula 05: Funções

Esta aula é baseada no capítulo 8 do livro "Introdução à programação com Python. Algoritmos e lógica de programação para iniciantes" de Nilo Ney Coutinho Menezes.

Esta é talvez a aula mais importante do curso.

Começamos o curso usando o interpretador (terminal do python na verdade) como uma calculadora. Nessa calculadora incrementada, aprendemos a trabalhar com números (inteiros e de ponto flutuante) e também com strings.

Logo no começo introduzimos um primeiro mecanismo de abstração: variáveis. Com as variáveis, pudemos dar nomes a valores. Aí bastava mudar o valor e executar o programa novamente.

Mas só variáveis não permitem que a gente faça muita coisa. Então aprendemos a usar expressões condicionais. Com isso e variáveis podíamos escolher que parte do programa seria executado.

Mas ainda assim, estávamos bem limitados ao que podíamos fazer. Então introduzimos algumas estruturas de dados mais complexas como

  • Listas
  • Dicionários
  • Tuplas
  • Conjuntos

Com isso começamos a implementar programas mais sofisticados, desenvolvendo algoritmos mais complexos (como por exemplo o programa para reordenar listas) e até mesmo joguinhos.

Mas ainda assim temos um problema: como reaproveitar programas ou parte dos programas? Ou executamos o programa novamente ou fazemos um copy and paste.

Aqui que entra o conceito de funções!

O que são funções em Python?

O termo surge da semelhança com as funções em matemática como por exemplo a função seno ou cosseno.

$$ y = cos(x) $$

Dado um valor representado por x, a função cos returna um outro valor que corresponde ao cosseno do valor x.

Em Python, a função cosseno é implementada no módulo math que deve ser carregado:

import math

e agora podemos usar acessar a função que calcula o cosseno como

python-repl
In [1]: import math

In [2]: print(math.cos(0.5))
0.8775825618903728

Muitas vezes é inconveniente ficar digitando math.cos(0.5) então podemos fazer

python-repl
In [5]: from math import cos

In [6]: print(cos(0.5))
0.8775825618903728
In [1]:
import math
In [2]:
math.cos(0.5)
Out[2]:
0.8775825618903728
In [3]:
math.sin(0.5)
Out[3]:
0.479425538604203
In [4]:
math.tan(0.5)
Out[4]:
0.5463024898437905
In [5]:
math.sin(0.5) / math.cos(0.5)
Out[5]:
0.5463024898437905
In [7]:
math.sin(0.5)**2 + math.cos(0.5)**2
Out[7]:
1.0
In [8]:
from math import cos
In [9]:
cos(0.5)
Out[9]:
0.8775825618903728

A biblioteca padrão do Python implementa um monte de coisa útil para o programador. Dê uma olhada na página https://docs.python.org/pt-br/3/library/index.html.

O módulo math tem um monte de coisa interessante https://docs.python.org/pt-br/3/library/math.html

Mas agora, o que queremos fazer é aprender a criar as nossas próprias funções.

Vamos começar com algo bem simples (e inútil!). Somar dois números:

In [10]:
def soma(a, b):
    print(a+b)

A instrução def é usada para definir uma nova função. No exemplo acima, é criada a função soma que tem 2 argumentos a e b e o corpo da função, que nesse caso é dado por uma expressão apenas print(a+b).

Repare na indentação. Assim como no if, while e for, o corpo da função deve ser indentado.

In [11]:
soma(1,2)
3

no exemplo acima, chamamos a função soma com os argumentos 1 e 2. O argumento da função a assume o valor 1 e o argumento b assume o valor 2.

In [12]:
soma(3,4)
7

Vamos fazer uma função parecida mas levemente diferente:

In [13]:
def soma2(a, b):
    print(a + 2*b)
In [14]:
soma2(1,2)
5
In [15]:
x = 1
y = 2
soma2(x,y)
5

novamente, o argumento a assume o valor de x e o argumento b assume o valor de y.

Exercício 1

O que o programa a seguir vai imprimir?

a = 1
b = 2
soma2(a,b)

e o programa

a = 1
b = 2
soma2(b, a)

Tente explicar o que aconteceu.

Os dois exemplos acima são bem simples mas ainda são diferentes do que observamos com funções matemáticas:

In [16]:
x = soma(1,2)
3
In [17]:
# Esperamos que o valor de `x` seja 3 (ou não...)
x

A função pode retornar um valor. Então podemos reescrever a função soma da seguinte maneira:

In [18]:
def soma(a,b):
    return a+b
In [19]:
x = soma(1,2)
In [20]:
x
Out[20]:
3

Agora temos algo que se comporta como as funções len ou int por exemplo.

Na verdade esse é o melhor jeito de se escrever uma função: usando os argumentos e o valor de retorno. A primeira versão é limitada. Não podemos usar diretamente o valor da soma.

Se a pessoa que está usando a função quiser imprimir o valor da soma, ela pode chamar a função e imprimir o valor. Muito mais útil e flexível:

In [21]:
print(soma(1,2))
3
In [22]:
x = soma(1,2)
print(x)
3
In [25]:
# Função para determinar se número é par
def é_par(x):
    return x % 2 == 0 # Se o resto da divisão for zero, o número é par!
In [26]:
print(é_par(1))
print(é_par(2))
print(é_par(3))
print(é_par(4))
False
True
False
True

Uma função pode chamar outra!

In [27]:
def par_ou_ímpar(x):
    if é_par(x):
        return "par"
    else:
        return "ímpar"
In [28]:
print(par_ou_ímpar(5))
print(par_ou_ímpar(32))
ímpar
par

Exercício 2

Escreva a função máximo que retorna o maior de dois números

In [ ]:
 

Exercício 3

Escreva a função múltiplo que retorna True se o primeiro argumento for um múltiplo do segundo

In [ ]:
 

Exercício 4

Escreva a função área_quadrado que recebe o lado de um quadrado e calcula a área.

In [ ]:
 

Exercício 5

Escreve a função área_triângulo que recebe a base e a altura de um triângulo e retorna a sua área

In [ ]:
 
In [ ]:
 
In [29]:
# Programa para pesquisar os elementos de uma lista:
def pesquise(lista, valor):
    for i,e in enumerate(lista):
        if e == valor:
            return i
    return None

    
In [30]:
pesquise([1,2,3], 2)
Out[30]:
1
In [31]:
pesquise([1,2,3], 4)
In [33]:
pesquise([1,2,3], 4) == None
Out[33]:
True
In [36]:
# Programa para somar os elementos de uma lista:
def soma(L):
    total = 0
    for v in L:
        total += v
    return total
In [39]:
soma([1,2,3])
Out[39]:
6
In [44]:
# A média dos elementos de uma lista
def média(L):
    total = 0
    for v in L:
        total += v
    return total / len(L)
In [45]:
média([1,2,3])
Out[45]:
2.0

Mas será que não dá para melhorar? A função é quase igual à função soma!

In [46]:
def média(L):
    return soma(L) / len(L)
In [47]:
média([1,2,3])
Out[47]:
2.0

Como não escrever a função soma:

In [48]:
def soma_ruim(L):
    total = 0
    i = 0
    while i < 5:
        total += L[i]
        i += 1
    return total
        
In [49]:
soma_ruim([1,2,3,4,5])
Out[49]:
15
In [51]:
# Porque isso dá errado???
soma_ruim([1,2,3,4,5,6,7])
Out[51]:
15

Fatorial

O fatorial de um número inteiro positivo n é dado por

$$ n! = 1\times 2 \times 3 \times \ldots \times n $$

e o fatorial de zero é 1: $$ 0! = 1 $$

In [52]:
def fatorial(n):
    fat = 1
    while n > 1:
        fat *= n
        n -= 1
    return fat
In [53]:
fatorial(5)
Out[53]:
120

Geralmente existem outras maneiras de escrever uma função:

In [56]:
def fatorial(n):
    fat = 1
    i = 1
    while i <= n:
        fat *= i
        i += 1
    return fat
In [57]:
fatorial(5)
Out[57]:
120

Exercício 6

Reescreve a função para pesquisar uma lista (pesquise) acima de modo a que use os métodos de pesquisa em lista que vimos na última aula.

Variáveis locais e globais

As funções que escrevemos até aqui tinham argumentos e eventualmente uma variável dentro da função. Que valor essa variável dentro da função assume? E se tivermos uma variável com mesmo nome fora da função?

In [94]:
EMPRESA = "Unidos Venceremos LTDA"
def imprime_cabeçalho():
    print(EMPRESA)
    print("-" * len(EMPRESA))
In [95]:
imprime_cabeçalho()
Unidos Venceremos LTDA
----------------------

Uma variável global é definida fora da função. Mas é aqui que as podem ficar confusas.

In [96]:
a = 5
def teste(a):
    print(a) # Que a estamos usando?
In [97]:
teste(10)
10

Este caso a gente já viu! Dentro da função estamos usando o argumento da função.

In [98]:
a = 5
def teste2():
    print(a)
In [99]:
teste2()
5

Este caso também está claro: estamos usando a variável global.

E agora?

In [100]:
a = 5
def teste3():
    a = 7
    print(a)
In [101]:
teste3()
7

Beleza, nada inesperado. Mas agora que estamos fora da função, qual o valor de a???

In [103]:
a
Out[103]:
5

Esquisito né? O que aconteceu?

Ao executarmos a linha a=7, criamos uma nova variável local!

Bom então no exemplo a seguir, vai imprimir 5 antes de mudar o valor (ou não???)

In [107]:
a = 5
def teste4():
    print(a)
    a = 7
    
In [108]:
teste4()
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
/tmp/ipykernel_9884/2345248876.py in <module>
----> 1 teste4()

/tmp/ipykernel_9884/3050936089.py in teste4()
      1 a = 5
      2 def teste4():
----> 3     print(a)
      4     a = 7
      5 

UnboundLocalError: local variable 'a' referenced before assignment

QUE É QUE ACONTECEU???? O PYTHON FICOU LOUCO

(ou não...)

O que ocorre é que existe uma atribuição de a dentro da função. Isso automaticamente faze com que a se torne uma variável local. Então a função nem sabe da existência da variável global a e portanto dá erro!

Mas e se eu quiser modificar o valor da variável global a? Use a instrução global

In [110]:
a = 5
def teste5():
    global a    # Olha o global aqui!
    a = 7
    print(f"Dentro da função: {a}")
print(f"Antes de chamar a função: {a}")
teste5()
print(f"Depois de chamar a função: {a}")
Antes de chamar a função: 5
Dentro da função: 7
Depois de chamar a função: 7

Recomendações

EVITE USAR VARIÁVEIS GLOBAIS. Quando você usa variáveis globais, o que uma função faz depende do estado do programa. Isso pode introduzir erros difíceis de serem diagnosticados. Se possível, passe o que seria uma variável global como um novo argumento da função.

Se você estiver usando variáveis globais, provavelmente você não pensou bem na estrutura do teu programa.

É lógico que isso não é dogma e variáveis globais podem ser úteis, por exemplo alguma configuração do programa.

Mas sempre pense duas (3, 4, 5) vezes antes de usar variáveis globais.

Funções recursivas

Já vimos que uma função pode chamar outra. Mas uma função pode chamar a si mesma! Esta é uma função recursiva.

Lembra da função fatorial? Bom, ela pode ser definida da seguinte maneira:

$$ 0! = 1 $$$$ 1! = 1 $$$$ n! = n \times (n-1)! $$

Com essa definição,

In [58]:
def fatorial(n):
    if n <= 1:
        return 1
    else:
        return n * fatorial(n-1)

Repare que é importante que exista uma condição de parada! Caso contrário a recursão não parará e o programa será executado até ocorrer o erro RecursionError.

Este erro ocorre pois a memória pode estourar (na verdade a pilha). Isso é equivalente ao loop infinito que já vimos para o while mas nesse caso, pode não ocorrer um erro.

In [62]:
def fatorial_errado(n):
    return n * fatorial_errado(n-1)
In [63]:
fatorial_errado(10)
---------------------------------------------------------------------------
RecursionError                            Traceback (most recent call last)
/tmp/ipykernel_9884/3944653170.py in <module>
----> 1 fatorial_errado(10)

/tmp/ipykernel_9884/3407553999.py in fatorial_errado(n)
      1 def fatorial_errado(n):
----> 2     return n * fatorial_errado(n-1)
      3 

... last 1 frames repeated, from the frame below ...

/tmp/ipykernel_9884/3407553999.py in fatorial_errado(n)
      1 def fatorial_errado(n):
----> 2     return n * fatorial_errado(n-1)
      3 

RecursionError: maximum recursion depth exceeded
In [66]:
# Vamos rastrear o fatorial?
def fatorial_rastreado(n):
    print(f"Calculando o fatorial de {n}")
    if n==0 or n==1:
        print(f"Fatorial de {n} = 1")
        return 1
    else:
        fat = n * fatorial_rastreado(n-1)
        print(f" fatorial de {n} = {fat}")
    return fat
In [67]:
fatorial_rastreado(4)
Calculando o fatorial de 4
Calculando o fatorial de 3
Calculando o fatorial de 2
Calculando o fatorial de 1
Fatorial de 1 = 1
 fatorial de 2 = 2
 fatorial de 3 = 6
 fatorial de 4 = 24
Out[67]:
24

Sequência de Fibonacci

Se $n \le 1$,

fibonacci(n) = 1

caso contrário,

fibonacci(n) = fibonacci(n-1) + fibonacci(n-2)

In [68]:
def fibonacci(n):
    if n <= 1:
        return n
    else:
        return fibonacci(n-1) + fibonacci(n-2)
In [81]:
fibonacci(20)
Out[81]:
6765

Exercício 7

Defina uma função recursive que calcule o maior divisor comum (MDC) entre dois números a e b em que a > b.

mdc(a,b) = a se b==0 e se a > b, mdc(a,b) = mdc(b, a % b)

In [ ]:
 

Exercício 8

Usando a função mdc do exercício anterior, defina uma função para calcular o mínimo múltiplo comum (MMC) entre dois números:

$$ mmc(a,b) = \frac{|a\times b|}{mdc(a,b)} $$

Lembre que $|a \times b|$ é escrito como abs(a * b) em Python.

In [ ]:
 

Exercício 9

Reescreva o programa para calcular a sequência de Fibonacci sem utilizar recursão.

Compare o desempenho com a função recursiva. Se você estiver usando o notebook do jupyter ou o ipython você pode usar a instrução %time como mostrado a seguir

In [93]:
%time fibonacci(10)
CPU times: user 23 µs, sys: 1e+03 ns, total: 24 µs
Wall time: 25.5 µs
Out[93]:
55

Pense no desempenho destas duas implementações. Consegue explicar?

In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
 

Parâmetros opcionais

Algumas vezes, os parâmetros da função podem ter valores típicos que mudam pouco. Então podemos usar um parâmetro opcional. Este parâmetro opcional, se não for fornecido, terá um valor padrão, definido junto com a função.

In [111]:
# Função para desenhar uma barra
def barra():
    return '*'*40
In [112]:
barra()
Out[112]:
'****************************************'

Mas eu quero especificar o número de caracteres:

In [116]:
def barra(n):
    return '*' * n
In [118]:
print(barra(40))  # Equivalente ao primeiro 
print(barra(60))
print(barra(20))
****************************************
************************************************************
********************

Mas e seu quiser usar um caracter diferente? Use um outro argumento!

In [119]:
def barra(n, caracter):
    return caracter * n
In [121]:
print(barra(40, '*'))
print(barra(40, '='))
****************************************
========================================

Mas agora eu preciso ficar digitando o caracter também ?!?

Use um argumento opcional!

In [124]:
def barra(n, caracter='*'):
    return caracter * n    
In [126]:
print(barra(40))
print(barra(40, '='))
****************************************
========================================

Mas geralmente vou usar 40 caracteres!

Então use outro argumento opcional!

In [127]:
def barra(n=40, caracter='*'):
    return caracter * n    
In [130]:
print(barra())
print(barra(20))
print(barra(40, '-'))
print(barra(20, '-'))
****************************************
********************
----------------------------------------
--------------------

Nomeando parâmetros

Python é ainda mais flexível ainda! Você pode usar os parâmetros pelo nome!

In [136]:
def retângulo(largura, altura, caracter):
    linha = caracter * largura
    for i in range(altura):
        print(linha)    
In [137]:
# Como fizemos até aqui.
retângulo(20, 4, '*')
********************
********************
********************
********************
In [138]:
# Podemos fazer isso:
retângulo(caracter='+', altura=3, largura=15)
+++++++++++++++
+++++++++++++++
+++++++++++++++

E podemos combinar isso com is argumentos opcionais:

In [139]:
def retângulo(largura=20, altura=4, caracter='*'):
    linha = caracter * largura
    for i in range(altura):
        print(linha)    
In [141]:
retângulo()
********************
********************
********************
********************
In [143]:
retângulo(caracter='+')
++++++++++++++++++++
++++++++++++++++++++
++++++++++++++++++++
++++++++++++++++++++
In [146]:
retângulo(largura=40)
****************************************
****************************************
****************************************
****************************************
In [147]:
retângulo(largura=40, altura=10)
****************************************
****************************************
****************************************
****************************************
****************************************
****************************************
****************************************
****************************************
****************************************
****************************************
In [148]:
retângulo(largura=40, caracter='-', altura=10)
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------
----------------------------------------

Isso é muito bom quando a função tem vários argumentos.

Funções como parâmetro

Até agora, os parâmetros das funções foram variáveis numéricas, listas, etc. Pode ser também uma função!

É isso mesmo. Uma função pode ser passada como um parâmetro em outra chamada de função!

In [151]:
def soma(a,b):
    return a+b
def subtração(a,b):
    return a-b
def multiplicação(a,b):
    return a*b

def imprime(a, b, foper):
    print(foper(a,b))
In [155]:
imprime(5,2,soma)
imprime(5,2,subtração)
imprime(5,2,multiplicação)
7
3
10

Parece esquisito. Será que tem uso?

Ahhhh, muito. Permite você flexibilizar o teu programa. Dar funcionalidade nova. Fazendo isso bem, o teu usuário vai poder usar as tuas funções de maneiras que você nunca imaginou.

In [161]:
def imprime_lista(L, fimpressão, fcondição):
    for e in L:
        if fcondição(e):
            fimpressão(e)
In [162]:
def imprime_elemento(e):
    print(f"Valor: {e}")
def épar(x):
    return x % 2 == 0
def éímpar(x):
    return not épar(x)
In [164]:
L = [1,7,9,2,11,0]
imprime_lista(L, imprime_elemento, épar)
Valor: 2
Valor: 0
In [165]:
imprime_lista(L, imprime_elemento, éímpar)
Valor: 1
Valor: 7
Valor: 9
Valor: 11

Exercício 10

Na aula 03 implementamos o algoritmo de reordenação de listas bubble sort. Crie uma função bubble_sort que reordena os elementos de uma lista de números em ordem crescente

In [ ]:
 

Exercício 11

Mude o programa do exercício 10 de modo que tenha um segundo parâmetro comparador que é uma função que compara dois elementos

def maior(a, b):
    return a > b

def bubble_sort(L, comparador=maior)
    # Corpo da função

Esse segundo parâmetro é o que compara os elementos da lista. Se esse parâmetros for a função maior, a lista será reordenada em ordem crescente.

Qual seria a função passada para o parâmetro comparador para que a lista fosse reordenada em ordem decrescente?

In [ ]:
 

Exercício 12

Escreva uma função mapa que recebe como primeiro parâmetro uma função e segundo parâmetro uma lista e cria uma nova lista aplicando esta função em cada elemento da lista.

Exemplo:

python-repl
In [10]: def dobro(n):
    ...:     return 2*n
    ...: 

In [11]: mapa(dobro, [1,2,3])
Out[11]: [2, 4, 6]
In [ ]:
 
In [171]:
 
Out[171]:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

List comprehension

No exercício 12, criamos uma função que aplica uma função a cada elemento de uma lista. Isso é tão útil que os criadores do Python implementaram uma sintaxe útil e simples para fazer isso: List Comprehension.

Com isso, muitas vezes o código fica mais curto e legível. Você nem precisa implementar laços e coisas parecidas.

In [173]:
L = [x for x in range(10)]
L
Out[173]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [175]:
Z = [2*x for x in L]
Z
Out[175]:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

Dá para criar coisas mais complexas:

In [176]:
[(x, 2*x, x*x) for x in L]
Out[176]:
[(0, 0, 0),
 (1, 2, 1),
 (2, 4, 4),
 (3, 6, 9),
 (4, 8, 16),
 (5, 10, 25),
 (6, 12, 36),
 (7, 14, 49),
 (8, 16, 64),
 (9, 18, 81)]

É funciona com outros tipos de dados. Na verdade com qualquer tipo de dado indexável:

In [177]:
Z = [s.upper() for s in "abcdefg"]
Z
Out[177]:
['A', 'B', 'C', 'D', 'E', 'F', 'G']

o melhor de tudo é que dá para filtrar as coisas

In [181]:
p = [x for x in range(10) if x % 2 == 0]  # Só os pares
p
Out[181]:
[0, 2, 4, 6, 8]

Tipo de uma variável. A função type

Em Python todas as variáveis e objetos têm um tipo. Você pode inspecionar isso usando a função type

In [183]:
type(10)
Out[183]:
int
In [185]:
type(1.23)
Out[185]:
float
In [186]:
type("IPT")
Out[186]:
str
In [187]:
type([1,2,3])
Out[187]:
list
In [188]:
type({'a':1, 'b':2})
Out[188]:
dict
In [190]:
type({1,2,3,4})
Out[190]:
set
In [197]:
type(len)
Out[197]:
builtin_function_or_method

Quando você está escrevendo uma função, é útil verificar se um parâmetro tem um tipo específico. Para isso existe a função isinstance que verifica se um objeto é de um tipo específico ou de uma lista de tipos:

In [198]:
isinstance(1, int)
Out[198]:
True
In [204]:
isinstance(1, float)
Out[204]:
False
In [206]:
isinstance(1, (float,int))
Out[206]:
True
In [207]:
isinstance([1,2,3], list)
Out[207]:
True
In [209]:
isinstance((1,2,3), tuple)
Out[209]:
True
In [211]:
isinstance((1,2,3), list)
Out[211]:
False
In [213]:
isinstance((1,2,3), (list, tuple))
Out[213]:
True
In [214]:
isinstance([1,2,3], (list, tuple))
Out[214]:
True
In [215]:
import types # Módulo da biblioteca padrão para tipos
In [227]:
def diz_o_tipo(a):
    if isinstance(a, str):
        return 'String'
    elif isinstance(a, list):
        return 'Lista'
    elif isinstance(a, dict):
        return 'Dicionário'
    elif isinstance(a, int):
        return 'Número inteiro'
    elif isinstance(a, float):
        return 'Número decimal'
    elif isinstance(a, types.FunctionType):
        return 'Função'
    elif isinstance(a, types.BuiltinFunctionType):
        return 'Função interna'
    else:
        return str(type(a))
In [217]:
diz_o_tipo(1)
Out[217]:
'Número inteiro'
In [218]:
diz_o_tipo([1,2,3])
Out[218]:
'Lista'
In [219]:
diz_o_tipo(1.2)
Out[219]:
'Número decimal'
In [223]:
diz_o_tipo(len)
Out[223]:
'Função interna'
In [225]:
diz_o_tipo(diz_o_tipo)
Out[225]:
'Função'
In [228]:
diz_o_tipo((1,2,3))
Out[228]:
"<class 'tuple'>"
In [ ]:
 

Exceções

Várias vezes ocorrem erros no programa. Neste curso fizemos alguns erros de propósto para mostrar funcionalidade e algumas vezes sem querer mesmo ao digitar algo errado.

Quando estes erros ocorreram, o programa simplesmente foi interrompido. Isso não é nem um pouco legal. Imagina você está usando um programa e de repente porque você digitou algo o programa acusa um erro e sai. Este não é o melhor dos mundos...

Em python um erro é conhecido como uma exceção (exception em inglês)

In [180]:
L = [1,2,3]

L[5]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
/tmp/ipykernel_9884/2673955037.py in <module>
      1 L = [1,2,3]
      2 
----> 3 L[5]

IndexError: list index out of range
In [230]:
int("IPT")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/tmp/ipykernel_9884/2167290565.py in <module>
----> 1 int("IPT")

ValueError: invalid literal for int() with base 10: 'IPT'

Repare que existem diferentes tipos de exceções!

In [234]:
# Capturando uma exceção:
nomes = ["Ana", "Carlos", "Maria"]
for tentativa in range(3):
    try:
        i = int(input("Digite o número que quer imprimir: "))
        print(nomes[i])
        break
    except ValueError:
        print("O programa só aceita número")
    except IndexError:
        print(f"Valor inválido, digite entre -3 e 3!")
Digite o número que quer imprimir: jhkasdasd
O programa só aceita número
Digite o número que quer imprimir: 10
Valor inválido, digite entre -3 e 3!
Digite o número que quer imprimir: 1
Carlos
In [240]:
# Outra possibilidade:
# Capturando uma exceção:
nomes = ["Ana", "Carlos", "Maria"]
for tentativa in range(3):
    try:
        i = int(input("Digite o número que quer imprimir: "))
        print(nomes[i])
        break
    except Exception as e:
        print(f"Algum erro na entrada: {e}")
Digite o número que quer imprimir: 6
Algum erro na entrada: list index out of range
Digite o número que quer imprimir: 6
Algum erro na entrada: list index out of range
Digite o número que quer imprimir: 6
Algum erro na entrada: list index out of range

Caso finalmente dê certo, existe a declaração finally. Essa parte sempre é executada!

In [241]:
nomes = ["Ana", "Carlos", "Maria"]
for tentativa in range(3):
    try:
        i = int(input("Digite o número que quer imprimir: "))
        print(nomes[i])
        break
    except Exception as e:
        print(f"Algum erro na entrada: {e}")
    finally: 
        print(f"Tentativa {tentativa+1}")
print("FIM")
Digite o número que quer imprimir: 5
Algum erro na entrada: list index out of range
Tentativa 1
Digite o número que quer imprimir: 5
Algum erro na entrada: list index out of range
Tentativa 2
Digite o número que quer imprimir: 5
Algum erro na entrada: list index out of range
Tentativa 3
FIM
In [242]:
math.sqrt(-1)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/tmp/ipykernel_9884/2272264683.py in <module>
----> 1 math.sqrt(-1)

ValueError: math domain error

Módulos

Ao se fazer um programa, escrevem-se funções para se realizar diferentes coisas. Estas funções podem ser úteis em outros programas. Então é interessante reaproveitar o teu trabalho. Com o decorrer do tempo, se você for organizado, você pode ter uma biblioteca de funções que são extremamente úteis e economizam um tempo danado.

O mecanismo básico para isso é o módulo. O módulo é um arquivo com terminação .py com funções (e outras coisas). Em geral está na mesma pasta que o programa que você está desenvolvendo. Como exemplo, vejamos o módulo utilidade.py

In [274]:
import os
os.getcwd()
Out[274]:
'/home/pjabardo/Documents/assipt/pythonassipt'
In [275]:
import utilidades
In [278]:
utilidades.sim_ou_não("Sim ou Não?")
Sim ou Não? (s/n): n
Out[278]:
False
In [280]:
utilidades.entrada_float("Entre com um número: ")
Entre com um número: asd
Valor ilegal - could not convert string to float: 'asd'! Tente novamente!
Entre com um número: asd
Valor ilegal - could not convert string to float: 'asd'! Tente novamente!
Entre com um número: asd
Valor ilegal - could not convert string to float: 'asd'! Tente novamente!
Entre com um número: asd
Valor ilegal - could not convert string to float: 'asd'! Tente novamente!
Entre com um número: asd
Valor ilegal - could not convert string to float: 'asd'! Tente novamente!
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
/tmp/ipykernel_9884/596805572.py in <module>
----> 1 utilidades.entrada_float("Entre com um número: ")

~/Documents/assipt/pythonassipt/utilidades.py in entrada_float(msg, xmin, xmax, ntentativas, x)
     22 
     23 def entrada_float(msg, xmin=None, xmax=None, ntentativas=5, x=None):
---> 24     return entrada(msg, float, xmin, xmax, ntentativas, x)
     25 
     26 def converter_sn(s):

~/Documents/assipt/pythonassipt/utilidades.py in entrada(msg, converter, xmin, xmax, ntentativas, x)
     14 
     15     if x is None:
---> 16         raise ValueError("Nenhum valor fornecido")
     17     else:
     18         return x

ValueError: Nenhum valor fornecido
In [ ]:
 

Comentários

Comments powered by Disqus