Skip to content

Instantly share code, notes, and snippets.

@antibagr
Last active September 12, 2021 14:25
Show Gist options
  • Save antibagr/416623e6838c175ccf83f2b9a7d4dbce to your computer and use it in GitHub Desktop.
Save antibagr/416623e6838c175ccf83f2b9a7d4dbce to your computer and use it in GitHub Desktop.
Dynamic parameterised decorator
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')
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
@antibagr
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment