Когда в Python для аргумента следует установить значение None?

Sep 10 2020

В центре моего вопроса - дизайн.

Если у меня есть аргумент, который может быть, Noneи он передается между несколькими функциями до тех пор, пока не будет наконец использован, какая функция должна рассматривать его как аргумент по умолчанию?

Например, предположим следующий блок кода:

def foo(a):
 b = # some code block to assign b
 return bar(a, b)

def bar(a, b):
 c = # some code block to assign c
 return baz(a, b, c)

def baz(a, b, c):
 return a + b + c

Значение по умолчанию должно быть установлено только в, fooа все остальные функции должны ожидать, что аргумент является обязательным (например, foo(a=None); bar(a, b); baz(a, b, c))? Или есть дизайн получше?

И если нужна была проверка типа, какая функция для этого больше всего подходит?

Ответы

4 DocBrown Sep 10 2020 at 09:55

Чтобы принять разумное решение относительно аргументов по умолчанию, нужно знать контекст, в котором эти функции будут использоваться! .

Если fooон будет частью общедоступного API модуля или компонента, то предоставление аргумента по умолчанию a=Noneпредполагает, что существует частый сценарий использования, при котором foo()будет вызываться в этой форме без каких-либо параметров. Та же мера верна для barи baz:

  • эти функции используются только «внутренне»? Тогда вы точно знаете, сохранит ли аргумент по умолчанию вам повторяющийся код, или если он bar(a, b)вызывается только один или два раза, возможно, только внутри foo, и в этом случае аргумент по умолчанию не выгоден

  • или эти функции также являются частью общедоступного API? Затем вам нужно оценить, как будет выглядеть их типичный сценарий использования (для которого вам нужен реальный контекст). Если вы хотите предоставить возможность для barвызова like bar(b="some value"), то необходимо предоставить подпись bar(a=none, b), независимо от параметра по умолчанию в foo.

Поэтому для принятия решения о аргументах по умолчанию не смотрите на сторону реализации, смотрите на сторону использования!

Что касается проверки типа: я не являюсь экспертом по этой теме в Python, но я предполагаю, что если вы хотите добавить аннотации типов для анализа статического типа, IMHO будет иметь смысл добавлять их на каждом уровне цепочки вызовов (это может быть фактически обязателен для работы анализа типов). Если «самая внутренняя функция» ( baz) ожидает только аргументы определенного типа, вы, очевидно, должны поместить туда аннотации типов. Это, однако, означает, что fooи barбудет правильно работать только с аргументами одного и того же типа, что означает, что для анализа статического типа там тоже требуются аннотации.