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

Possible to define a generic property? #8440

Closed
martsa1 opened this issue Feb 25, 2020 · 2 comments
Closed

Possible to define a generic property? #8440

martsa1 opened this issue Feb 25, 2020 · 2 comments

Comments

@martsa1
Copy link

martsa1 commented Feb 25, 2020

Feature Request, or just a clarification of whats possible, using python 3.6.10, Mypy 0.761

Hi folks,

I have some code which uses a class decorator to mutate a collection of callables, into a collection of properties, which has recently lead me down a bit of a garden path with mypy.

I believe that I can refactor my work to make use of a generic property, and achieve a similar net goal. What I would quite like to create, would be something loosely like a Generic Protocol that describes a property. With that I'd be able to define something approximately like this (I may need to clarify a bit further):

class Foo:
    foo: Property[str] = property(lambda _: "Foo")
    foobar: Property[str] = property(lambda self: self.foo + "bar")

f = Foo()

def test(thing: str):
    print(thing)

test(f.foo)  # Mypy would be able to verify that Foo.foo returns a string

Whilst I believe that simple properties are now supported by mypy, I've been having a collection of issues with dynamically using the property() builtin.

I wonder whether I would be able to create a property Protocol that supports generics, to achieve something like the above?

Any advice much appreciated, and thanks for your time in advance!

Possibly related: #8083

@JukkaL
Copy link
Collaborator

JukkaL commented Feb 28, 2020

Maybe you can get something like this to work by using a protocol with __get__ and __set__ (the stub for property would also need to modified, I believe)? I haven't thought about this carefully though.

@martsa1
Copy link
Author

martsa1 commented Feb 28, 2020

Hi JukkaL, thanks for coming back to me,

I managed to create a Prototype Generic subclass of the builtin property, which appears to work nicely, though it is slightly slower than the builtin property, so wouldn't be useful in some areas. For the area of my project where I'm using it that isn't an issue though:

from typing import Generic, TypeVar, Optional, Callable, Any

T = TypeVar("T")

class Property(property, Generic[T]):
    """Generic implementation of a property.

    Allows us to provide type annotations on top of builtin properties.
    """

    def __init__(
            self,
            fget: Optional[Callable[[Any], Any]] = None,
            fset: Optional[Callable[[Any, Any], None]] = None,
            fdel: Optional[Callable[[Any], None]] = None,
            doc: Optional[str] = None,
    ) -> None:
        super().__init__(fget, fset, fdel, doc)

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

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

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

Are there any improvements you might suggest to the above? Otherwise I think I'm quite happy with this approach for now, so can close this. :)

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

No branches or pull requests

2 participants