How to define a property as part of a Protocol
Asked Answered
M

2

11

Could somebody please clarify the generally accepted way of defining a property as part of a Protocol?

I've been doing it like so:

from typing import Protocol

class MyProtocol(Protocol):
    @property
    def my_property(self):
        """ Classes should have a my_property to conform to MyProtocol """

But Pycharm's built-in linter keeps complaining that a "Getter should return or yield something", hence my confusion. Raising a NotImplementedError makes the linter message go away, but doing that seems to fit more with an abstract class than with a Protocol.

Monroe answered 2/10, 2021 at 13:58 Comment(8)
why would you want to use @property in a protocol? I mean, it's a protocol, not a base classSydelle
@Marat, to me it seems useful to be specific about the intent of my protocol, i.e. I would want to signal to any interface that depends on this protocol that they should access a property instead of a method.Monroe
From the outsider's perspective, it is just a property, and from the standpoint of protocol definition it should remain as such. Implementation details should be left to implementation or inherited classes.Sydelle
If you could post the information above as an answer I will make sure to accept and upvote :)Monroe
@Sydelle its not just a property, its a read only property. It makes a difference if the implementation allows a public facing property to be set.Bluegreen
@Bluegreen it is a Protocol, a thing used for structural subtyping. Introducing implementation details into this abstraction kind of ruins its purpose. UPD: we had this exact discussion in the comments above - please readSydelle
In the abstract, properties can absolutely make sense in a protocol, without being some leak of implementation detail. For example, it’d be perfectly valid for a “WheeledVehicle” protocol to require conforming types to have a getter for a numberOfWheels. If that weren’t allowed, you’d have to use a function like getNumberOfWheels(), which you wouldn’t otherwise do. Though if the language’s definition of properties is only stored properties (and doesn’t support computed properties), then the function is a more flexible bet.Paleface
Even the protocols PEP itself speaks of properties. On the other hand, this is at the time of writing still an open issue in PyCharm.Nichol
C
2

Defining a property in a protocol is supported in the latest mypy: https://mypy.readthedocs.io/en/stable/common_issues.html?highlight=%40property#covariant-subtyping-of-mutable-protocol-members-is-rejected

In this case, you can simply define the property in the protocol and in the classes that conform to that protocol:

from typing import Protocol

class MyProtocol(Protocol):
    @property
    def my_property(self) -> str:
        ...

class MyClass(MyProtocol):
    @property
    def my_property(self) -> str:
        # the actual implementation is here
Cosmology answered 17/7, 2023 at 14:32 Comment(3)
pycharm says "Getter should return or yield something"Thistledown
@Thistledown I just tested this snippet in the latest pyright and the latest mypy, and I didn't get any errors or warnings. It looks like PyCharms implementation of the spec raises this false positive: youtrack.jetbrains.com/issue/PY-40180/…Cosmology
yeah copy that. finding a lot of these inspection bugs recentlyThistledown
H
-2

They are separate. Property is to allow a function to be called like an attribute. for example

class MyClassProtocol(Protocol):
    def example() -> int: ...

class MyClass(MyClassProtocol):
    @property
    def example() -> int:
        return 5

tmp = MyClass()
tmp.example

5

That is why your IDE is picking up the must return or yield something because a property is expecting a return value.

Hanaper answered 20/12, 2022 at 10:23 Comment(1)
I downvote, because your sample won't pass type checking with any conformant checker.Codfish

© 2022 - 2024 — McMap. All rights reserved.