Skip to content

Feature Request: Add a generic property class #758

Closed

Description

@jp-larose

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.

Activity

  1. gvanrossum commented on Sep 30, 2020

    @gvanrossum
    Member

    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?

  2. bubblefoil commented on May 5, 2021

    @bubblefoil

    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?

    In my case, I have a generic class with a property of that generic type. I can type-hint the @property annotated function and PyCharm would understand it. However, if I type-hint @foo.setter function, PyCharm has no idea what type the setter expects.

    from typing import TypeVar, Generic
    
    T = TypeVar('T')
    
    
    class C(Generic[T]):
    
        def __init__(self, val: T):
            self._val = val
    
        @property
        def val(self) -> T:
            return self._val
    
        @val.setter
        def val(self, val: T):
            self._val = val
    
    
    c = C('abc')
    x: float = c.val  # Warning
    c.val = 5  # No problem
  3. jp-larose commented on May 5, 2021

    @jp-larose
    Author

    Sorry, I never came back to this until now...

    The point for me was to ensure/validate that the getter and setter for a given property had a matching type.

  4. srittau commented on May 13, 2021

    @srittau
    Collaborator

    This honestly sounds like a bug/missing feature in PyCharm, although I think mypy has similar issues. The type of a property is the same as the return type of the getter function. (It's a bit more complicated if it has getter and setter methods accepting different types, but the principle is the same.) I don't think a generic would make any difference in the provided code samples.

  5. srittau commented on May 13, 2021

    @srittau
    Collaborator

    One thing we could improve is the types of property in typeshed, though. Making it generic there sounds like a good idea to me.

  6. jp-larose commented on May 18, 2021

    @jp-larose
    Author

    One thing we could improve is the types of property in typeshed, though. Making it generic there sounds like a good idea to me.

    I think this might be more appropriate than my initial suggestion.

  7. added
    topic: featureDiscussions about new features for Python's type annotations
    and removed on Nov 4, 2021
  8. srittau commented on Nov 4, 2021

    @srittau
    Collaborator

    Closing this as a duplicate of #594 and python/typeshed#4731.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    resolution: duplicateThe idea/problem was already reportedtopic: featureDiscussions about new features for Python's type annotations

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions