Skip to content

Instantly share code, notes, and snippets.

@michaelwooley
Created April 13, 2022 02:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save michaelwooley/1a7a8e75f2bf70893c8fccfa3e45febd to your computer and use it in GitHub Desktop.
Save michaelwooley/1a7a8e75f2bf70893c8fccfa3e45febd to your computer and use it in GitHub Desktop.
Experiment w/ decorators in python 3.10
import functools
from typing import Any, Callable, ParamSpec, Concatenate, TypeVar
import typing
P = ParamSpec("P") # Parameters remaining after decorator autofill
R = TypeVar("R") # Return type
def get_authenticated_user():
return "John"
InpFn = Callable[Concatenate[int, str, P], R]
RetFn = Callable[Concatenate[int, P], R]
def inject_user() -> Callable[[InpFn[P, R]], RetFn[P, R]]:
def decorator(func: InpFn[P, R]) -> RetFn[P, R]:
def wrapper(arg0: int, *args: P.args, **kwargs: P.kwargs) -> R:
username = get_authenticated_user()
if username is None:
raise Exception("Don't!")
return func(arg0, username, *args, **kwargs)
return wrapper
return decorator
@inject_user()
def foo(a: int, username: str) -> bool:
"""A docstring"""
print(username)
return bool(a % 2)
print(foo(3))
###############################
# P = ParamSpec("P") # Parameters remaining after decorator autofill
# R = TypeVar("R") # Return type
# ####################################################
# VERBOSE VERSION
# ####################################################
def inject_a0(a: int) -> Callable[[Callable[Concatenate[int, P], R]], Callable[P, R]]:
def decorator(func: Callable[Concatenate[int, P], R]) -> Callable[P, R]:
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
return func(a, *args, **kwargs)
return wrapper
return decorator
@inject_a0(3)
def foo_a0(a: int, username: str, *args: Any) -> bool:
"""A docstring"""
print(username, args)
return bool(a % 2)
foo_a0("asf")
# ####################################################
# DRY(-ER) VERSION
# ####################################################
InpFnA = Callable[Concatenate[int, P], R]
RetFnA = Callable[P, R]
def inject_a(a: int) -> Callable[[InpFnA[P, R]], RetFnA[P, R]]:
def decorator(func: InpFnA[P, R]) -> RetFnA[P, R]:
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
return func(a, *args, **kwargs)
return wrapper
return decorator
@inject_a(3)
def foo_a(a: int, username: str, *args: Any) -> bool:
"""A docstring"""
print(username, args)
return bool(a % 2)
foo_a("asf")
# ####################################################
# DRY(-ER) VERSION
# ####################################################
InpFnA2: typing.Final = Callable[Concatenate[int, P], R] # Callable[[int, str], R]
RetFnA2: typing.Final = Callable[P, R] # Callable[[str], R]
# The
def inject_a2(a: int) -> Callable[[InpFnA2], RetFnA2]:
def decorator(func: InpFnA2) -> RetFnA2:
# @functools.wraps(func)
def wrapper(*args: Any, **kwargs: Any):
return func(a, *args, **kwargs)
return wrapper
return decorator
@inject_a2(3)
def foo_a2(a: int, username: str) -> bool:
"""A docstring"""
print(username)
return bool(a % 2)
foo_a2("asf")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment