Last active
September 19, 2024 19:57
-
-
Save nitori/4dfc60b25bf2e9aa82c39b89202a2e47 to your computer and use it in GitHub Desktop.
Convert a decorator into one that allows multiple forms
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from functools import wraps, partial | |
def argumentarize(func): | |
@wraps(func) | |
def decorator(decorated_func=None, /, **kwargs): | |
if decorated_func is None: | |
# decorator was used with (...) | |
# so return the decorator again as partial | |
return partial(func, **kwargs) | |
if not callable(decorated_func): | |
raise TypeError(f"First argument of {func} must be callable. Use keyword arguments instead.") | |
return func(decorated_func, **kwargs) | |
return decorator | |
# Usage, apply to a decorator. | |
# Signature needs to be: deconame(func, /, **kwargs) | |
@argumentarize | |
def decorate(func, /, **kwargs): | |
@wraps(func) | |
def wrapper(): | |
print("Before", kwargs) | |
r = func() | |
print("After", kwargs) | |
return r | |
return wrapper | |
# Now with that decorator, all three forms are possible: | |
# regular decorator | |
@decorate | |
def foo(): | |
print('foo') | |
# decorator called | |
@decorate() | |
def bar(): | |
print('bar') | |
# decorator called with keyword arguments (no positional possible) | |
@decorate(foo='bar') | |
def spam(): | |
print('spam') | |
def main(): | |
foo() | |
bar() | |
spam() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment