Browse Source

A complete explanation of decorators

master
Kashirigi 5 years ago
parent
commit
be5b3210c8
  1. 29
      Python/Decorators/Decorators.py
  2. 123
      Python/Decorators/decoCompleteExample.py
  3. 18
      Python/Decorators/decoratortest.py
  4. 31
      Python/Decorators/successful_decorator.py

29
Python/Decorators/Decorators.py

@ -1,29 +0,0 @@ @@ -1,29 +0,0 @@
def deco(func):
def wrapper(*args, **kwargs):
func(*args, **kwargs)
wrapper.count+=1
wrapper.count=0
return wrapper
def deco2(func):
def wrapper(*args, **kwargs):
print(args)
def fname(*args):
print('args',args)
return fname
@deco2
def fname(arg):
print(arg)
@deco
def main(arg):
print(arg)
for item in range(3):
main(item)
print('count', main.count)
fname('test')

123
Python/Decorators/decoCompleteExample.py

@ -0,0 +1,123 @@ @@ -0,0 +1,123 @@
#https://www.datacamp.com/community/tutorials/decorators-python
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()

18
Python/Decorators/decoratortest.py

@ -1,9 +1,23 @@ @@ -1,9 +1,23 @@
from random import randint
'''
How a decorator works:
1. Create the decorator function. This is what @whatever is. It takes a function as input. It *can* also take parameters as per:
https://www.geeksforgeeks.org/decorators-with-parameters-in-python/
2. Inside that function is a wrapper function. It will take the same number of parameters as the decorated function.
3. Anything inside the wrapper function is defined, not run.
4. The function call with parameters passed through is called. Then the wrapped function is returned.
'''
#this is the decorator
def decor(func): #takes a function as an argument
def x(z): # z = arguments passed from function that was decorated
def x(z): # z = arguments passed from function that was decorated. Note that the number of arguments must be the same.
''' Decorator function wrapper must take the same number of arguments or it will fail
'''
print('now with decoration') #extra shit from the decorator
func(z) #run that function
func(z) #run that function WHEN CALLED ON. Not now, because it is inside a function definition.
return x #return the decorator function
@decor #invoke the decorator

31
Python/Decorators/successful_decorator.py

@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
#import numpy as np
#import time
import math
from math import tan as qe
def deco(func):
def wrapper(y):
ang = y *2 *math.pi/360
return func(ang)
return wrapper #You need two returns! So confusing!
def test(number):
return number
@deco
def test2(number):
return number
print('undecorated')
print(test(45))
print('decorated')
print(test2(45))
print('math.tan')
print(qe(45))
print('math.tan decorated')
test3=deco(qe)
print(type(test3))
print(test3(45))
print(math.tan(45))
Loading…
Cancel
Save