In this pull request it looks like type hinting support for descriptors was added.
However it looks like no finalized "correct" usage example was ever posted, nor does it looks like any documentation was ever added to the typing
module or to Mypy.
It looks like the correct usage is something like this:
from typing import TypeVar
T = TypeVar('T')
V = TypeVar('V')
class classproperty():
def __init__(self, getter: Callable[[Type[T]], V]) -> None:
self.getter = getter
def __get__(self, instance: Optional[T], owner: Type[T]) -> V:
return self.getter(owner)
def forty_two(cls: Type) -> int:
return 42
class C:
forty_two: int = classproperty(forty_two)
This seems logical, but I have no idea if that's actually the right way to do things.
Is there any documentation on this? Or complete examples that actually works on the version that was merged?
The method described in the question seems to work for both Mypy and the PyCharm type checker.
Edit: Apparently my example code type checks, but MyPy cannot actually infer the type as of version 0.800.
"""Defines the `classproperty` decorator."""
from typing import Any, Callable, Optional, Type, TypeVar
T = TypeVar("T")
V = TypeVar("V")
class classproperty(property):
"""Class property decorator."""
def __init__(self, getter: Callable[[Any], V]) -> None:
"""Override getter."""
self.getter = getter # type: ignore
def __get__(self, instance: Optional[T], owner: Type[T]) -> V: # type: ignore
return self.getter(owner) # type: ignore
def __set__(self, obj, value):
super(classproperty, self).__set__(type(obj), value)
def __delete__(self, obj):
super(classproperty, self).__delete__(type(obj))
class Thing:
@classproperty
def value1(cls) -> int:
return 44
value2 = classproperty(lambda cls: 55)
@property
def value3(self) -> int:
return 66
thing = Thing()
reveal_type(thing.value1)
reveal_type(thing.value2)
reveal_type(thing.value3)
main.py:40: note: Revealed type is '<nothing>'
main.py:41: note: Revealed type is '<nothing>'
main.py:42: note: Revealed type is 'builtins.int'
https://mypy-play.net/?mypy=0.800&python=3.9&gist=79f6fab466ecc4c4b45b75f1c7b6a6a8.
I could not get the example to work with MyPy. However, the derived definition below worked for me:
"""Defines the `classproperty` decorator."""
from typing import Any, Callable, Optional, Type, TypeVar
T = TypeVar("T")
V = TypeVar("V")
class classproperty(property):
"""Class property decorator."""
def __init__(self, getter: Callable[[Any], V]) -> None:
"""Override getter."""
self.getter = getter # type: ignore
def __get__(self, instance: Optional[T], owner: Type[T]) -> V: # type: ignore
return self.getter(owner) # type: ignore
def __set__(self, obj, value):
super(classproperty, self).__set__(type(obj), value)
def __delete__(self, obj):
super(classproperty, self).__delete__(type(obj))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With