-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Document why having a union return type is often a problem #1693
Comments
The key reason is that every caller will have to use isinstance() to pick the union apart before its value can be used, right? And that's often unnecessary because there's some reason why the runtime value is always one or the other. Example, if pow() returned Union[int, float], then we couldn't use pow(2, 2) as a sequence index. |
I think it's an implementation detail of how the type checker works and what it considers a type error. I've worked with Python type hinting for quite a while (love it by the way), though using PyCharm rather than This is how PyCharm 2016.4 handles the following Python 3.5 code: from typing import Union
x = 1 # type: Union[int, float]
def f(y: int) -> None:
pass
f(x) # No type error, as 'Union[int, float]' is allowed to be input into 'int' parameter
# Test to show that bare 'float' will raise error.
f(0.5) # Warning raised: Expected type 'int', got 'float' instead PyCharm seems to prefer avoiding false positive type errors, which I suppose is more of a design choice. I bring this up because they recently fixed a type hinting issue by switching the inferred type hint to a I also heard PyCharm is planning to switch to using I don't know the internal plans for PyCharm, only a user, so I'll let @vlasovskikh speak to those details and correct me if needed. |
PEP 484 doesn't define the precise semantics of union types. Mypy does "strict" union checking which is similar to how union types behave in type theory: an operation is okay for a union type if it is valid for all items of the union. It seems that PyCharm uses "unsafe" (not established terminology) union type checking where an operation is okay if it is valid for some item of an union. @vlasovskikh please let me know if I understood this correctly. The main motivation for strict unions in mypy is finding For a checker that does strict unions Here are ideas for resolving this general issue:
|
@JukkaL Thanks for the detailed explanation. Just wanted to highlight, as you've said, the different interpretations being used so that the community as a whole can continue to work together on this.
While PyCharm's handing of
I think another reason I can imagine why PyCharm would favor |
If mypy deals better with (Btw. pytype does "unsafe" Unions as well, for most operations) |
@johnthagen Yes, using an @matthiaskramm I don't like the idea of ignoring some type annotations, as this could be very confusing for users. Also, often a union return type will be fine for mypy. For example, the types in the union may have some common functionality, and sometimes the caller is expected to do a check before using the value. We are planning to teach mypy to special case the signatures of some functions (#1240), and then there would be more flexibility. It would be less of a usability problem for mypy to infer a more precise type for a return type than the one declared. For example, if Also, PEP 484 suggests that |
@JukkaL @johnthagen In PyCharm we switched from "strict" to "weak" unions a few years ago after some experiments with |
Could mypy add a configuration flag to chose between strict and lenient union matching? A configuration flag seems like a better solution than to ask mypy users to reduce return type specificity by replacing |
Is this really because Union return types (other than possibly the degenerate case of By which I mean that the return type should usually be inferrrable from the types (or For example, a function that upcases either strings or the ascii-range letters of a bytes object could accept and return and Union: def upcase(s: Union[str, bytes]) -> Union[str, bytes]: ... ...but the better thing to do is use an overload... @overload
def upcase(s: str) -> str: ...
@overload
def upcase(s: bytes) -> bytes: ...
def upcase(s):
if isinstance(s, str):
return s.upper()
elif isinstance(s, bytes):
return bytes(x - 0x20 if 0x61 <= x <= 0x7A else x for x in s)
else:
raise TypeError("need str or bytes") If this is the kinda thing we're getting at, I'd be glad to document this. |
Hi jriddy. Apologies, but does python provide an
|
get_text() -> Union[str, array] depending on what was used when set_text() was used. Because of <python/mypy#1693> use Any.
What is the recommendation to handle cases like this? def my_sort(items: Sequence[int], also_return_indices: bool) -> Union[List[int], Tuple[List[int], List[int]]]
sorted_items, indices = ... # bunch of code
if also_return_indices:
return sorted_items, indices
return sorted_items i.e. I cannot use |
Use overload + Literal, should work for most cases. (Otherwise your fallback is the same as everyone else's, use Any) |
Do you have an example or link to docs? Are you saying I need to change |
It’s frustrating that annotating the return values of a function as I know this is because the Annotating the return type of my function as only Mishaps like this is what make me hate annotations still. |
get_text() -> Union[str, array] depends on what was used when set_text() was used. Because of <python/mypy#1693> use Any.
get_text() -> Union[str, array] depends on what was used when set_text() was used. Because of <python/mypy#1693> use Any.
get_text() -> Union[str, array] depends on what was used when set_text() was used. Because of <python/mypy#1693> use Any.
Union return types get suggested pretty often, but they usually are not the right thing for library stubs.
The text was updated successfully, but these errors were encountered: