The code has been taken from Learning Python 4th Edition by Mark Lutz
class tracer:
def __init__(self, func):
self.calls = 0
self.func = func
def __call__(self, *args):
self.calls += 1
print('call %s to %s' % (self.calls, self.func.__name__))
self.func(*args)
@tracer
def spam(a, b, c):
print(a + b + c)
spam(1, 2, 3)
Also, when I run this code, it doesn't print the sum of 1,2,3 either, but in the book, it's shown that it does! I am left scratching my head at this entire code. I have no idea what is going on in here.
A decorator is called as soon as the decorated function is defined. It is equivalent to writing something like this: def __do_stuff(... ): ...
A decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it. Python allows "nested" functions ie (a function within another function). Python also allows you to return functions from other functions.
What's happening here is the body of the function is being replaced. A decorator like so
@tracer
def spam(...)
...
Is the equivalent of:
def spam(...)
...
spam = tracer(spam)
Now, tracer(spam)
returns an instance of the tracer
class where the original definition of spam
is stored in self.func
class tracer:
def __init__(self, func): #tracer(spam), func is assigned spam
self.calls = 0
self.func = func
Now when you call spam
, (which is actually an instance of tracer
) you invoke the __call__
method defined in the tracer
class:
def __call__(self, *args):
self.calls += 1
print('call %s to %s' % (self.calls, self.func.__name__))
So in essense this __call__
method has overriden the body origianlly defined in spam
. To have the body execute, you need to call the function stored in the instance of the tracer
class like so:
def __call__(self, *args):
self.calls += 1
print('call %s to %s' % (self.calls, self.func.__name__))
self.func(*args)
Resulting in
>>>
call 1 to spam
6
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With