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

document ternary/conditional type inference limitations #6649

Closed
wants to merge 2 commits into from
Closed

document ternary/conditional type inference limitations #6649

wants to merge 2 commits into from

Conversation

petergaultney
Copy link

As per the discussion in #4134 , it seems worth documenting that conditional expressions don't always work smoothly with type inference. This PR makes sure to include the word ternary and conditional so that page/doc searches will turn up an explanation for this behavior in case anyone is searching for it.

Copy link
Member

@ilevkivskyi ilevkivskyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I have few suggestions.

docs/source/common_issues.rst Outdated Show resolved Hide resolved
docs/source/common_issues.rst Outdated Show resolved Hide resolved
docs/source/common_issues.rst Outdated Show resolved Hide resolved

.. code-block:: python

def f(x: AnyStr, y: AnyStr) -> bytes:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example with AnyStr is not the best one, since it combines two tricky points:

  • the one you are explaining
  • the fact that functions generic in variables with restrictions are type checked multiple times.

I would rather use a single argument function with a Union[str, bytes] argument.

Copy link
Author

@petergaultney petergaultney Apr 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, if I try to simplify this down to

def f(x: Union[str, bytes]) -> bytes:
    r = x.encode('ascii') if isinstance(x, str) else x
    # results in 'error: "bytes" has no attribute "encode"; maybe "decode"?'

    if isinstance(x, str):
        r = x.encode('ascii')  # whereas Mypy can narrow within an if statement
    else:
        r = x
    return r

Mypy doesn't error at all, which is quite interesting. Whereas if I use AnyStr on that same argument, there is an error.

It may be that I have oversimplified the explanation for what is going on?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify, mypy can restrict types using isinstance() in ternary expressions, but it cannot consider sub-expressions of ternary expression unreachable. Here is even simpler example:

x: bytes

if isinstance(x, str):
    r = x.encode()  # OK, this is unreachable
else:
    r = x

r = x.encode() if isinstance(x, str) else x  # Error here

@JukkaL
Copy link
Collaborator

JukkaL commented Nov 25, 2021

Closing since there has been no activity in a long time. Feel free to repopen if you want to continue working on this.

@JukkaL JukkaL closed this Nov 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants