Reputation: 39
registry = []
def register(func):
print('running register(%s)' % func)
registry.append(func)
return func
@register
def f1():
print('running f1()')
@register
def f2():
print('running f2()')
def f3():
print('running f3()')
def main():
print('running main()')
print('registry ->', registry)
f1()
f2()
f3()
if __name__=='__main__':
main()
in the above program why doesnt the f1() f2() and f3() in main work if return func is not used in the register function
Upvotes: 0
Views: 56
Reputation: 51998
A decorator is a higher-order function which takes a function as input and returns a function as output. Decorator syntax is a way of calling this higher order function.
The lines
@register
def f1():
print('running f1()')
are equivalent to the lines
def f1():
print('running f1()')
f1 = register(f1)
Usually, the decorator modifies the decorated function. In this case it is returned unmodified. But -- it is still returned. If the decorator returned nothing then the decorator would replace f1
by None
(which wouldn't be very useful). This particular decorator is called for its side effects (registering a function). The fact that it returns an unmodified function doesn't mean that it isn't called.
The output that you see should make sense now:
running register(<function f1 at 0x0000000001DCCBF8>)
running register(<function f2 at 0x0000000003566D90>)
running main()
registry -> [<function f1 at 0x0000000001DCCBF8>, <function f2 at 0x0000000003566D90>]
running f1()
running f2()
running f3()
You used @register
twice, which calls register()
twice, before main is run. Neither f1
nor f2
were actually changed by the decorator, hence they work as expected when called in main()
. The printed value of registry
shows that the decorator worked as intended: it registered the decorated f1, f2
but didn't register the undecorated f3
.
On the other hand, if you remove the line return func
from the decorator, you see (something like):
running register(<function f1 at 0x00000000004DCBF8>)
running register(<function f2 at 0x0000000003586D90>)
running main()
registry -> [<function f1 at 0x00000000004DCBF8>, <function f2 at 0x0000000003586D90>]
Traceback (most recent call last):
File "C:\Users\jcoleman\Documents\Programs\PythonScripts\socode.py", line 68, in <module>
main()
File "C:\Users\jcoleman\Documents\Programs\PythonScripts\socode.py", line 64, in main
f1()
TypeError: 'NoneType' object is not callable
The decorator is still called twice -- but they are now (implicitly) returning None
. As soon as f1()
is hit in main
you get a run-time error since at that stage f1
is None
, which isn't callable.
See this question for more on decorators.
Upvotes: 1