Python Forum
the order of running code in a decorator function - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: the order of running code in a decorator function (/thread-41090.html)



the order of running code in a decorator function - akbarza - Nov-09-2023

hi
in below code:
# from:https://python.coderz.ir/lessons/l14-recursive-  \
# functions-and-memoization-in-python.html 

def logger(func):
     print('Decorator is created!')
     def func_wrapper(number):
         print(f'New factorial call with parameter: {number}')
         result = func(number)
         print (f'factorial({number}) ==> {result}')
         return result
     return func_wrapper

@logger
def factorial(n):
    if n <= 1:
         return 1
    else:
         return n            #* factorial(n - 1)

def test():
     print("it is a test")

if __name__=="__main__" :
    test() 
    print(f"factoril(5) is : {factorial(5)}")
I ran and debugged the above code in idle.
the order of running lines was: 4,13,14,13,5,6,11,14,20,23,24,21,25,7,8,15,18,9,10 .
the above code is a decorator function. why the order of running lines is as above line? plz, explain.
thanks


RE: the order of running code in a decorator function - deanhystad - Nov-09-2023

The factorial function is more interesting when it works.
def logger(func): # 1
     print(f"{func.__name__} wrapped by logger.") #2
     def func_wrapper(number): #3
         print(f"{func.__name__}({number})") # 4
         result = func(number) # 5
         print (f'==> {result}') # 6
         return result # 7
     return func_wrapper # 8

print("Decorating factorial") #10
@logger # 11
def factorial(n): # 12
    if n <= 1: # 13
         return 1 # 14
    else: # 15
         return n * factorial(n-1) # 16

print("Using the wrapped function") # 18
print(f"factorial(5) is : {factorial(3)}") # 19
Output:
Decorating factorial factorial wrapped by logger. Using the wrapped function factorial(3) factorial(2) factorial(1) ==> 1 ==> 2 ==> 6
The first two output lines:
Output:
Decorating factorial factorial wrapped by logger.
Show that the logger function gets called when we wrap the factorial function, not when the factorial function gets called at the end of the program.

This code:
@logger # 11
def factorial(n): # 12
replaces "factorial" with "func_wrapper". When the program later calls "factorial(5)" it is really calling "func_wrapper(5)",

The program calls "func_wrapper" here:
print(f"factorial(5) is : {factorial(3)}") # 19
So we begin executing func_wrapper's code.
         print(f"{func.__name__}({number})") # 4
         result = func(number) # 5
         print (f'==> {result}') # 6
         return result # 7
This line:
result = func(number) # 5)
calls "func" which is the original "factorial" function, so we start executing the original factorial function code:
    if n <= 1: # 13
         return 1 # 14
    else: # 15
         return n * factorial(n-1) # 16
When we get to this line:
return n * factorial(n-1) # 16
We recursively call the "factorial" function. But remember, the factorial function has been replaced with a call to "func_wrapper" so we find ourselves here:
         print(f"{func.__name__}({number})") # 4
         result = func(number) # 5
         print (f'==> {result}') # 6
         return result # 7
The end result is that the program lines are executed in this order:
print("Decorating factorial") #10
def logger(func): # 1
     print(f"{func.__name__} wrapped by logger.") #2
     return func_wrapper # 8
print("Using the wrapped function") # 18
factorial(3)
    def func_wrapper(3): #3
         print(f"{func.__name__}({3})") # 4
         result = func(3) # 5
def factorial(3): # 12
    if 3 <= 1: # 13
    else: # 15
         return 3 * factorial(2) # 16
    def func_wrapper(2): #3
         print(f"{func.__name__}({2})") # 4
         result = func(2) # 5
def factorial(2): # 12
    if 2 <= 1: # 13
    else: # 15
         return 2 * factorial(1) # 16
    def func_wrapper(1): #3
         print(f"{func.__name__}({1})") # 4
         result = func(1) # 5
def factorial(1): # 12
    if 1 <= 1: # 13
        return 1 # 14
        print (f'==> {1}') # 6
        return 2 # 7
        print (f'==> {2}') # 6
        return 6 # 7
        print (f'==> {6}') # 6
        return result # 7
print(f"factorial(5) is : {6}") # 19



RE: the order of running code in a decorator function - akbarza - Nov-10-2023

(Nov-09-2023, 01:13 PM)deanhystad Wrote:

thanks very much Smile Heart LOL
plz, replace factorial(5) with factorial(3). thanks again