Чи є ** kwargs антипатерном?


16

У нашій внутрішній базі коду є багато коду, який викликає наші бібліотеки всередину - у цих бібліотек часто є багато аргументів (думаю, matplotlib), і наш код часто виконує лише певне завдання і просто передає **kwargsнаступну функцію, яку називають.

Наприклад:

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

Хоча **kwargsзаважає нам повторити всі параметри в нашому декларації методу, це також робить надзвичайно непрозорим, які аргументи дійсні при виклику our_method- я повинен знати, який метод викликається, про що я часто не хочу знати.

Що ви ставитесь до цього?

Відповіді:


16

Як ваш код використовують розробники? Іншими словами, що саме вони роблять, щоб визначити, які аргументи слід використовувати і як?

  • Якщо вони покладаються на документацію, автоматично сформовану з вашого коду, і генератор не має поняття, що з цим робити **kwargs, це справді проблематично. Замість того, щоб знайти перелік аргументів та їх значення в документації, вони не мають абсолютно ніякої інформації, окрім розпливчастого «це потребує деяких аргументів».

    Можливо, ця проблема може бути вирішена шляхом документування методу вручну, заміни автоматично створеної документації. Це вимагає додаткової роботи від реалізатора методу, але пам’ятайте, що код (та його документація) читається набагато частіше, ніж написано.

  • Якщо код - це їх документація, розробники, які використовують метод, **kwargsпотребують двох додаткових кроків: їм потрібно не тільки подивитися на підпис методу, але і на його фактичну реалізацію, щоб знайти інший метод, який він насправді викликає. Потім їм потрібно перейти до цього іншого методу, щоб нарешті знайти те, що шукали.

    Це не вимагає великих зусиль, але все-таки зусилля потрібно повторювати знову і знову. Найгірше те, що ви не можете їм допомогти, додавши документацію: якщо ви коментуєте свій метод, перераховуючи фактичні аргументи, є великий ризик, що наступна версія бібліотеки, яку ви називає ваш метод, матиме різні аргументи, і ваша документація буде бути застарілим, оскільки ніхто не згадає, що його потрібно постійно оновлювати.

Моя рекомендація - покладатися **kwargsлише на методи, які мають обмежений обсяг. Приватні методи (і приватні в контексті Python, я маю на увазі методи, починаючи від _), які використовуються в кількох місцях класу, є хорошими кандидатами, наприклад. З іншого боку, методи, якими користуються десятки класів по всій кодовій базі, є дуже поганими кандидатами.

Зрештою, не слід забирати занадто багато зусиль, щоб переписати аргументи методу, який ви викликаєте, у межах написаного методу. Сподіваємось, більшість методів не мають більше шести-восьми аргументів, і якщо вони є, запитайте себе, чи не слід ви переробляти код. У всіх випадках:

  • Здійснення явних аргументів у вашому методі не вимагає великих зусиль,

  • Пізніше ви можете все-таки підтвердити аргументи (хоча якщо ви покладаєтесь лише на цьому, щоб зробити аргументи явними, ви порушите YAGNI).


Мені дуже подобається ця відповідь і я думаю, що це хороша. На жаль, багато нашого коду мають безліч публічних методів, що використовують цю схему. Але тепер у мене є аргументи, що нам слід це змінити (і кинути матплотліб, ніколи не бачив крапперовського "інтерфейсу" ..)
Крістіан Зауер

3

Якщо функція наступного рівня має __doc__, ви можете просто скопіювати __doc__ у вашу нову функцію.

Наприклад:

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

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

b.__doc__=a.__doc__

Це може застосовуватися рекурсивно і може бути застосоване декоратором (що може бути корисним, якщо ви все одно це робите оптом). Рядок __doc__ теж можна маніпулювати, щоб додати більше до кінця. Це означає, що показані параметри все одно будуть кирги, але принаймні є документація у довідці, що описує фактичні параметри.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.