Python decorators are difficult to understand at first.
And even if you think you understand it, it's often not a best-practice implementation.
Meanwhile, what is functools.wraps
that I didn't know until now?
https://docs.python.jp/3/library/functools.html#functools.wraps
@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)(Original)
This is update when defining the wrapper function_wrapper()Is a convenience function that calls as a function decorator.
This is partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)Is equivalent to
Why? If you look at this, it's a mess, but ** Function names and Docstrings will be decorators ** I wonder if that means
Test code
def hoge_decorator(f):
def hoge_wrapper(*args, **kwargs):
"""It's the decorator Docstring"""
print("It's a decorator")
return f(*args, **kwargs)
return hoge_wrapper
@hoge_decorator
def hoge_function():
"""It's the Docstring of the decorating function"""
print("This is the deco function!")
if __name__ == '__main__':
hoge_function()
result
It's a decorator
This is the deco function!
The one you often see. There is no particular problem with the movement.
But ...
def hoge_decorator(f):
def hoge_wrapper(*args, **kwargs):
"""It's the decorator Docstring"""
print("It's a decorator")
return f(*args, **kwargs)
return hoge_wrapper
@hoge_decorator
def hoge_function():
"""It's the Docstring of the decorating function"""
print("This is the deco function!")
if __name__ == '__main__':
hoge_function()
print(hoge_function.__name__)
print(hoge_function.__doc__)
result
It's a decorator
This is the deco function!
hoge_wrapper
It's the decorator Docstring
That? It's funny, isn't it? The hidden attribute output by print is a decorator.
The problem with this is that doctest doesn't work. (I think there are many unit test people ...) Besides, normal operation may not be a problem, but the name is not actually the name of the function that is running. I don't know what you're talking about, but ... it's a development.
functools.wraps
Therefore This is where ** functools.wraps ** comes into play. Let's use it immediately.
import functools
def hoge_decorator(f):
@functools.wraps(f)
def hoge_wrapper(*args, **kwargs):
"""It's the decorator Docstring"""
print("It's a decorator")
return f(*args, **kwargs)
return hoge_wrapper
@hoge_decorator
def hoge_function():
"""It's the Docstring of the decorating function"""
print("This is the deco function!")
if __name__ == '__main__':
hoge_function()
print(hoge_function.__name__)
print(hoge_function.__doc__)
result
It's a decorator
This is the deco function!
hoge_function
It's the Docstring of the decorating function
Sounds good.
doctest
The last is doctest.
By the way, if you do not normally test and if you pass the test, there will be no log, so add -v
as a parameter.
Also, the decorator test is run, so the decorator Docstring has been removed.
import functools
import doctest
def hoge_decorator(f):
def hoge_wrapper(*args, **kwargs):
return f(*args, **kwargs)
return hoge_wrapper
@hoge_decorator
def hoge_function(n):
"""It's the Docstring of the decorating function
>>> hoge_function(2)
4
"""
return n ** 2
if __name__ == '__main__':
doctest.testmod()
result
3 items had no tests:
__main__
__main__.hoge_decorator
__main__.hoge_function
0 tests in 3 items.
0 passed and 0 failed.
Test passed.
After all the test is not running.
import functools
import doctest
def hoge_decorator(f):
@functools.wraps(f)
def hoge_wrapper(*args, **kwargs):
return f(*args, **kwargs)
return hoge_wrapper
@hoge_decorator
def hoge_function(n):
"""It's the Docstring of the decorating function
>>> hoge_function(2)
4
"""
return n ** 2
if __name__ == '__main__':
doctest.testmod()
result
Trying:
hoge_function(2)
Expecting:
4
ok
2 items had no tests:
__main__
__main__.hoge_decorator
1 items passed all tests:
1 tests in __main__.hoge_function
1 tests in 3 items.
1 passed and 0 failed.
Test passed.
The test passed properly.
Recommended Posts