X Tutup
The Wayback Machine - https://web.archive.org/web/20201019100901/https://github.com/python/typing/issues/758
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Add a generic property class #758

Open
jp-larose opened this issue Sep 29, 2020 · 1 comment
Open

Feature Request: Add a generic property class #758

jp-larose opened this issue Sep 29, 2020 · 1 comment
Labels

Comments

@jp-larose
Copy link

@jp-larose jp-larose commented Sep 29, 2020

Can you add a generic counterpart to the property decorator class to allow for proper typing of object properties. This would align with many other new classes in the typing library to improve type hinting in our code.

Here's my stab at an implementation:

from __future__ import annotations
from typing import Generic, TypeVar, Callable, Any, cast, get_type_hints, Optional, Type

T = TypeVar('T')


class Property(property, Generic[T]):
    def __init__(self,
                 fget: Optional[Callable[[Any], T]] = None,
                 fset: Optional[Callable[[Any, T], None]] = None,
                 fdel: Optional[Callable[[Any], None]] = None,
                 doc: Optional[str] = None):
        super().__init__(fget=fget, fset=fset, fdel=fdel, doc=doc)

    def __get__(self, obj: Any, obj_type: type = None) -> T:
        return cast(T, super().__get__(obj, obj_type))

    def __set__(self, obj: Any, value: T) -> None:
        super().__set__(obj, value)

    def __delete__(self, obj: Any) -> None:
        super().__delete__(obj)

    def getter(self, fget: Callable[[Any], T]) -> Property[T]:
        return cast(Property[T], super().getter(fget))

    def setter(self, fset: Callable[[Any, T], None]) -> Property[T]:
        return cast(Property[T], super().setter(fset))

    def deleter(self, fdel: Callable[[Any], None]) -> Property[T]:
        return cast(Property[T], super().deleter(fdel))

This would allow us to do the following:

from typing import Property  
IntProperty = Property[int]

class C:
    def __init__(self, int_prop: int, str_prop: str):
        self._int_prop = int_prop
        self._str_prop = str_prop

    @IntProperty
    def int_prop(self) -> int:
        return self._int_prop

    @Property[str]  # Relaxed syntax brought to you by PEP 614
    def str_prop(self) -> str:
        return self._str_prop

    @str_prop.setter
    def str_prop(self, new_str_prop: str) -> None:
        self._str_prop = new_str_prop

I'm not sure if I have all the subtleties of the implementation correct, however my own cursory tests on python 3.9 work.

@gvanrossum
Copy link
Member

@gvanrossum gvanrossum commented Sep 30, 2020

I'm not sure what this give beyond the standard property. Is there anything in your example program whose type gets inferred incorrectly in your example if you just use @property? Or is there anything which mypy incorrectly disallows when using that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.
X Tutup