Adicionando valor de parâmetro padrão com o tipo hint no Python

236

Se eu tiver uma função como esta:

def foo(name, opts={}):
  pass

E eu quero adicionar dicas de tipo aos parâmetros, como faço isso? A maneira que assumi me dá um erro de sintaxe:

def foo(name: str, opts={}: dict) -> str:
  pass

O seguinte não gera um erro de sintaxe, mas não parece a maneira intuitiva de lidar com este caso:

def foo(name: str, opts: dict={}) -> str:
  pass

Não consigo encontrar nada na typingdocumentação ou em uma pesquisa no Google.

Edit: Eu não sabia como os argumentos padrão funcionavam no Python, mas, para o bem desta pergunta, vou manter os exemplos acima. Em geral, é muito melhor fazer o seguinte:

def foo(name: str, opts: dict=None) -> str:
  if not opts:
    opts={}
  pass
Josh
fonte
4
A última função é a maneira correta. É da mesma maneira que a scalalinguagem também.
Israel Unterman
14
você tem um tipo padrão mutável - que levará a problemas
noɥʇʎԀʎzɐɹƆ
consulte a minha resposta de atualização, @josh
noɥʇʎԀʎzɐɹƆ 2/08/16
@ noɥʇʎԀʎzɐɹƆ Não, a menos que você esteja usando, por exemplo, memorização. : P
Mateen Ulhaq

Respostas:

281

Seu segundo caminho está correto.

def foo(opts: dict = {}):
    pass

print(foo.__annotations__)

isso gera

{'opts': <class 'dict'>}

É verdade que não está listado no PEP 484 , mas as dicas de tipo são uma aplicação de anotações de funções, documentadas no PEP 3107. A seção de sintaxe deixa claro que os argumentos das palavras-chave funcionam com as anotações de funções dessa maneira.

Eu desaconselho fortemente o uso de argumentos de palavras-chave mutáveis. Mais informações aqui .

noɥʇʎԀʎzɐɹƆ
fonte
1
Consulte legacy.python.org/dev/peps/pep-3107/#syntax . A dica de tipo é apenas uma aplicação de anotações de função.
Chepner
@chepner true. não sabia que o PEP 3107 tinha algo sobre argumentos de palavras-chave.
noɥʇʎԀʎzɐɹƆ
2
Uau, eu não sabia sobre os argumentos padrão mutáveis ​​em Python ... especialmente provenientes de Javascript / Ruby, onde os argumentos padrão funcionam de maneira diferente. Não vou repetir o que já foi dito ad nauseum sobre o SO, apenas estou feliz por ter descoberto isso antes que me mordesse. Obrigado!
Josh2
6
Sempre fui aconselhado a usar None, em vez de um tipo mutável como {} ou [] ou um objeto padrão, pois as mutações nesse objeto sem uma cópia aprofundada persistirão entre as iterações.
26418 MrMesees
2
definir funções suficientes com argumentos nomeados mutáveis e é apenas uma questão de tempo antes de encontrar-se olhando para trás em uma sessão de depuração 4 horas questionando suas escolhas de vida
Joseph Sheedy
20

Se você estiver usando digitação (introduzido no Python 3.5), poderá usar typing.Optional, onde Optional[X]é equivalente Union[X, None]. É usado para sinalizar que o valor explícito de Noneé permitido. Desde a digitação .

def foo(arg: Optional[int] = None) -> None:
    ...
Tomasz Bartkowiak
fonte
2
Não deveria haver espaço em branco em torno da entrada =, Optional[int] = Nonecomo é a convenção para argumentos de palavras-chave sem sugestões de tipo?
actual_panda 24/03
7

Eu vi recentemente essa frase:

def foo(name: str, opts: dict=None) -> str:
    opts = {} if not opts else opts
    pass
Kirkalicious
fonte
Olá @Kirkalicious, obrigado pela sua resposta. Você poderia explicar como isso funciona?
Nathan
1
O ditado vazio transmitido como parâmetro padrão é o mesmo ditado para cada chamada. Portanto, se a função a modificar, a próxima vez padrão será o valor alterado da última vez. Tornar Noneo padrão e depois verificar dentro do método evita esse problema, alocando um novo ditado cada vez que o método é chamado.
Ian Goldby