for some readability and searchability, here is the typed out code
def counter(func):
def wrapper(*args, **kwargs):
wrapper.count += 1
return func (*args, **kwargs)
wrapper.count = 0
return wrapper
@counter
def foo():
print('calling foo()')
foo()
foo()
print('foo() was called {} times.'.format(foo.count))
currently learning how decorator works...encounter this bit of code
couldn't understandwrapper.count = 0
and how when using the decorate in the following code, that the wrapper.count = 2
but not reset to 0
does this have anything to do with closure?
I visited other post which contains similar problem. the answer wasn't that clear to me
can anyone explain the logic behind this code?
Thanks!
In python, functions are first-class objects, which means that functions themselves are objects, and can be treated as such -- you can assign them to a variable, you can set attributes, etc.
So the line wrapper.count = 0
sets the count
attribute for the wrapper
object to the integer 0
. The fact that wrapper
is a function is irrelevant for now.
The way the wrapper
function is defined, every time you call wrapper
, the function increments its own count
attribute.
Now, when you use counter
as a decorator, the decorated function is replaced by the value that your decorator returned. It would be as if you did something like this:
def foo():
print("Calling foo()")
def counter(func):
def wrapper(*args, **kwargs):
wrapper.count += 1
func(*args, **kwargs)
wrapper.count = 0
return wrapper
# These two lines are equivalent to decorating foo with @counter
wrapping_func = counter(foo)
foo = wrapping_func
So when you call foo()
, you're actually calling the wrapper
function object that was returned when you decorated foo
with @counter
(i.e. wrapping_func
). This wrapper
does two things:
.count
attributefoo
function with whatever args you passedSince you called foo()
two times, the .count
was incremented two times
Later, when you access foo.count
, you're actually accessing the count
attribute for the wrapper
object that we talked about earlier (wrapping_func.count
), which is 2
.