问题
So I am aware of pythons typing.Optional. But I wrote my own crude PyOptional (https://github.com/felixhertrampf/PyOptional/blob/master/PyOptional.py) and would like to combine Optional[T] with my PyOptional to PyOptional[T].
I am currently using Python 3.7 and tried extending typing.Optional.
Some of my PyOptional
class PyOptional:
T: TypeVar = TypeVar("T")
def __init__(self, obj: T):
self.value: Any = obj
def get(self) -> Optional[T]:
return self.value
def or_else(self, default) -> T:
return self.value or default
Pseudo code of what I want:
def find_user_by_id(id: int) -> PyOptional[User]:
return PyOptional(db.find_user_by_id(id))
The goal is for my IDE to be able to check what return type to expect and still be able to invoke my methods on the returned object. So it would have to be PEP compliant.
回答1:
You should review the documentation on generics -- specifically, user-defined generics. The mypy docs also have a thorough overview of generics that can be useful to reference.
In this particular case, you want to make the entire class generic by adding in a Generic[T]
as a class base. Just using T
in the individual function signatures will make each individual function generic, but not the class as a whole:
from typing import TypeVar, Generic, Optional
T = TypeVar("T")
class PyOptional(Generic[T]):
def __init__(self, obj: Optional[T]) -> None:
self.value = obj
def get(self) -> Optional[T]:
return self.value
def or_else(self, default: T) -> T:
return self.value or default
Some additional notes:
Don't add an annotation for any TypeVar variable. Here,
T
is a sort of meta-type construct that serves as "hole"/can represent any number of types. So, assigning it a fixed type doesn't really make sense, and will confuse type checkers.Never use a TypeVar only once in any given signature -- the whole point of using TypeVars is so that you can declare two or more types are always going to be the same.
Note that the fixed PyOptional class above also obeys this rule. For example, take
get
. Now that we made the whole class generic, the type signature for this function is now basically something likedef get(self: PyOptional[T]) -> Optional[T]
. Before, it was more likedef get(self: PyOptional) -> Optional[T]
.For your class to make sense, you probably want your constructor to accept an
Optional[T]
instead of justT
.Making
self.value
Any is probably unnecessary/is unnecessarily too vague. We can leave off the type hint, and now it'll have an inferred type ofOptional[T]
.If you want to more thoroughly check whether or not your class is PEP 484 compliant and will likely be understood by IDEs such as PyCharm, consider type-checking your class + some code using your class via mypy, a PEP 484 type checker.
This won't guarantee that your IDE will fully understand your class (since it might not fully implement everything about PEP 484/you might run into a bug in either mypy or your IDE), but it should help you get pretty close.
来源:https://stackoverflow.com/questions/57867124/python-typing-return-type-with-generics-like-clazzt-as-in-java-clazzt