Каков логический порядок выполнения этой украшенной Python-функции? - PullRequest
4 голосов
/ 24 октября 2011

Представьте себе:

def b1(fnc):
  print "b1"
  return fnc

@b1
def a1():
  print "a1"

if __name__ == "__main__":
  a1() # will print b1 a1

Итак, когда я использую @b1, a1 превращается в a1 = b1(a1), верно?Затем, когда я говорю:

a1()

Это превращается в:

b1(a1)

И затем переходит к:

print "b1"
return fnc

Где / Кто именно вызывает fnc?У меня такое чувство, что я задаю очень глупый вопрос, но я хочу понять.

Ответы [ 4 ]

7 голосов
/ 24 октября 2011

Декоратор выполняется только один раз.Он берет вызываемый объект и возвращает вызываемый объект. Возвращаемый объект используется вместо a1.

Другими словами, b1 вызывается в точке, где a1определено.Он печатает "b1" и возвращает a1 без изменений.Поскольку он возвращает a1 без изменений, b1 не играет никакой роли при последующих вызовах a1.

Поэтому следующий комментарий не совсем корректен:

  a1() # will print b1 a1

На самом деле

  • a1() печатает только "a1".
  • "b1", который вы видите, печатается как @b1 / def a1():.

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

def b1(fnc):
  print "b1"
  return fnc

@b1
def a1():
  print "a1"

if __name__ == "__main__":
  print 'in __main__'
  a1()
  a1()

Наконец, чтобы добиться того эффекта, который вы искали, декоратору потребуется вернуть другой вызываемый объект:

def b1(fnc):
  def decorated():
    print "b1"
    return fnc()
  return decorated

@b1
def a1():
  print "a1"

if __name__ == "__main__":
  print 'in __main__'
  a1()
  a1()

Здесь довольно ясно, ктозвонит fnc().

1 голос
/ 24 октября 2011

Кто звонит fnc?

В основном, () позади a1 в последней строке кода.

Итак, что происходитна?Декораторы предназначены для изменения поведения функций.

Таким образом, когда вы что-то декорируете, создается новая функция на основе того, что декоратор возвращает.Это означает, что декоратор запускается один раз , когда a1 определено .Вот пример, который демонстрирует это:

print 'def b1'
def b1(fnc):
  print "b1"
  return fnc

print 'def a1'
@b1
def a1():
  print "a1"

if __name__ == "__main__":
  print 'main'
  a1() # will print b1 a1

Это напечатает:

def b1
def a1
b1
main
a1

Как вы можете видеть, декоратор b1 вызывается до выполнения main.

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

Это то, что «оператор вызова» () после a1в последней строке кода делает.

0 голосов
/ 03 апреля 2012

Давайте назовем a1_prev, функцию a1 перед оформлением, a1() превращается в

b1(a1_prev)()

и не только b1(a1_prev), последние () - это те, кто вызывает func возвращено b1.

0 голосов
/ 24 октября 2011

Ознакомьтесь с верхним ответом Как составить цепочку декораторов функций?

. В этом вы заметите, что определение декоратора фактически преобразует функцию и возвращает преобразованнуюфункция.Это выполняется один раз при оформлении (когда применяется символ @ ...).В приведенном вами примере b1 не определяет преобразование, но оператор print по-прежнему выполняется.Затем возвращается исходная функция, поэтому a1 не получает «переопределение».тогда действие декоратора b1 - ничего не делать с a1.

...