def foo():
return 123
foo()
123
def double(func):
return lambda: func() * 2
foo = double(foo) # redefine foo
foo()
246
# decorators are just syntactic sugar for the above:
@double
def bar():
return "asdf"
bar()
'asdfasdf'
What happens when?
def logit(func):
print('inside logit, before wrapper is defined')
def wrapper(a):
print('inside wrapper, before func is called')
result = func(a)
print ('after call to func, result =', result)
return result
print ('inside logit, after wrapper is defined')
return wrapper
def square(x):
return x * x
square(3)
9
logged_square = logit(square)
inside logit, before wrapper defined inside logit, after wrapper defined
logged_square(4)
inside wrapper, before after call to func, result = 16
16
logged_square() # here the error happens when calling `wrapper`
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-19-76ac99888a96> in <module>() ----> 1 logged_square() TypeError: wrapper() missing 1 required positional argument: 'a'
square() # Note: here it's `square`
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-21-514c4eeba5e6> in <module>() ----> 1 square() # Note: here it's `square` TypeError: square() missing 1 required positional argument: 'x'
Real world example (eg. for testing)
#@with_temporary_transaction
#def foo(db):
# db.execute("...")
#foo()
And something for URL routing in a web framework
globalregistry = {}
def register(path):
print('start of register, path =', path)
def decorator(func):
print('start of decorator, func=', func)
globalregistry[path] = func
setattr(func, 'path', path)
print('end of decorator, returning', func)
return func
print('end of register, returning', decorator)
return decorator
print('A')
print('B')
print(globalregistry)
@register('/index.html')
def webpage():
print('inside webpage')
return "<blink>yeah</blink>"
web = register('/index.html')(webpage)
print(globalregistry)
print(webpage.path)
print('C')
print('calling webpage directly:', webpage())
print('D')
def get(path):
return globalregistry[path]()
print('E')
print('calling via get:', get("/index.html"))
print('F')
A B {} start of register, path = /index.html end of register, returning <function register.<locals>.decorator at 0x108d1c2f0> start of decorator, func= <function webpage at 0x108d1c268> end of decorator, returning <function webpage at 0x108d1c268> start of register, path = /index.html end of register, returning <function register.<locals>.decorator at 0x108d1cc80> start of decorator, func= <function webpage at 0x108d1c268> end of decorator, returning <function webpage at 0x108d1c268> {'/index.html': <function webpage at 0x108d1c268>} /index.html C inside webpage calling webpage directly: <blink>yeah</blink> D E inside webpage calling via get: <blink>yeah</blink> F