Seu navegador não oferece leitura em voz alta. Você pode ler o guia normalmente.
Funções, escopo de variáveis e tratamento de erros concentram as pegadinhas mais refinadas de Python em provas: o código parece inocente, e a saída surpreende quem não conhece o modelo da linguagem. Os trechos abaixo foram executados em Python 3 e as saídas são as reais. O básico de tipos e listas está em Python: tipos, listas, dicionários e laços.
Funções, parâmetros e retorno
Uma função é definida com def, recebe parâmetros e devolve valor com return; sem return, devolve None. Parâmetros podem ter valor padrão e podem ser variáveis:
def soma(*args, **kw):
return sum(args), kw
print(soma(1, 2, 3, a=1))
Saída: (6, {'a': 1}). O *args reúne os argumentos posicionais numa tupla; o **kw reúne os nomeados num dicionário.
Funções anônimas e de ordem superior: list(map(lambda v: v*2, [1, 2, 3])) dá [2, 4, 6]; list(filter(lambda v: v > 1, [1, 2, 3])) dá [2, 3]; sorted(['bb', 'a', 'ccc'], key=len) dá ['a', 'bb', 'ccc']. Um gerador com yield produz valores sob demanda: list(gen(4)), para uma função que cede i*i, dá [0, 1, 4, 9].
Pegadinha 1: parâmetro padrão mutável
def f(x, lista=[]):
lista.append(x)
return lista
print(f(1), f(2), f(3))
Saída: [1, 2, 3] [1, 2, 3] [1, 2, 3]. O valor padrão [] é criado uma única vez, quando a função é definida, e é reaproveitado em todas as chamadas. Cada chamada acrescenta à mesma lista. Note que a impressão mostra a lista final três vezes porque print só imprime depois de todas as chamadas, e as três respostas são o mesmo objeto.
A forma correta usa None como sentinela:
def g(x, lista=None):
if lista is None:
lista = []
lista.append(x)
return lista
print(g(1), g(2)) dá [1] [2].
Pegadinha 2: atribuição não copia
a = [1, 2, 3]
b = a
b.append(4)
print(a, a is b)
Saída: [1, 2, 3, 4] True. b = a copia a referência, não a lista: as duas variáveis apontam para o mesmo objeto. Para copiar, use a.copy(); após c = a.copy(); c.append(5), a continuou [1, 2, 3, 4] e c ficou [1, 2, 3, 4, 5]. A cópia é rasa: listas dentro da lista continuam compartilhadas.
Prova disso com listas aninhadas:
| Construção | Após m[0][0] = 1 |
|---|---|
m = [[0]*2]*2 |
[[1, 0], [1, 0]] (as duas linhas são a mesma lista) |
m = [[0]*2 for _ in range(2)] |
[[1, 0], [0, 0]] (linhas independentes) |
Escopo: local, global e a palavra global
Variável criada dentro da função é local. Teste: com x = 10 no módulo e uma função que faz x = 5 e devolve x, a chamada devolve 5, mas o x do módulo continua 10. Para alterar a variável global é preciso declarar global x dentro da função; com isso, x passou a valer 99 no teste. A regra de busca de nomes costuma ser resumida como LEGB: local, englobante (função externa), global e predefinido (built-in).
Recursão
Uma função recursiva chama a si mesma e precisa de um caso base que a encerre.
def fat(n):
return 1 if n <= 1 else n * fat(n - 1)
fat(5) dá 120 e fat(0) dá 1. A sequência de Fibonacci com fib(n) = n se n < 2, ou fib(n-1) + fib(n-2), gerou para n de 0 a 9: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34. Sem caso base, a recursão estoura o limite de profundidade da pilha de chamadas (veja a pilha em pilha, fila e lista). A versão ingênua de Fibonacci repete muitos cálculos e tem custo exponencial.
Exceções: try, except, else e finally
try:
print(1 / 0)
except ZeroDivisionError as e:
print('erro:', e)
else:
print('else')
finally:
print('finally')
Saída: erro: division by zero e depois finally. O else só roda quando não houve exceção; o finally roda sempre, com ou sem erro, o que o torna o lugar certo para liberar recursos.
Exceções comuns e as mensagens obtidas:
| Código | Exceção | Mensagem |
|---|---|---|
int('abc') |
ValueError | invalid literal for int() with base 10: ‘abc’ |
[1, 2][5] |
IndexError | list index out of range |
{'a': 1}['b'] |
KeyError | ‘b’ |
print(undefined) |
NameError | name ‘undefined’ is not defined |
t[0] = 9 (tupla) |
TypeError | ‘tuple’ object does not support item assignment |
O except deve citar a exceção mais específica possível; um except genérico esconde erros reais. As exceções formam uma hierarquia, e quem captura uma classe captura também as suas subclasses. Para sinalizar um erro, usa-se raise.
Outras pegadinhas rápidas
sorted(l)não alteral;l.sort()altera e devolveNone.3 * 'ab'dá'ababab';[0] * 3dá[0, 0, 0].divmod(17, 5)dá(3, 2): quociente e resto.int(3.9)dá 3 eint(-3.9)dá -3 (truncamento).(1, 2) < (1, 3)éTrue: tuplas comparam elemento a elemento.
Como analisar um trecho na prova
- Liste as variáveis e anote o valor após cada linha.
- Marque se cada atribuição cria objeto novo ou apenas outra referência.
- Em funções, identifique escopo e valores padrão.
- Em
try, decida qual bloco executa:exceptse houve erro,elsese não houve,finallysempre. - Releia a pergunta: “o que será impresso” ou “qual o valor final”.
Erros comuns
- Achar que
b = aduplica a lista. - Usar lista ou dicionário como valor padrão de parâmetro.
- Esquecer que variável criada na função não existe fora dela.
- Achar que o
finallysó roda em caso de erro. - Recursão sem caso base.
Fontes e atualização
Não há norma oficial brasileira sobre a linguagem Python; o conteúdo segue o comportamento documentado do interpretador, e as saídas vieram da execução dos trechos em Python 3. Mensagens de erro e detalhes finos podem mudar entre versões: confira a versão do edital.
Próximos passos
- Aprofunde o paradigma de objetos em programação orientada a objetos: herança, polimorfismo e encapsulamento.
- Veja a análise de custo em busca sequencial e binária e Big O.
- Volte ao básico em Python: tipos, listas, dicionários e laços.