Ian Pilcher <
arequipeno@gmail.com> wrote or quoted:
them is how to write type hints for a method decorator.
To get your type hints dialed in for a method decorator,
we're going to need to pull in "ParamSpec", "TypeVar", and
"Callable" from the typing module, plus "Concatenate" from
typing_extensions if you're rolling with Python older than
3.10. Check out how you can soup up your _check_eof method:
from typing import TypeVar, ParamSpec, Callable
from typing_extensions import Concatenate # Use this for Python < 3.10
T = TypeVar('T')
P = ParamSpec('P')
class BufferScanner:
# . . . other methods . . .
@staticmethod
def _check_eof(method: Callable[Concatenate['BufferScanner', P], T]) -> Callable[Concatenate['BufferScanner', P], bool]:
def wrapper(self: 'BufferScanner', *args: P.args, **kwargs: P.kwargs) -> bool:
if not self._eof:
method(self, *args, **kwargs)
if self._index >= len(self._buffer):
self._eof = True
return self._eof
return wrapper
# . . . other methods . . .
Let's break it down like we're dissecting a California roll:
1. "T = TypeVar('T')": This bad boy's a generic type
variable, standing in for whatever the original method
kicks out.
2. "P = ParamSpec('P')": This dude's capturing all the
parameters of the original method, minus the self part.
3. "Callable[Concatenate['BufferScanner', P], T]": This is
the type of the method getting decorated. It's like a
burrito bowl - BufferScanner instance as the base, other
ingredients (P) mixed in, and T as the guac on top.
4. "Callable[Concatenate['BufferScanner', P], bool]": This is
what the decorator's dishing out. It's taking the same
order as the original method (including self) and always
serves up a bool.
In the wrapper function, we're tagging self as "BufferScanner"
and using "P.args" and "P.kwargs" to scoop up the rest of
the arguments. A few more nuggets for you:
1. Stick to "typing" instead of "collections.abc" for the
freshest type hinting flavors.
2. In Python 3, your class can just chill as class
"BufferScanner": without the explicit object inheritance.
3. If you're cruising with Python 3.10 or newer, you can
import "Concatenate" straight from "typing". For the
classic versions, you'll need to grab it from
"typing_extensions".
This approach is like catching the perfect wave at Mavericks for
your method decorator type hinting. It captures the essence of
decorating a BufferScanner method and keeps all the juicy details
about parameters and return types, while making sure the self
parameter doesn't wipe out in the type annotations. Cowabunga!