I am having a problem with the following programm. When I try to run decorator the easier way, using @ like this
def decorator1(fun):
def wrapper():
text = '------'
return text + '\n' + fun + '\n' + text
return wrapper()
def decorator2(fun):
def wrapper():
return fun.upper()
return wrapper()
@decorator1
@decorator2
def function():
return "Hey ya!"
print(function())
Following problems occurs:
Traceback (most recent call last):
File "C:\Python_projects\main.py", line 17, in <module>
def function():
File "C:\Python_projects\main.py", line 13, in decorator2
return wrapper()
File "C:\Python_projects\main.py", line 11, in wrapper
return fun.upper()
AttributeError: 'function' object has no attribute 'upper'
or when I switch the order of decorators then it goes like this:
Traceback (most recent call last):
File "C:\Python_projects\main.py", line 17, in <module>
def function():
File "C:\Python_projects\main.py", line 6, in decorator1
return wrapper()
File "C:\Python_projects\main.py", line 4, in wrapper
return text + '\n' + fun + '\n' + text
TypeError: can only concatenate str (not "function") to str
When I run the code in this way, then it works just fine:
def decorator1(fun):
def wrapper():
text = '------'
return text + '\n' + fun + '\n' + text
return wrapper()
def decorator2(fun):
def wrapper():
return fun.upper()
return wrapper()
def function():
return "Hey ya!"
print(decorator(decorator2(function())))
But it seems like using @ with decorators is much more popular. Do you have any idea what I am doing wrong?
A decorator is a function which is run on another function, as in a function object, not the result of another function. So:
@decorator
def func():
...
Is equivalent to:
def func():
...
func = decorator(func)
Notice that the function func
has never actually been called.
Therefore, within the wrapper function within the decorator, you actually need to call the function yourself. Use, for example, fun().upper()
, not fun.upper()
.
Also, the wrapper function should never be called within the decorator; the function itself should be returned, so return wrapper
not return wrapper()
.
Here is the corrected code:
def decorator1(fun):
def wrapper():
text = '------'
return text + '\n' + fun() + '\n' + text
return wrapper
def decorator2(fun):
def wrapper():
return fun().upper()
return wrapper
@decorator1
@decorator2
def function():
return "Hey ya!"
print(function())