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

isinstance inference not working in closures #4679

Closed
ThomasHickman opened this issue Mar 5, 2018 · 6 comments
Closed

isinstance inference not working in closures #4679

ThomasHickman opened this issue Mar 5, 2018 · 6 comments

Comments

@ThomasHickman
Copy link

In the code:

class SuperCls:
    pass

class Cls(SuperCls):
    prop = 9

def do_something(inp):
    # type: (SuperCls) -> None
    if isinstance(inp, Cls):
        def x():
            # type: () -> None
            print(inp.prop)
        return x()

inst = Cls()
do_something(inst)

this warning is wrongly emitted:

test.py:12: error: "SuperCls" has no attribute "prop"
@gvanrossum
Copy link
Member

This is a known issue; it's somewhat of a feature because sometimes the closure variable can change its value (and hence type) again before the function is called (e.g. consider if your code has inp = SuperCls() just before the return x()). Detecting the cases where this isn't a problem is somewhat complicated. You can work around it by passing inp as an argument to x().

@nilehmann
Copy link

nilehmann commented Mar 31, 2018

Related to this. I would like to write code similar to this one

def add(m: int, n: int) -> int:
    return m + n

one: Optional[int] = 1

if one:
    map(lambda n: add(one, n), [1, 2, 3])

Maybe the case for anonymous function is easier?

@gvanrossum
Copy link
Member

gvanrossum commented Mar 31, 2018 via email

@nilehmann
Copy link

nilehmann commented Mar 31, 2018

Giving it a second thought, I think is it equally easy to invalidates things for lambdas than for regular functions.

@jrideout
Copy link

jrideout commented Dec 7, 2018

I ran into this as well:

def test(a: Optional[str] = None) -> str:
    if a is None:
        a = 'abc'
    def inner() -> str:
        return a  #  <---  error: Incompatible return value type (got "Optional[str]", expected "str")
    return inner()

In this case the closure isn't going to change. I wonder if we can infer that.

@ilevkivskyi
Copy link
Member

This is actually a duplicate of #2608 (already high priority). Yes, one of proposed solutions was to use the binder, if e.g. the inner function appears at the end of the outer function, so the closure can't change.

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

No branches or pull requests

5 participants