Skip to content

Instantly share code, notes, and snippets.

@clintval
Created July 23, 2024 01:55
Show Gist options
  • Save clintval/737d51492d5a3803b1dd6765ec51db8d to your computer and use it in GitHub Desktop.
Save clintval/737d51492d5a3803b1dd6765ec51db8d to your computer and use it in GitHub Desktop.
class MethodType:
"""A Python-equivalent method type that binds type arguments to the calling class."""
def __init__(self, func: Callable, obj: object) -> None:
"""Initialize this method with the calling class and function."""
self.__func__ = func
self.__self__ = obj
self._generic_classmethod = False
def __call__(self, *args: object, **kwargs: object) -> object:
"""Call this method with the given arguments and keyword arguments."""
return self.__func__(self.__self__, *args, **kwargs)
def __getitem__(self, *values: type) -> None:
"""Bind the type arguments this method was given to the calling class."""
print(self.__self__)
if hasattr(self.__self__, "__args__"):
print(self.__self__.__args__)
assert all(isinstance(value, type) for value in values), "Type arguments must be types!"
# https://github.com/python/cpython/blob/0aa0fc3d3ca144f979c684552a56a18ed8f558e4/Lib/typing.py#L1346
self.__self__.__args__ = values
return self
class classmethod_generic:
"""A generic classmethod decorator that will allow the method to know its type parameters."""
def __init__(self, func: Callable) -> None:
"""Initialize the decorator with the supplied classmethod."""
self.func = func
def __get__(self, obj: object, cls: object | None = None) -> Callable:
"""Wrap the generic classmethod with a custom method type that knows its type parameters."""
if cls is None:
cls = type(obj)
method = MethodType(self.func, cls)
method._generic_classmethod = True
return method
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment