I am trying to learn about closures and decorators in python.
I understand that, in my code below, variable fn has been assigned to a 'cell' object, which will itself reference the function object my_func
once that is passed as an argument to function "outer" and outer is called.
I do not understand why, when fn
is called from within function inner
(the decorated function), it calls inner
(ie the decorated function) rather than the 'original' undecorated my_func function (which is what was passed as an argument to "outer")
I had not anticipated that decorating my_func
would cause the cell which i mentioned above to now reference a "different version" of my_func
, which it what it appears from the console output is what has happened.
I therefore have two questions about my code below:
- In the assignment
my_func = outer(my_func)
, what is the "my_func" on the left handside of the assignment? I had understood it was a variable called "my_func" which masked the functionmy_func
(but that the original function which was defined asmy_func
remained). - why does
fn
now appear to referenceinner
rather thanmy_func
which is what was passed. Maybe it does not in fact do this and I am misunderstanding something.
Any help would be gratefully appreciated.
I have wrote the following code:
def my_func():
print(f"This function's name is '{my_func.__name__}'. Its ID is {hex(id(my_func))}")
return None
def outer(fn):
def inner():
print(f"The function that is about to be called is called '{fn.__name__}'. Its ID is {hex(id(fn))}")
return fn()
return inner
print(f"I have created a function called '{my_func.__name__}'. Its ID is {hex(id(my_func))}")
my_func = outer(my_func)
print(f"The function has been decorated. The variable 'my_func' refers to a function object called '{my_func.__name__}'. Its ID is {hex(id(my_func))}\n")
my_func()
The following is printed to the console:
I have created a function called 'my_func'. Its ID is 0x7f3c040cbb50
The function has been decorated. The variable 'my_func' refers to a function object called 'inner'. Its ID is 0x7f3c040f4040
The function that is about to be called is called 'my_func'. Its ID is 0x7f3c040cbb50
This function's name is 'inner'. Its ID is 0x7f3c040f4040
What I was expecting is:
I have created a function called 'my_func'. Its ID is 0x7f3c040cbb50
The function has been decorated. The variable 'my_func' refers to a function object called 'inner'. Its ID is 0x7f3c040f4040
The function that is about to be called is called 'my_func'. Its ID is 0x7f3c040cbb50
The function that is about to be called is called 'my_func'. Its ID is 0x7f3c040cbb50
I recognize that it is my_func = outer(my_func)
which is the cause of the 'issue', but I do not understand why. I had expected that the closure fn would continue to reference the "original" undecorated my_func
function. I dont understand why assigning my_func
to outer(my_func)
appears to 'change' the object that fn refers to.