Files
2025-05-20 11:57:43 -04:00

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))