LINUX.ORG.RU

Декоратор и рекурсия в питоне

 


0

3
@foobar
def fact(n):
    return n * fact(n-1)

Вызовы fact внутри самого fact будут происходить с декоратором или нет? Как там вообще идентификаторы лукапятся внутри объявления функции? Для самого названия функции есть какое-нибудь правило или нет?

А если так?

def fact(n):
    return n * fact(n-1)

fact = foobar(fact)

Что за чушь? Первый пример это сахар для второго, поэтому они идентичны.

Вызовы fact внутри самого fact будут происходить с декоратором или нет?

После выполнения fact = foobar(fact) fact нет, а есть то, что вернулось foobar(fact).

Virtuos86 ★★★★★
()
In [1]: def fact(n):
   ...:     return n*fact(n-1)
   ...: 

In [2]: import dis

In [3]: dis.dis(fact)
  2           0 LOAD_FAST                0 (n)
              3 LOAD_GLOBAL              0 (fact)
              6 LOAD_FAST                0 (n)
              9 LOAD_CONST               1 (1)
             12 BINARY_SUBTRACT     
             13 CALL_FUNCTION            1
             16 BINARY_MULTIPLY     
             17 RETURN_VALUE        

LOAD_GLOBAL

Deleted
()

Это легко проверить, просто сделай print в декораторе и смотри есть ли выхлоп в терминале.

anonymous
()
Ответ на: комментарий от Virtuos86

После выполнения fact = foobar(fact) fact нет, а есть то, что вернулось foobar(fact).

То, что fact'а нет после применения декоратора, не отвечает на его вопрос само по себе. Кто знает, может тот вызов внутри функции обращается к оригинальной функции, поскольку декоратор на тот момент еще применился.

anonymous
()
Ответ на: комментарий от anonymous

А мне понравилось. Железная аргументация без запуска самого кода.

nezamudich ★★
()
Ответ на: комментарий от anonymous

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

ТС'у лучше в доки заглянуть, хотя на ЛОР'е интереснее, конечно, спрашивать.

Virtuos86 ★★★★★
()

А почему если импортировать fact и foobar из модуля с помощью from modulename import fact, foobar и декорировать вручную, то декорируется только сама функция, но не рекурсивные вызовы?

# factorial.py

def foobar(func):
    def decorated_func(*args, **kwargs):
        print("decorated by foobar")
        return func(*args, **kwargs)

    return decorated_func


def fact(n):
    if n == 1:
        return 1
    return n * fact(n-1)
# main.py

from factorial import fact, foobar

fact = foobar(fact)

if __name__ == '__main__':
    print(fact(5))

Если запустить main.py, то печатается следующее:

decorated by foobar
120

Только внешний вызов декорировался.

hlebushek ★★
() автор топика
Ответ на: комментарий от hlebushek

Ты же задекорировал функцию в другом модуде, при вычислении в рекурсии сам fact достанет недекорированную функцию из своей области видимости

In [11]: def foobar(func):
   ....:         def decorated_func(*args, **kwargs):
   ....:                 print("decorated by foobar")
   ....:                 return func(*args, **kwargs)
   ....:         return decorated_func
   ....:

In [12]: @foobar
   ....: def fact(n):
   ....:         if n == 1:
   ....:                 return 1
   ....:         return n * fact(n-1)
   ....:

In [13]: fact(5)
decorated by foobar
decorated by foobar
decorated by foobar
decorated by foobar
decorated by foobar
Out[13]: 120

proofit404
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.