Skip to content

Inferring a more precise type on assignment to a variable with Any type #2928

Description

@JukkaL

Mypy infers the type Any for y after the second assignment:

from typing import Any

def f(x: Any) -> None:
    y = x
    y = 1
    reveal_type(y)  # Any

Inferring int as the type might be less surprising. However, if a variable is explicitly declared with an Any type, such as x in the above example, it's less clear what would be the right thing to do.

A more general solution would allow redefining variables with arbitrary new types (#1174).

Activity

  1. gvanrossum commented on Mar 1, 2017

    @gvanrossum
    Member

    It seems that in general variables whose initial type is Any are untouched by the binder and always remain typed as Any? That doesn't feel right or consistent. IMO it should mean that anything can be assigned to such a variable, not that we should ignore tracking assignments.

    As a work-around, if the initial type is object you can also assign anything to a variable, and it does get tracked by the binder. But I don't like the long-lasting effect of Any here.

  2. JukkaL commented on Mar 1, 2017

    @JukkaL
    CollaboratorAuthor

    The Any type can come from a skipped module, so using object is not a good workaround in general.

  3. ddfisher commented on Mar 2, 2017

    @ddfisher
    Collaborator

    One thing to note is that we don't distinguish between variables that have type annotations and variables that set their type from the first assignment. The example would look a lot more reasonable if it was:

    from typing import Any
    
    def f(x: Any) -> None:
        y = x  # type: Any
        y = 1
        reveal_type(y)  # Any

    In this case example (where the type is explicit), I don't think it makes sense to reduce Any's use as an escape hatch. There's an argument to be made for behaving differently with and without an explicit type annotation, but that comes with a cost in complexity and user education. My initial inclination is it's not worthwhile here.

  4. gvanrossum commented on Mar 2, 2017

    @gvanrossum
    Member

    This is an old argument (so far carried out in private I think) but I don't think the explicit # type: Any should override the subsequent assignment of a value of a given type either. I like to see the analogy between

    y = x # (inferred or declared Any)
    y = 1
    reveal_type(y)
    

    and

    y = x # (inferred or declared Any)
    assert isinstance(y, int)
    reveal_type(y)
    

    I think both of these should reveal the same type (int).

    (In fact, if anything, the assert has less of a runtime guarantee about y's "int-less" than the straight assignment, since python -O doesn't compile code for assert.)

  5. JukkaL commented on Jan 28, 2020

    @JukkaL
    CollaboratorAuthor

    This would be nice to fix, on one hand. On the other hand, this could generate a lot of false positives in existing code that type checks cleanly, so I'm not sure if fixing this is actually worth it.

  6. hauntsaninja commented on Dec 30, 2025

    @hauntsaninja
    Collaborator

    Fixed by #18538

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions