psb psb - 3 months ago 6
Python Question

"Push" attribute from decorator to decorated function in Python

Some basic question from beginner. Is there a way to "push" attribute to a decorated function not using function arguments ?

import sys
from functools import wraps


def decorator_(func):
@wraps(func)
def newfunc():
func.some_attr = 'some_attr'
func()
return newfunc

@decorator_
def decorated_function():
# ??? access some_attr ???
print some_attr

def main():
decorated_function()

if __name__ == '__main__':
sys.exit(main())


Thanks in advance.

Answer

If you set the attribute on new_func instead, you can access it simply as decorated_function.some_attr:

def decorator_(func):
    @wraps(func)
    def newfunc():
        newfunc.some_attr = 'some_attr'
        func()
    return newfunc

@decorator_
def decorated_function():
    print(decorated_function.some_attr)

Otherwise, wraps makes the original function available as decorated_function.__wrapped__ in Python 3:

def decorator_(func):
    @wraps(func)
    def newfunc():
        func.some_attr = 'some_attr'
        func()
    return newfunc

@decorator_
def decorated_function():
    print(decorated_function.__wrapped__.some_attr)

In Python 2, the __wrapped__ is not set by wraps, so we need to set it up manually:

def decorator_(func):
    @wraps(func)
    def newfunc():
        func.some_attr = 'some_attr'
        func()
    newfunc.__wraps__ = func
    return newfunc

However, this sounds like an XY problem; if you want to pass a value to the decorated_function you should let decorator_ pass it as an argument instead.