DEV Community

Cover image for Argumentos Opcionais Mutáveis em Python
Marcelo Lino
Marcelo Lino

Posted on

Argumentos Opcionais Mutáveis em Python

Argumentos deveriam ser coisas simples, não é mesmo? Você passa um valor para a função e ela faz o que você espera. Mas o que acontece quando a sua função não te obriga a passar um valor e trabalha com um valor padrão?

Uma função de soma que recebe dois valores e retorna a soma deles, porém caso nenhum valor seja inserido os argumentos assumem o valor 10 para cada um, retornando assim 20.

def soma(a=10, b=10):
    return a + b
Enter fullscreen mode Exit fullscreen mode

Nesse exemplo os valores padrões são imutáveis, então a cada operação não há modificação no seu conteúdo.

Agora o que acontece se modificamos o valor padrão para uma lista ou um dicionário?

Problema

from random import randint

def mutable_arguments(a_list=[], a_dict={}):
    a_list.append(randint(0, 100))
    a_dict[randint(0, 100)] = randint(0, 100)

    print(f"A lista agora contém os seguintes items: {a_list}")
    print(f"O dicionário agora contém os seguintes items: {a_dict}", end="\n\n")

mutable_arguments()
mutable_arguments()
mutable_arguments()
Enter fullscreen mode Exit fullscreen mode

Essa execução gera a seguinte saída:

The local list a_list now contains: [43]
The local dict a_dict now contains: {50: 61}

The local list a_list now contains: [43, 74]
The local dict a_dict now contains: {50: 61, 128: 69}

The local list a_list now contains: [43, 74, 42]
The local dict a_dict now contains: {50: 61, 128: 69, 86: 79}
Enter fullscreen mode Exit fullscreen mode

Note que a cada execução a lista e o dicionário são modificados, isso acontece porque o interpretador do Python aloca cada função ou método na inicialização do programa, caso essa assinatura contenha inicializadores de objetos eles então serão instanciados e alocados em memória durante a inicialização.

Sendo assim, quando você executa seu código e altera esses mesmos valores, está alterando objetos já alocados e não criando novos a cada execução. O que pode ao final do programa gerar resultados inesperados.

Solução

Existem duas formas de resolver esse problema, a primeira é passar None como valor padrão e então verificar se o valor é None e então atribuir o valor padrão.

from random import randint

def immutable_arguments(a_list=None, a_dict=None):
    if a_list is None:
        a_list = []
    if a_dict is None:
        a_dict = {}

    a_list.append(randint(0, 100))
    a_dict[randint(0, 100)] = randint(0, 100)

    print(f"A lista agora contém os seguintes items: {a_list}")
    print(f"O dicionário agora contém os seguintes items: {a_dict}", end="\n\n")

immutable_arguments()
immutable_arguments()
immutable_arguments()
Enter fullscreen mode Exit fullscreen mode

Outra abordagem é reatribuir o valor padrão ou então um objeto mutável vazio.

from random import randint

def immutable_arguments(a_list=None, a_dict=None):
    a_list = a_list or []
    a_dict = a_dict or {}

    a_list.append(randint(0, 100))
    a_dict[randint(0, 100)] = randint(0, 100)

    print(f"A lista agora contém os seguintes items: {a_list}")
    print(f"O dicionário agora contém os seguintes items: {a_dict}", end="\n\n")

immutable_arguments()
immutable_arguments()
immutable_arguments()
Enter fullscreen mode Exit fullscreen mode

Em ambos os casos a saída será a seguinte:

A lista agora contém os seguintes items: [44]
O dicionário agora contém os seguintes items: {7: 37}

A lista agora contém os seguintes items: [39]
O dicionário agora contém os seguintes items: {28: 50}

A lista agora contém os seguintes items: [40]
O dicionário agora contém os seguintes items: {40: 99}
Enter fullscreen mode Exit fullscreen mode

Perceba que agora a cada execução os valores são reatribuídos e não mais modificados.

Top comments (0)