|
|
|
#https://www.datacamp.com/community/tutorials/decorators-python
|
|
|
|
#A an example of how this can be actually useful is here:
|
|
|
|
#https://www.codementor.io/sheena/advanced-use-python-decorators-class-function-du107nxsv
|
|
|
|
|
|
|
|
def basicdeco(func):
|
|
|
|
'''A basic wrapper that just adds things
|
|
|
|
'''
|
|
|
|
def wrapper():
|
|
|
|
print('Some code inside the wrapper runs here')
|
|
|
|
return func() #function has to run unless you want to run something like ()()
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
def deco1(func):
|
|
|
|
'''A wrapper that reads args and kwargs and does nothing with them
|
|
|
|
#print('before wrapper 2: runs on definition')
|
|
|
|
Note that placing things before the wrapper will case them to run before the
|
|
|
|
decorated function call because they must run to wrap the function
|
|
|
|
'''
|
|
|
|
|
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
print("This is decorated and took arguments (args, kwargs)")
|
|
|
|
print(args, kwargs)
|
|
|
|
print("but didn't pass them to the wrapped function")
|
|
|
|
return func()
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
def deco2(func):
|
|
|
|
'''A wrapper that reads args and kwargs and passes them to the function
|
|
|
|
#print('before wrapper 2: runs on definition')
|
|
|
|
Note that placing things before the wrapper will case them to run before the
|
|
|
|
decorated function call because they must run to wrap the function
|
|
|
|
|
|
|
|
Any positional arguments from the function are passed along with args.
|
|
|
|
'''
|
|
|
|
|
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
print("This is decorated and took arguments (args, kwargs)")
|
|
|
|
print(args, kwargs)
|
|
|
|
print("but didn't pass them to the wrapped function")
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
def deco3(*args, **kwargs):
|
|
|
|
'''This time it is the *decorator* that takes arguments, then passes them to
|
|
|
|
the decorated function. You have to write a decorator *within* a decorator
|
|
|
|
print('whatever') #would also run on wrap
|
|
|
|
|
|
|
|
Remember that wrappers can access variables outside their scope, but not
|
|
|
|
vice versa, so the args and kwargs can filter down.
|
|
|
|
'''
|
|
|
|
def insidedeco(func):
|
|
|
|
print('These are the decorator args, kwargs:', args, kwargs)# prints on wrap
|
|
|
|
def wrapper(*args1, **kwargs1):
|
|
|
|
print("This is the decorated nested wrapper")
|
|
|
|
print("Decorator variables", args, kwargs)
|
|
|
|
print("Inner wrapper variables", args1, kwargs1)
|
|
|
|
return func(*args1, **kwargs1)
|
|
|
|
return wrapper
|
|
|
|
return insidedeco
|
|
|
|
|
|
|
|
def practical_example(func):
|
|
|
|
'''A function counter wrapper'''
|
|
|
|
def wrapper(*args, **kwargs):
|
|
|
|
wrapper.count+=1
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
wrapper.count=0 #wrapper must be assigned first! That's why this is at the bottom.
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
@basicdeco
|
|
|
|
def testme0():
|
|
|
|
print('@basic deco test function')
|
|
|
|
print('Undecorated function takes no arguments')
|
|
|
|
print(30*'_')
|
|
|
|
|
|
|
|
@deco1
|
|
|
|
def testme1():
|
|
|
|
print('@deco1 test function')
|
|
|
|
print(30*'_')
|
|
|
|
|
|
|
|
@deco2
|
|
|
|
def testme2(positional):
|
|
|
|
print('@deco 2 test function')
|
|
|
|
print('positional variable', positional)
|
|
|
|
print(30*'_')
|
|
|
|
|
|
|
|
@deco3(deco3var="bollocks")
|
|
|
|
def testme3(positional, *args, **kwargs):
|
|
|
|
print('@deco3 test function')
|
|
|
|
print('positional', positional)
|
|
|
|
print('args, kwargs from decorated function:', args, kwargs)
|
|
|
|
print(30*'_')
|
|
|
|
|
|
|
|
@practical_example
|
|
|
|
def countme():
|
|
|
|
'''see https://stackoverflow.com/questions/44968004/python-decorators-count-function-call
|
|
|
|
for how the counting variable works
|
|
|
|
'''
|
|
|
|
print('I count for something:', countme.count)
|
|
|
|
print(30*'_')
|
|
|
|
|
|
|
|
@practical_example
|
|
|
|
def second_count():
|
|
|
|
print('I also count as a separate object', second_count.count)
|
|
|
|
print(30*'_')
|
|
|
|
|
|
|
|
def wo_decorator_syntax():
|
|
|
|
'''Just to show how it works without syntax'''
|
|
|
|
print('Manually wrapped')
|
|
|
|
print(30*'_')
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
print('__main__ starts running here___')
|
|
|
|
print(30*'_')
|
|
|
|
#decorator without shorthand
|
|
|
|
basicdeco(wo_decorator_syntax)()
|
|
|
|
|
|
|
|
#decorators in action
|
|
|
|
testme0()
|
|
|
|
testme1(name='PassedVariable')
|
|
|
|
testme2("myPositionalVariable")
|
|
|
|
testme3("positionalVar", name=37)
|
|
|
|
for i in range(10):
|
|
|
|
countme()
|
|
|
|
for i in range(5):
|
|
|
|
second_count()
|