Curso de Python / Argumentos posicionais, nomeados e valores padrão
Em Python, argumentos posicionais são associados pela ordem e argumentos nomeados são associados pelo nome do parâmetro. Valores padrão tornam entradas opcionais, mas uma lista usada como padrão pode conservar alterações entre chamadas; quando cada chamada precisa de uma lista nova, receba None e crie a lista no corpo da função.
Escolher chamadas por posição ou por nome
Na definição format_expense(name, amount, *, currency="KRW"), os dois primeiros parâmetros são obrigatórios e aceitam argumentos por posição ou por nome. Por posição, o primeiro valor corresponde a name e o segundo a amount. Com nomes explícitos, a ordem desses dois argumentos pode mudar sem alterar sua associação.
O asterisco isolado * na definição indica que os parâmetros seguintes são somente nomeados: currency precisa ser fornecido como currency="KRW" quando você quiser especificá-lo. O valor padrão permite omiti-lo, mas não permite passá-lo como terceiro argumento posicional. Esse asterisco não cria uma lista nem recebe um valor do chamador.
Uma chamada comum pode combinar argumentos posicionais primeiro e nomeados depois. Atribuir o mesmo parâmetro duas vezes causa TypeError; colocar um argumento posicional comum depois de um nomeado causa SyntaxError. Essas regras completam a distinção entre parâmetros, argumentos e valores retornados por funções.
Executar argumentos opcionais e listas novas
Salve o código completo em arguments.py, com codificação UTF-8, numa pasta de prática. No terminal com o ambiente virtual selecionado, execute python arguments.py. Em macOS ou Ubuntu sem ambiente virtual, use python3 arguments.py se esse for o nome do interpretador. Nenhuma biblioteca externa é necessária.
def format_expense(name, amount, *, currency="KRW"):
return f"{name}: {amount:,} {currency}"
def append_name(name, names=None):
if names is None:
names = []
names.append(name)
return names
print(format_expense("lunch", 8000))
print(format_expense(amount=9000, name="dinner", currency="KRW"))
print(append_name("A"))
print(append_name("B"))
O resultado esperado é:
lunch: 8,000 KRW
dinner: 9,000 KRW
['A']
['B']
A primeira chamada usa a moeda padrão; a segunda explicita os nomes e muda a ordem de amount e name. As palavras lunch e dinner são apenas dados de exemplo, correspondentes a almoço e jantar. KRW identifica o won sul-coreano. Mudar esse texto para BRL mudaria somente o rótulo: a função não consulta cotação, não converte valores e não aplica formatação monetária brasileira.
O especificador :, usa vírgula para separar milhares, por isso aparece 8,000. Cada chamada de append_name() sem uma lista recebe o padrão None, cria uma lista vazia e acrescenta o nome. Assim, a chamada com B não reutiliza a lista criada na chamada com A.
Comparar um padrão compartilhado com uma lista criada por chamada
Uma expressão de valor padrão é avaliada quando a instrução de definição da função é executada, e não novamente a cada chamada. Usar names=[] cria um objeto que permanece como padrão daquela função. Como append() modifica esse objeto, chamadas posteriores que omitem a lista observam os nomes acrescentados antes.
Para comparar, salve este segundo programa completo em defaults.py e execute python defaults.py no mesmo terminal. Use o nome python3 quando necessário, como no primeiro programa. As chamadas precisam ocorrer na mesma execução para revelar o compartilhamento.
def shared(name, names=[]):
names.append(name)
return names
def fresh(name, names=None):
if names is None:
names = []
names.append(name)
return names
print(shared("A"))
print(shared("B"))
print(fresh("A"))
print(fresh("B"))
A saída esperada é:
['A']
['A', 'B']
['A']
['B']
A segunda chamada de shared() ainda encontra A e acrescenta B. Já fresh() cria listas diferentes para as duas chamadas que omitem names. Ao executar o arquivo inteiro novamente num processo novo, as definições também são executadas novamente: a primeira saída de shared() volta a ser ['A']. O acúmulo pertence ao objeto usado naquela execução, não a um arquivo de dados salvo automaticamente.
Use if names is None quando quiser preservar uma lista vazia passada explicitamente. Uma condição como if not names também considera a lista vazia falsa e criaria outra lista, perdendo a associação pretendida com o objeto do chamador. A documentação dos valores padrão de argumentos apresenta a razão para usar esse padrão com None.
Testar chamadas inválidas e a alteração de objetos fornecidos
- Depois das definições em
arguments.py, acrescente temporariamenteprint(format_expense("lunch", 8000, "KRW")). O terceiro argumento posicional causaTypeError. Corrija a chamada paraprint(format_expense("lunch", 8000, currency="KRW"))e confiralunch: 8,000 KRW. - Teste separadamente
format_expense("lunch", 8000, amount=9000). O parâmetroamountreceberia dois valores, portanto ocorreTypeError. Teste tambémformat_expense(name="lunch", 8000): essa forma é sintaticamente inválida e impede a execução do arquivo inteiro. Remova cada teste inválido antes de seguir. - Depois da definição de
append_name(), acrescentenames = [],result = append_name("A", names)eprint(names, result is names), cada instrução em sua própria linha. A saída adicional deve ser['A'] True: o objeto do chamador foi modificado e retornado. - Somente para comparar, substitua
if names is Noneporif not namese repita o teste anterior num processo novo. A saída adicional muda para[] False, pois a lista vazia fornecida foi substituída por uma nova. Restaureif names is None, retire as linhas de teste e confirme a saída original dos dois programas.
Evitar um padrão mutável compartilhado não significa copiar todas as listas recebidas. Quando o chamador passa uma lista, append_name() altera deliberadamente esse objeto. Se o contrato exigir preservar a entrada, é preciso decidir e implementar uma cópia; isso é uma escolha diferente da criação de uma lista quando o argumento foi omitido.
O mesmo momento de avaliação vale para uma expressão que calcula a data ou a hora atual: usá-la diretamente como padrão conserva o resultado obtido na definição. Se precisar de um valor novo em cada chamada, calcule-o no corpo quando receber o marcador escolhido. None é adequado quando significa “não fornecido”; se ele próprio for um argumento com significado, escolha outro marcador distinto. A documentação dos parâmetros especiais detalha como restringir a interface de chamada sem confundir essas regras com o conteúdo dos objetos recebidos.




