typing
typing copied to clipboard
Optional class and protocol fields and methods
Sometimes, implementations check for the existence of a method on an object before using it. Take this example from Python 2.7's urllib:
class addbase:
def __init__(self, fp):
self.fp = fp
self.read = self.fp.read
self.readline = self.fp.readline
if hasattr(self.fp, "readlines"): self.readlines = self.fp.readlines
if hasattr(self.fp, "fileno"):
self.fileno = self.fp.fileno
else:
self.fileno = lambda: None
if hasattr(self.fp, "__iter__"):
self.__iter__ = self.fp.__iter__
if hasattr(self.fp, "next"):
self.next = self.fp.next
Currently this is best modeled by leaving these methods out from a protocol. But this means that their signature is unknown, and mypy will complain about the non-existing attribute. It would be useful to be able to model this somehow, for example by using a decorator for such methods.
This was explicitly deferred in PEP 544. On the other hand this would be not hard to implement now. Also another structural type in mypy -- TypedDict
-- supports this. So maybe we should also support total=False
for protocols?
@JukkaL what do you think?
I don't think a total=False
attribute would be sufficient. In the example above - in fact in all cases where I have encountered this so far - there are required members as well as optional ones. A per-attribute flag (a decorator?) would serve these cases much better.
I don't think a
total=False
attribute would be sufficient
It is always sufficient. Whether it is convenient is a different question.
I mentioned this again on typing-sig. It could reuse PEP 655's NotRequired
class:
class MyProto:
x: NotRequired[int]
@not_required
def foo(self) -> None: ...
It would also make sense for non-protocols:
class Foo:
x: NotRequired[int]
def setup(self) -> None:
self.x = some_calc()
(Not a design I would recommend, but I have seen this from time to time in the wild.)
I think this could be helpful for solving https://github.com/python/typing/discussions/1498 by marking _my_property
as a non-required attribute. What do you think?
See also:
- https://github.com/falconry/falcon/issues/1820#issuecomment-1912779512