328 lines
6.9 KiB
Python
328 lines
6.9 KiB
Python
#!/usr/bin/env python
|
|
"""
|
|
decorama -- demo of 8 combinations of decorator implementation
|
|
|
|
decorators applied to functions:
|
|
1. decorator without args @deco_func
|
|
decorator returns replacement function
|
|
2. decorator with args @deco_func(arg, ...)
|
|
decorator returns wrapper
|
|
wrapper returns replacement function
|
|
3. class without args @deco_class
|
|
__call__ IS replacement function
|
|
4. class with args @deco_class(arg, ...)
|
|
__call__ RETURNS replacement function
|
|
|
|
#TODO: straighten this mess out
|
|
decorators applied to classes:
|
|
(NOTE: replacement class is frequently the original class, but doesn't have to be)
|
|
5. decorator function without args @deco_func
|
|
decorator returns replacement class
|
|
6. decorator function with args @deco_func(arg, ...)
|
|
decorator returns wrapper
|
|
wrapper return replacement class
|
|
7. decorator class without args @deco_class
|
|
__call__ returns replacement class
|
|
8. decorator class with args @deco_class(arg, ...)
|
|
???
|
|
"""
|
|
|
|
from functools import wraps, update_wrapper
|
|
|
|
|
|
def deco_one(wrapped_function):
|
|
"""
|
|
function without params decorating a function -- the simplest kind of decorator
|
|
|
|
@deco_one
|
|
def bar():
|
|
pass
|
|
|
|
same as
|
|
bar = deco_one(bar)
|
|
|
|
|
|
:param wrapped_function: function to decorate
|
|
:return: replacement function
|
|
"""
|
|
@wraps(wrapped_function)
|
|
def _replacement(*args, **kwargs):
|
|
print("GREETINGS from deco_one!")
|
|
result = wrapped_function(*args, **kwargs)
|
|
return result + 1
|
|
|
|
return _replacement
|
|
|
|
@deco_one
|
|
def target_one():
|
|
print("Hello from target_one")
|
|
return 1
|
|
|
|
print('-' * 60)
|
|
print("** deco_one() **")
|
|
print('-' * 60)
|
|
|
|
result = target_one()
|
|
print("target_one() result is:", result)
|
|
result = target_one()
|
|
print("target_one() result is:", result)
|
|
|
|
print('-' * 60)
|
|
|
|
def deco_two(animal):
|
|
"""
|
|
function with params decorating a function
|
|
|
|
The decorator gets the args, and then returns a wrapper
|
|
function.
|
|
|
|
The wrapper gets the function being wrapped, and returns
|
|
the replacement function.
|
|
|
|
@deco_two('some string')
|
|
def bar():
|
|
pass
|
|
|
|
same as
|
|
bar = deco_two('some_string')(bar)
|
|
or,
|
|
wrapper = foo('blah')
|
|
bar = wrapper(bar)
|
|
|
|
|
|
:param value: decorator parameter
|
|
:return: wrapper function (which returns replacement function)
|
|
"""
|
|
|
|
def wrapper(wrapped_function):
|
|
|
|
@wraps(wrapped_function)
|
|
def _replacement(*args, **kwargs):
|
|
print(("GREETINGS from deco_two -- animal is {}!".format(animal)))
|
|
result = wrapped_function(*args, **kwargs)
|
|
return result
|
|
|
|
return _replacement
|
|
|
|
return wrapper
|
|
|
|
@deco_two('wombat')
|
|
def target_two_alpha():
|
|
print("GREETINGS from target_two_alpha")
|
|
|
|
@deco_two('coatimundi')
|
|
def target_two_beta():
|
|
print("GREETINGS from target_two_beta")
|
|
|
|
target_two_alpha()
|
|
target_two_alpha()
|
|
target_two_beta()
|
|
|
|
class DecoThree():
|
|
"""
|
|
class without params decorating a function
|
|
|
|
__call__() is the replacement function
|
|
|
|
__init__() is passed the wrapped function
|
|
|
|
@DecoThree
|
|
def bar():
|
|
pass
|
|
|
|
same as
|
|
bar = DecoThree(bar)
|
|
|
|
|
|
"""
|
|
|
|
def __init__(self, wrapped_function):
|
|
self.__name__ = wrapped_function.__name__
|
|
self._wrapped = wrapped_function
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
print("GREETINGS from deco_three!")
|
|
result = self._wrapped(*args, **kwargs)
|
|
return result + 3
|
|
|
|
|
|
class DecoFour():
|
|
"""
|
|
class with params decorating a function
|
|
|
|
__call__() RETURNS the replacement function
|
|
|
|
|
|
@deco_four('blah')
|
|
def bar():
|
|
pass
|
|
|
|
same as
|
|
bar = deco_four('blah')(bar)
|
|
or,
|
|
wrapper = deco_four('blah')
|
|
bar = wrapper(bar)
|
|
"""
|
|
|
|
def __init__(self, value):
|
|
self._value = value
|
|
|
|
def __call__(self, wrapped_function):
|
|
@wraps(wrapped_function)
|
|
def _replacement(*args, **kwargs):
|
|
print(("GREETINGS from deco_four -- value is {}!".format(self._value)))
|
|
result = wrapped_function(*args, **kwargs)
|
|
return result + 4
|
|
|
|
return _replacement
|
|
|
|
|
|
print("Function decorators:")
|
|
|
|
|
|
@deco_one
|
|
@deco_two('APPLE')
|
|
@DecoThree
|
|
@DecoFour('BANANA')
|
|
def target_function(color, value):
|
|
"""
|
|
Target function for decorators 1-4
|
|
|
|
:param color: Color as string
|
|
:param value: Any value
|
|
:return: None
|
|
"""
|
|
print(("Hello from target_function -- color is {} and value is {}".format(color, value)))
|
|
print(("Target function's name is", target_function.__name__))
|
|
return 10 * value
|
|
|
|
|
|
TF_RESULT = target_function('red', 10)
|
|
print(("RESULT is", TF_RESULT))
|
|
print(('-' * 50))
|
|
TF_RESULT = target_function('green', 45)
|
|
print(("RESULT is", TF_RESULT))
|
|
print(('-' * 50))
|
|
print()
|
|
print()
|
|
|
|
|
|
def deco_five(target_class):
|
|
"""
|
|
function without params decorating a class
|
|
|
|
:param target_class: class to be decorated
|
|
:return: modified class
|
|
"""
|
|
print("GREETINGS from deco_five!")
|
|
|
|
@property
|
|
def _temp(self):
|
|
return self._value1
|
|
|
|
target_class.value_one = _temp
|
|
|
|
return target_class
|
|
|
|
|
|
def deco_six(fruit):
|
|
"""
|
|
function with params decorating a class; returns wrapper which is applied to target class
|
|
|
|
:param fruit:
|
|
:return: modified class
|
|
"""
|
|
print("GREETINGS from deco_six!")
|
|
|
|
def wrapper(target_class):
|
|
target_class._fruit = fruit
|
|
|
|
@property
|
|
def _temp(self):
|
|
return self._fruit
|
|
|
|
target_class.fruit = _temp
|
|
|
|
return target_class
|
|
|
|
return wrapper
|
|
|
|
|
|
@deco_five
|
|
@deco_six('MANGO')
|
|
class TargetClass():
|
|
|
|
def __init__(self, v1, v2, v3, v4):
|
|
self._value1 = v1
|
|
self._value2 = v2
|
|
self._value3 = v3
|
|
self._value4 = v4
|
|
|
|
|
|
T1 = TargetClass('fee', 'fi', 'fo', 'fum')
|
|
print(("T1 is", T1))
|
|
print(("value_one:", T1.value_one))
|
|
|
|
print(('-' * 50))
|
|
T2 = TargetClass('eeny', 'meeny', 'miny', 'mo')
|
|
print(("T2:", T2))
|
|
print(("T2.value_one:", T2.value_one))
|
|
print(("T2.fruit:", T2.fruit))
|
|
|
|
print(('-' * 50))
|
|
|
|
|
|
class DecoSeven():
|
|
"""
|
|
class without params decorating a class
|
|
|
|
__new__() returns the modified class (not __init__, because __init__ is *instance* initializer)
|
|
|
|
"""
|
|
|
|
def __new__(cls, class_): # self is the old class
|
|
print("GREETINGS from deco_seven!")
|
|
class_.color = 'blue'
|
|
return class_
|
|
|
|
|
|
@DecoSeven
|
|
class TargetClass():
|
|
pass
|
|
|
|
|
|
T1 = TargetClass()
|
|
print((T1.color))
|
|
print(("T1 id:", id(T1)))
|
|
print((TargetClass.__name__, T1))
|
|
|
|
T2 = TargetClass()
|
|
print((T2.color))
|
|
print(("T2 id:", id(T2)))
|
|
|
|
print(('-' * 50))
|
|
|
|
|
|
class DecoEight():
|
|
"""
|
|
class with params decorating a class
|
|
|
|
__call__() returns the modified class
|
|
"""
|
|
|
|
def __init__(self, color):
|
|
print("GREETINGS from deco_eight!")
|
|
self._color = color
|
|
|
|
def __call__(self, old_class):
|
|
old_class.color = self._color
|
|
return old_class
|
|
|
|
|
|
@DecoEight('purple')
|
|
class TargetClass():
|
|
pass
|
|
|
|
T1 = TargetClass()
|
|
print((T1.color))
|