É verdade que a maioria das linguagens de programação torna a ordem dos parâmetros parte do contrato de chamada de função, mas não precisa ser assim. Por que seria? Meu entendimento da questão é, então, se Python é diferente de outras linguagens de programação nesse aspecto. Além de outras boas respostas para Python 2, considere o seguinte:
__named_only_start = object()
def info(param1,param2,param3,_p=__named_only_start,spacing=10,collapse=1):
if _p is not __named_only_start:
raise TypeError("info() takes at most 3 positional arguments")
return str(param1+param2+param3) +"-"+ str(spacing) +"-"+ str(collapse)
A única maneira que um chamador seria capaz de fornecer argumentos spacing
e collapse
posicionalmente (sem uma exceção) seria:
info(arg1, arg2, arg3, module.__named_only_start, 11, 2)
A convenção de não usar elementos privados pertencentes a outros módulos já é muito básica em Python. Como acontece com o próprio Python, essa convenção para parâmetros seria apenas parcialmente aplicada.
Caso contrário, as chamadas precisariam ser no formato:
info(arg1, arg2, arg3, spacing=11, collapse=2)
Uma chamada
info(arg1, arg2, arg3, 11, 2)
atribuiria o valor 11 ao parâmetro _p
e uma exceção gerada pela primeira instrução da função.
Características:
- Os parâmetros anteriores
_p=__named_only_start
são admitidos posicionalmente (ou pelo nome).
- Parâmetros depois
_p=__named_only_start
devem ser fornecidos apenas pelo nome (a menos que __named_only_start
seja obtido e usado conhecimento sobre o objeto sentinela especial ).
Prós:
- Os parâmetros são explícitos em número e significado (o último se bons nomes também forem escolhidos, é claro).
- Se o sentinela for especificado como primeiro parâmetro, todos os argumentos precisam ser especificados por nome.
- Ao chamar a função, é possível alternar para o modo posicional usando o objeto sentinela
__named_only_start
na posição correspondente.
- Um desempenho melhor do que outras alternativas pode ser antecipado.
Contras:
A verificação ocorre durante o tempo de execução, não durante o tempo de compilação.
- Uso de um parâmetro extra (embora não seja um argumento) e uma verificação adicional. Pequena degradação do desempenho em relação às funções regulares.
- A funcionalidade é um hack sem suporte direto do idioma (veja a nota abaixo).
- Ao chamar a função, é possível alternar para o modo posicional usando o objeto sentinela
__named_only_start
na posição correta. Sim, isso também pode ser visto como um profissional.
Lembre-se de que esta resposta só é válida para Python 2. O Python 3 implementa o mecanismo semelhante, mas muito elegante, com suporte de linguagem descrito em outras respostas.
Descobri que quando abro minha mente e penso sobre isso, nenhuma pergunta ou decisão de outra pessoa parece estúpida, idiota ou simplesmente boba. Muito pelo contrário: normalmente aprendo muito.
_named_only_start
, torna-se impossível referenciá-la de um módulo externo, o que remove um prós e um contra. (os sublinhados principais únicos no escopo do módulo são privados, IIRC)__named_only_start
e umnamed_only_start
(sem sublinhado inicial), o segundo para indicar que o modo nomeado é "recomendado", mas não ao nível de ser "promovido ativamente" (como um é público e o outro não é). Quanto à "privacidade" de_names
começar com sublinhados, ela não é muito fortemente imposta pela linguagem: pode ser facilmente contornada pelo uso de importações específicas (não *) ou nomes qualificados. É por isso que vários documentos Python preferem usar o termo "não público" em vez de "privado".Você pode fazer isso de uma forma que funcione no Python 2 e no Python 3 , criando um argumento de primeira palavra-chave "falso" com um valor padrão que não ocorrerá "naturalmente". Esse argumento de palavra-chave pode ser precedido por um ou mais argumentos sem valor:
Isso permitirá:
mas não:
Se você alterar a função para:
então, todos os argumentos devem ter palavras-chave e
info(odbchelper)
não funcionarão mais.Isso permitirá que você posicione argumentos de palavra-chave adicionais em qualquer lugar depois
_kw
, sem forçá-lo a colocá-los após a última entrada. Isso geralmente faz sentido, por exemplo, agrupar coisas logicamente ou organizar palavras-chave em ordem alfabética pode ajudar na manutenção e no desenvolvimento.Portanto, não há necessidade de voltar a usar
def(**kwargs)
e perder as informações de assinatura em seu editor inteligente. Seu contrato social é fornecer certas informações, forçando (algumas delas) a exigir palavras-chave, a ordem em que são apresentadas, tornou-se irrelevante.fonte
Atualizar:
Percebi que usar
**kwargs
não resolveria o problema. Se seus programadores alteram os argumentos da função como desejam, é possível, por exemplo, alterar a função para esta:e o código antigo quebraria novamente (porque agora cada chamada de função tem que incluir o primeiro argumento).
Na verdade, tudo se resume ao que Bryan diz.
Em geral, ao alterar funções, novos argumentos devem sempre ir para o final. Caso contrário, ele quebra o código. Deve ser óbvio.
Se alguém alterar a função para que o código seja interrompido, essa alteração deve ser rejeitada.
(Como diz Bryan, é como um contrato)
Olhando para a assinatura da função (isto é
def info(object, spacing=10, collapse=1)
), deve-se ver imediatamente que todo argumento que não tem um valor padrão é obrigatório.Para que serve o argumento, deve ir para a docstring.
Resposta antiga (mantida para integridade) :
Esta provavelmente não é uma boa solução:Você pode definir funções desta forma:
kwargs
é um dicionário que contém qualquer argumento de palavra-chave. Você pode verificar se um argumento obrigatório está presente e, se não, gerar uma exceção.A desvantagem é que pode não ser mais tão óbvio, quais argumentos são possíveis, mas com uma docstring adequada, deve estar tudo bem.
fonte
Os argumentos somente de palavra-chave do python3 (
*
) podem ser simulados em python2.x com**kwargs
Considere o seguinte código python3:
e seu comportamento:
Isso pode ser simulado usando o seguinte, observe que tomei a liberdade de alternar
TypeError
paraKeyError
no caso do "argumento nomeado necessário", não seria muito trabalhoso tornar esse mesmo tipo de exceção tambémE comportamento:
A receita funciona igualmente bem em python3.x, mas deve ser evitada se você for apenas python3.x
fonte
kwargs.pop('foo')
é um idioma Python 2? Preciso atualizar meu estilo de codificação. Eu ainda estava usando essa abordagem no Python 3 🤔Você pode declarar suas funções como
**args
apenas recebedoras . Isso exigiria argumentos de palavra-chave, mas você teria algum trabalho extra para garantir que apenas nomes válidos fossem passados.fonte
foo(**kwargs)
. O que eu passo nisso?foo(killme=True, when="rightnowplease")
dict
.Como outras respostas dizem, alterar as assinaturas de função é uma má ideia. Adicione novos parâmetros ao final ou corrija cada chamador se forem inseridos argumentos.
Se você ainda quiser fazer isso, use um decorador de função e a função inspect.getargspec . Seria usado mais ou menos assim:
A implementação de
require_named_args
é deixada como um exercício para o leitor.Eu não me incomodaria. Será lento cada vez que a função for chamada, e você obterá melhores resultados escrevendo código com mais cuidado.
fonte
Você pode usar o
**
operador:desta forma, as pessoas são forçadas a usar parâmetros nomeados.
fonte
em python, se usar * args, isso significa que você pode passar n-número de argumentos para este parâmetro - que virá uma lista dentro da função para acessar
e se usar ** kw significa seus argumentos de palavra-chave, que podem ser acessados como dict - você pode passar n-número de argumentos kw, e se quiser restringir esse usuário deve inserir a sequência e os argumentos para não usar * e ** - (sua forma pitônica de fornecer soluções genéricas para grandes arquiteturas ...)
se você quiser restringir sua função com valores padrão, você pode verificar dentro dela
fonte
Não entendo por que um programador adicionará um parâmetro entre dois outros em primeiro lugar.
Se você deseja que os parâmetros da função sejam usados com nomes (por exemplo
info(spacing=15, object=odbchelper)
), não deve importar em que ordem eles são definidos, então você pode também colocar os novos parâmetros no final.Se você deseja que o pedido seja importante, não pode esperar que nada funcione se você alterá-lo!
fonte