Нестандартные необязательные аргументы по умолчанию

У меня есть две функции:

def f(a,b,c=g(b)):
    blabla

def g(n):
    blabla

c необязательный аргумент в функции f, Если пользователь не указывает его значение, программа должна вычислить g(b), и это будет значение c, Но код не компилируется - он говорит, что имя 'b' не определено. Как это исправить?

Кто-то предложил:

def g(b):
    blabla

def f(a,b,c=None):
    if c is None:
        c = g(b)
    blabla

Но это не работает. Может быть, пользователь намеревался c быть None, а затем c будет иметь другое значение.

5 ответов

Решение
def f(a,b,c=None):
    if c is None:
        c = g(b)

Если None может быть допустимым значением для c тогда вы делаете это:

sentinel = object()
def f(a,b,c=sentinel):
    if c is sentinel:
        c = g(b)

Вы не можете сделать это таким образом.

Внутри функции проверьте, указан ли c. Если нет, сделайте расчет.

def f(a,b,c=None):
    if c == None:
        c = g(b)
    blabla

Ценность c будет оцениваться (g(b)) во время компиляции. Тебе нужно g определено ранее f следовательно. И конечно вам нужен глобальный b переменная, которая будет определена на этом этапе тоже.

b = 4

def g(a):
    return a+1

def test(a, c=g(b)):
    print(c)

test(b)

отпечатки 5.

Проблема с

sentinel = object()
def f(a, b, c=sentinel):
  if c is sentinel:
    c = g(b)

в том, что sentinel является глобальным / общедоступным, если этот код не является частью функции / метода. Так что кто-то еще может позвонить f(23, 42, sentinel), Однако если f является глобальным / публичным, вы можете использовать закрытие, чтобы сделать sentinel local / private, чтобы вызывающая сторона не могла его использовать:

def f():
  sentinel = object()
  def tmp(a, b, c=sentinel):
    if c is sentinel:
      c = g(b)
  return tmp
f = f()

Если вы обеспокоены тем, что статические анализаторы кода могут неправильно понять f затем вы можете использовать те же параметры для фабрики:

def f(a, b, c=object()): #@UnusedVariable
  sentinel = object()
  def tmp(a, b, c=sentinel):
    if c is sentinel:
      c = g(b)
  return tmp
f = f(23, 42)
def f(a,b,*args):
    if len(args) == 1:
        c = args[0]
    elif len(args) == 0:
        c = g(b)
    else:
        raise Exception('Function takes 2 or 3 parameters only.')
    blabla

def g(n):
    blabla

Вы можете, вероятно, структурировать это лучше, но это главная идея. В качестве альтернативы вы можете использовать **kwargs и использовать функцию как f(a,b,c=Something)Вы просто должны изменить f соответственно.

Документация

Другие вопросы по тегам