Я пытаюсь понять, как использовать два декоратора для одной функции со следующим кодом:

def fxn(func):
    print("fxn_outer 1")
    def fxn_inner(*args, **kwargs):
        print("fxn_inner 1")
    return fxn_inner

def fxn2(func):
    print("fxn_outer 2")
    def fxn_inner2(*args, **kwargs):
        print("fxn_inner 2")
    return fxn_inner2

@fxn
@fxn2
def fxn3 (a, b):
    print(a + b)

fxn3(1, 2)

Я не понимаю, почему fxn_inner выполняется в приведенном выше коде, а fxn_inner2 - нет.

Выход:

fxn_outer 2
fxn_outer 1
fxn_inner 1

Когда я ожидал следующий вывод:

fxn_outer 2
fxn_outer 1
fxn_inner 1
fxn_inner 2

Почему при вызове их обеих выполняется только одна из двух упакованных функций?

1
Matt 8 Окт 2018 в 10:09

2 ответа

Лучший ответ

Декораторы - это просто синтаксический сахар для вызова функции и переназначения имени, поэтому то, что вы делаете, эквивалентно следующему:

fxn3 = fxn2(fxn3)
fxn3 = fxn(fxn3)

fxn3(1, 2)

Так что же происходит? После первого назначения у вас есть fxn3 == fxn2_inner. После второй строки у вас есть fxn3 == fxn_inner.

Но в определении fxnfxn_inner) они просто отбрасывают параметр func! Следовательно, вы не видите звонка, когда звоните fxn3(1,2) == fxn_inner(1, 2).

Если вы хотите, чтобы исходная функция вызывалась, вы должны вызвать func внутри функций *_inner:

def fxn(func):
    print("fxn_outer 1")
    def fxn_inner(*args, **kwargs):
        print("fxn_inner 1")
        return func(*args, **kwargs)
    return fxn_inner

def fxn2(func):
    print("fxn_outer 2")
    def fxn_inner2(*args, **kwargs):
        print("fxn_inner 2")
        return func(*args, **kwargs)
    return fxn_inner2
4
Giacomo Alzetta 8 Окт 2018 в 07:15

Это потому, что вы не выполняете функцию, переданную декоратору (упакованную функцию) в теле вашего декоратора. Таким образом, выполнение останавливается в теле первого декоратора (т.е. fxn_inner).

Обычно то, что вы делаете с декораторами, - это вызов (вызов) декорированной функции внутри декоратора, т.е.

def fxn(func):
    print("fxn_outer 1")
    def fxn_inner(*args, **kwargs):
        print("fxn_inner 1")
        func(*args, **kwargs)
    return fxn_inner

def fxn2(func):
    print("fxn_outer 2")
    def fxn_inner2(*args, **kwargs):
        print("fxn_inner 2")
        func(*args, **kwargs)
    return fxn_inner2

@fxn
@fxn2
def fxn3 (a, b):
    print(a + b)

fxn3(1, 2)
1
Léopold Houdin 8 Окт 2018 в 07:15