Reputation: 767
What would be the proper way to type the print_before
function decorator, so that the
wrapped function has the proper type but I can't use the decorator on a class that would not work?
thank you
def print_before(func):
def func_wrapper(self, *args):
self.print_hi()
return func(self, *args)
return func_wrapper
class PrintThings:
def print_hi(self):
print("hi")
@print_before
def add_nums(self, a: int, b: int) -> int:
return a + b
pt = PrintThings()
pt.add_nums(5, 4)
class ShouldNotWork:
@print_before
def add_nums(self, a: int, b: int) -> int:
return a + b
snw = ShouldNotWork()
snw.add_nums(4, 5)
Upvotes: 1
Views: 684
Reputation: 532418
The decorator has a very general type as written. The only thing you know about the wrapper is that it accepts at least one argument of some unknown type, and returns some unknown type. As for the decorator itself, you only know that it returns something with the same type as its argument.
Actually, there is one more thing we know. Whatever the type of self
is, it must have a print_hi
method. We can represent that using a Protocol
.
We also introduce a type variable T
, which represents the same class (or a subclass thereof) each time it is used in the signature of print_before
.
from typing import Any, Tuple, Protocol, TypeVar
class PrintsHi(Protocol):
def print_hi(self):
pass
T = TypeVar('T', bound=PrintsHi)
def print_before(func: Callable[[T, Tuple[Any,...]], Any]) -> Callable[[T, Tuple[Any,...]], Any]:
def func_wrapper(self: T, *args: Tuple[Any,...]):
self.print_hi()
return func(self, *args)
return func_wrapper
Upvotes: 1