** kwargs é um antipadrão?

15

Temos muito código em nossa base de código interna que chama nossas bibliotecas internamente - essas bibliotecas costumam ter muitos argumentos (pense em matplotlib) e nosso código geralmente executa apenas uma tarefa específica e simplesmente passa **kwargspara a próxima função chamada.

Por exemplo:

def our_method(dataframe, **kwargs):
    result = do_something_with_data(dataframe)
    external_module.draw(result, **kwargs)

Embora **kwargsnos impeça de repetir todos os parâmetros em nossa declaração de método, também torna extremamente opaco quais argumentos são válidos ao chamar our_method- eu tenho que saber qual método é chamado e que muitas vezes não quero saber.

Qual é a sua opinião sobre isso?

Christian Sauer
fonte

Respostas:

15

Como seu código é usado pelos desenvolvedores? Em outras palavras, o que exatamente eles fazem para determinar quais argumentos devem ser usados ​​e como?

  • Se eles dependem da documentação gerada automaticamente a partir do seu código e o gerador não tem idéia do que fazer **kwargs, isso é realmente problemático. Em vez de encontrar a lista de argumentos e seu significado na documentação, eles não têm absolutamente nenhuma informação, exceto o vago "leva alguns argumentos".

    Esse problema provavelmente pode ser resolvido documentando o método manualmente, substituindo a documentação gerada automaticamente. Isso requer trabalho extra do implementador do método, mas lembre-se de que o código (e sua documentação) é lido com muito mais frequência do que está escrito.

  • Se o código é sua documentação, os desenvolvedores que usam o método **kwargsprecisam de duas etapas adicionais: eles precisam não apenas observar a assinatura do método, mas também sua implementação real, a fim de encontrar o outro método que ele realmente chama. Então, eles precisam seguir esse outro método para finalmente encontrar o que estavam procurando.

    Isso não envolve muito esforço, mas, mesmo assim, o esforço deve ser repetido várias vezes. A pior parte é que você não pode ajudá-los adicionando documentação: se você comentar seu método, listando os argumentos reais, há um grande risco de que a próxima versão da biblioteca que seu método chama tenha argumentos diferentes e sua documentação estar desatualizado, pois ninguém se lembrará de que precisa ser mantido atualizado.

Minha recomendação é confiar **kwargsapenas em métodos com escopo reduzido. Métodos privados (e privados em um contexto de Python, refiro-me a métodos iniciados por _) que são usados ​​em poucos lugares da classe são bons candidatos, por exemplo. Por outro lado, métodos usados ​​por dezenas de classes em toda a base de código são candidatos muito ruins.

Afinal, não é preciso muito esforço para reescrever os argumentos de um método que você chama dentro do método que você escreve. Felizmente, a maioria dos métodos não leva mais que seis a oito argumentos e, se o fizer, pergunte a si mesmo se você não deveria refatorar o código. Em todos os casos:

  • Tornar explícitos os argumentos dentro do seu método não requer muito esforço,

  • Você pode, posteriormente, validar os argumentos de qualquer maneira (embora se você confiar apenas nesse ponto para tornar os argumentos explícitos, violará o YAGNI).

Arseni Mourzenko
fonte
Eu realmente gosto desta resposta e acho que é uma boa. Infelizmente, grande parte do nosso código possui muitos métodos públicos usando esse padrão. Mas agora eu tenho argumentos que devemos mudá-lo (e matplotlib gota, nunca vi um "interface" crappier ..)
Christian Sauer
3

Se a função de próximo nível tiver um __doc__, você poderá copiar o __doc__ para sua nova função.

Por exemplo:

def a(x):
    """This function takes one parameter, x, and does nothing with it!"""
    pass

def b(**kwargs):
    a(**kwargs)

b.__doc__=a.__doc__

Isso pode se aplicar recursivamente e pode ser aplicado por um decorador (o que pode ser útil se você estiver fazendo isso em massa de qualquer maneira). A string __doc__ também poderia ser manipulada para adicionar mais ao final. Isso significa que os parâmetros mostrados ainda seriam kwargs, mas pelo menos há documentação na ajuda que descreve os parâmetros reais.

AMADANON Inc.
fonte