python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.26k stars 2.79k forks source link

defining self.__call__ makes the class callable when it isn't #2113

Open euresti opened 8 years ago

euresti commented 8 years ago

I thought I had a found a great workaround for a problem I'm having. I'll define __call__ in the __init__

class A(object):

    def __init__(self):
        # type: () -> None
        self.__call__ = self.stuff

    def stuff(self, a):
        # type: (int) -> int
        return a + 2

a = A()
print a(7)

Mypy has no issues with this code at all. However python2 disagrees:

Traceback (most recent call last):
  File "example.py", line 12, in <module>
    print a(7)
TypeError: 'A' object is not callable

Looks like __call__ has to be defined on the class not the instance.

gvanrossum commented 8 years ago

Right, __call__ (and any other dunder methods) must be defined on the class. This is tricky to fix until we refactor some things in mypy to teach it about the relationship between class and instance variables and how they differ.

gvanrossum commented 7 years ago

Can we close this or is there an action item for mypy?

euresti commented 7 years ago

Well how do we feel about code that typechecks but fails when used as expected? It's basically a false positive.

gvanrossum commented 7 years ago

I think that's called a false negative :-) but you're right that that's an issue. It's more general though -- mypy just doesn't distinguish between class and instance attributes very well. (The rules for dunder methods are also super special, it's not just __call__.) I'll go look for an existing issue about that; if I can't find one I'll rename this one.

gvanrossum commented 7 years ago

The bug is really that mypy doesn't understand the difference between classes and instances enough, and that dunder methods must be defined on the class in order to apply to the instance.