zyxue
zyxue

Reputation: 8888

Does mypy require __init__ to have -> None annotation

Seeing kind of contradictory results:

class A:
    def __init__(self, a: int):
        pass

The snippet above passes a mypy test, but the one below doesn't.

class A:
    def __init__(self):
        pass

Any idea why?

Upvotes: 7

Views: 3009

Answers (1)

Daniil Fajnberg
Daniil Fajnberg

Reputation: 18598

This is documented here.

When you have at least one (annotated) argument for a function, it is considered (at least partially) typed. When neither arguments nor return values are annotated, the function is considered untyped.

This distinction is important because by default, mypy does not check the bodies of untyped functions at all. This behavior is configurable via check_untyped_defs.

Note that the complaint about the missing return type only arises, if you set disallow_untyped_defs (or strict). Otherwise neither of your examples will trigger an error.

The __init__ method receives special treatment because people complained that always returns None and they did not want to explicitly write out the return type accordingly. This is why that behavior is so inconsistent.

class A:
    def __init__(self, x: int):  # this is fine with `mypy`
        pass

    def foo(self, x: int):
        print("hi")


class B:
    def __init__(self):
        pass

    def foo(self):
        print("hi")

Out of all these methods, only A.__init__ is considered fully typed (because of the implicit None return by __init__). All the other methods will trigger errors with disallow_untyped_defs set:

error: Function is missing a return type annotation  [no-untyped-def]

I don't particularly like this approach, but that is the way they decided to handle it.

Upvotes: 9

Related Questions