Использование функции в качестве аргумента в другой функции через декораторы - PullRequest
0 голосов
/ 13 марта 2020

Вот код:

def smart_divide(func):
   def inner(a,b):
      print("I am going to divide",a,"and",b)
      if b == 0:
        print("Whoops! cannot divide")
      else:
        return func(a,b)
   return inner

@smart_divide
def divide(c,d):
    return c/d

divide(5,2)

Это программа, которая делит два числа и выдает сообщение об ошибке, если знаменатель равен 0.

Мы передаем 5 и 2 как аргумент функции деления. Как функция inner узнает, что значения a и b равны 5 и 2 соответственно?

Согласно тому, что я прочитал в inte rnet: @smart_divide означает, что divide = smart_divide(divide(c,d))

Функция divide имеет параметры c, d, а функция inner имеет параметры a, b. Как переводчик узнает, что a = c и b = d?

Ответы [ 3 ]

1 голос
/ 13 марта 2020

@smart_divide означает, что

result = smart_divide(divide)(c,d)

Это означает, что divide не указывает на функцию inner, а функция inner вызывает исходную функцию divide через func.

0 голосов
/ 13 марта 2020

Ваше понимание декораторов почти правильно, это должно прояснить ситуацию.

Код в вашем примере:

@smart_divide
def divide(c,d):
    return c/d

Функционально идентичен:

def simple_div(c,d):
    return c/d

divide = smart_divide(simple_div)

divide определяется как inner декоратора smart_divide. smart_divide задается simple_div в качестве параметра (func), который inner использует для вызова первоначально оформленного simple_div метода.

Более того: smart_divide можно использовать для украшения несколько функций, потому что новая функция inner создается каждый раз, когда вызывается smart_divide, поэтому ссылка func отличается каждый раз.

0 голосов
/ 13 марта 2020

divide = smart_divide(divide(c,d)) не совсем хорошее описание того, что происходит. Посмотрите на логическое расширение шаг за шагом, в каком-то псевдо- Python:

divide(x, y)
= smart_divide(lambda c, d: c / d)(x, y)
= inner[func ~> lambda c, d: c / d](x, y)
= (def inner(a,b):
      print("I am going to divide",a,"and",b)
      if b == 0:
        print("Whoops! cannot divide")
      else:
        return (lambda c, d: c / d)(a, b))(x, y)
= print("I am going to divide",a,"and",b)
  if y == 0:
      print("Whoops! cannot divide")
  else:
      return (lambda c, d: c / d)(x, y))
= print("I am going to divide",a,"and",b)
  if y == 0:
      print("Whoops! cannot divide")
  else:
      return x / y

Важное, что происходит, это лексическая область видимости . Если вы подставите выражение в другое выражение (операция ~> выше), то вы предполагаете, что имена не будут искажены. То есть (lambda a: lambda b: a)(b)) не становится lambda b: b, но (что-то эквивалентно) lambda b_prime: b. Имена не имеют значения: это называется альфа-эквивалентность .

...