Um dos exercícios mais comuns nas aulas básicas de programação é sem dúvida alguma o de trocar os valores das variáveis a e b.

// Codigo classico em linguagem c
int main(){
    int a = 5, b = 7;

    int tmp = a;
    a = b;
    b = tmp;
}

Mas se a linguagem for Python, existe uma outra maneira:

a = 5
b = 7
a, b = b, a

Ok até agora não tivemos muitas novidades, provavelmente você já viu isso em algum lugar. Mas neste post eu vou apresentar mais algumas possibilidades deste desempacotamento do Python!

Desempacotamento com Python⌗

Algo que eu faço muito resolvendo exercícios do URI é ler a linha dar um split na linha e converter todos os elementos para um tipo especifico, geralmente int.

Claro que podemos fazer isso de várias formas, por exemplo:

linha = input().split()

a = int(linha[0])
b = int(linha[1])
c = int(linha[2])
d = int(linha[3])

Esse exemplo funcionaria, mas seria extremamente lento de se escrever isso se tivermos várias variáveis diferentes na linha, então hoje eu uso muito, mas muito mesmo essa solução com list-comprehensions:

a, b, c, d = [int(x) for x in input().split()]

De cinco linhas para uma até que nos livramos de uma boa parte de código repetitivo!

Melhorando a legibilidade do código⌗

Agora vamos a um exemplo menos bobinho, e também com menos cara de exercício de programação, sem unpacking:

curso = get_curso_by_id(2)

print("Nome:", curso[1])
print("Coordenador:", curso[3])
print("Data de Inicio:", curso[4])
print("Descrição:", curso[2])

A função get_curso_by_id() retorna uma tupla com: id, nome, descrição, coordenador, data de inicio. Referenciar estes campos por seu índices é uma solução feia que permite muitos erros. Então vamos deixar este código mais legível com desempacotamento:

id_curso, nome, desc, coordenador, dt_inicio = get_curso_by_id(2)

print("Nome:", nome)
print("Coordenador:", coordenador)
print("Data de Inicio:", dt_inicio)
print("Descrição:", desc)

Muito mais legível!

Agora vamos dizer que a data retorna também uma tupla com anos, mês e dia. Para separar esses valores também nos poderíamos fazer o seguinte:

id_curso, nome, desc, coordenador, (ano, mes, dia) = get_curso_by_id(2)

print("Nome:", nome)
print("Coordenador:", coordenador)
print("Data de Inicio:", "{}/{}/{}".format(dia, mes, ano))
print("Descrição:", desc)

Ignorando valores⌗

Agora vamos dizer que você precisa apenas do nome do curso e do coordenador, o Python não possui nenhuma sintaxe específica pra isso, mas você pode simplesmente atribuir esses campos para uma variável aleatória, como _:

_, nome, _, coordenador, _ = get_curso_by_id(2)

Desempacotando valores de iteráveis de tamanho variável⌗

Tudo isso e muito bonito mas é no caso de iteráveis que eu não sei exatamente o tamanho? É agora que entram as * no Python, mas acalme-se meu jovem traumatizado pelos ponteiros de C essa estrelinha não tem nenhuma relação com eles.

>>> aluno
('João', 'joao@bol.com.br', '(11) 93233-32323', '(11) 93233-3863', '(11) 98603-32323')
>>> nome, email, *telefones
>>> nome
'João'
>>> email
'joao@bol.com.br'
>>> telefones
['(11) 93233-32323', '(11) 93233-3863', '(11) 98603-32323']

Em detalhes: nome e email receberam os dois primeiros elementos, e telefones recebeu todo o resto.

E claro que as ’estrelinhas’ não servem só pra desempacotar os últimos elementos: elas podem estar no meio, no incio e no fim da expressões de desempacotamento.

A única exigência e que exista apenas um ‘valor estrelado’ na expressão:

>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> a, *b, c, *d = l
  File "<stdin>", line 1
SyntaxError: two starred expressions in assignment
>>>

Passando um iterável ou dicionário como argumentos de uma função⌗

Essa talvez você já tenha visto em algum lugar:

>>> def a(*args, **kwargs):
...     print(args)
...     print(kwargs)
...
>>> a(1, 2, 'a', 'b', z=9, x=8)
(1, 2, 'a', 'b')
{'z': 9, 'x': 8}
>>>

E aí, o que achou dessa forma de desempacotar dados com o Python?