Skip to content

Instantly share code, notes, and snippets.

@jasco
Last active March 30, 2017 05:12
Show Gist options
  • Save jasco/e924c794f066bc64445ef84440ab83d7 to your computer and use it in GitHub Desktop.
Save jasco/e924c794f066bc64445ef84440ab83d7 to your computer and use it in GitHub Desktop.
Configurable python decorators

Decorator class using decorator called methods to configure

Allow the behavior of a decorator to be modified by other decorators.

@mod_b
@mod_a
@base_decorator
def myfunc(): pass

In contrast to a more typical

@arg_decorator(opt_a, opt_b)
def myfunc(): pass

The motivation was a situation where a decorator was used extensively for access control checks. A new situation arose where the access control criteria needed to change for some decorated methods.

Typically this would be a case for using a decorator generator with arguments passed to configure as needed. This would have required updating every instance of the decorator to make it into a function call on the generator.

This decorator class approach allowed the existing decorators to remain unchanged and to add a configuring decorator in the handful of cases in which it was required.

Obviously there is a complexity and clarity trade-off. Perhaps time will reveal whether it is a reasonable trade.

from functools import update_wrapper
class decorator_class:
def __init__(self, func):
update_wrapper(self, func)
self.func = func
self.triggered = False
def __call__(self, *args, **kwargs):
print "I'm a decorator function"
if self.triggered:
print "I'm triggered"
self.func(*args, **kwargs)
def trigger_me(self):
self.triggered = True
def trigger(decor):
decor.trigger_me()
return decor
@trigger
@decorator_class
def wrapme(arg1):
"""Description of wrapme"""
print(arg1)
wrapme('boo')
# I'm a decorator function
# I'm triggered
# boo
print(wrapme.__name__)
# wrapme
print(wrapme.__doc__)
# Description of wrapme
from functools import wraps
def decorator_func(func):
@wraps(func)
def wrapper(*args, **kwargs):
print "I'm a decorator function"
func(*args, **kwargs)
return wrapper
@decorator_func
def wrapme(arg1):
"""Description of wrapme"""
print(arg1)
wrapme('boo')
# I'm a decorator function
# boo
print(wrapme.__name__)
# wrapme
print(wrapme.__doc__)
# Description of wrapme
help(wrapme)
# Help on function wrapme in module __main__:
#
# wrapme(*args, **kwargs)
# Description of wrapme
from functools import update_wrapper
class decorator_class:
def __init__(self, func):
update_wrapper(self, func)
self.func = func
def __call__(self, *args, **kwargs):
print "I'm a decorator function"
self.func(*args, **kwargs)
@decorator_class
def wrapme(arg1):
"""Description of wrapme"""
print(arg1)
wrapme('boo')
# I'm a decorator function
# boo
print(wrapme.__name__)
# wrapme
print(wrapme.__doc__)
# Description of wrapme
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment