Last active
September 12, 2021 14:25
-
-
Save antibagr/416623e6838c175ccf83f2b9a7d4dbce to your computer and use it in GitHub Desktop.
Dynamic parameterised decorator
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 __future__ import annotations | |
from typing import Any, Callable, Type | |
from dataclasses import dataclass | |
class A: | |
pass | |
@dataclass | |
class A_without_args(A): | |
func: Callable | |
def __call__(self, *args: Any, **kw: Any) -> Any: | |
return self.func(*args, **kw) | |
@dataclass | |
class A_with_args(A): | |
foo: str | |
bar: int | |
def __call__(self, func: Callable) -> Callable: | |
def wrapper(*args: Any, **kw: Any) -> Any: | |
return func(*args, **kw) | |
return wrapper | |
class deco: | |
def __new__(cls: Type[A], *args: Any, **kwargs: Any) -> A: | |
if (len(args) > 1 or len(kwargs)) or not args: | |
return A_with_args(*args, **kwargs) | |
return A_without_args(func=args[0]) | |
# creates an instance of A_with_args | |
@deco(foo='foo', bar=5) | |
def foo(a: int) -> str: | |
return 'foo' | |
# also creates an instance of A_with_args | |
@deco() | |
def bar(b: int) -> str: | |
return 'bar' | |
# creates an instance of A_without_args | |
@deco | |
def baz(c: bytes) -> str: | |
return 'baz' | |
foo(a=1) | |
bar(b=10) | |
baz(c=b'baz') |
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 dataclasses import dataclass | |
@dataclass | |
class parametrize_decorator: | |
a: str | |
b: int | |
def __call__(self, func): | |
def wrapper(*args, **kw): | |
return func(*args, **kw) | |
return wrapper | |
# this is a decorator that can only | |
# be used with parameters | |
# use default values for attributes | |
# to create keyword parameters | |
@parametrize_decorator('foo', 1) | |
def foo(a: str): | |
return a |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It's extendible in some way.
For instance, you can declare some method in
A class
and call it in both decorator classes before calling a function being wrapped. That allows you to encapsulate a core behavior inside the base class' method not paying much attention to implementation details.