Reputation:
Why should we use ->
in def __init__(self, n) -> None:
? I read the following excerpt from PEP 484, but I am unable to understand what it means.
(Note that the return type of
__init__
ought to be annotated with-> None
. The reason for this is subtle. If__init__
assumed a return annotation of-> None
, would that mean that an argument-less, un-annotated__init__
method should still be type-checked? Rather than leaving this ambiguous or introducing an exception to the exception, we simply say that__init__
ought to have a return annotation; the default behavior is thus the same as for other methods.)
What's the subtle difference between using def __init__(self, n) -> None:
and def __init__(self, n):
? Can someone explain the quoted excerpt in simple words?
Upvotes: 27
Views: 62119
Reputation: 15273
The critical reading on this matter is the thread including Guido in MyPy issue 604, where he opines
I still think
__init__
is a special case -- its return value is determined by how Python uses it, not by what the user might want it to return. I think the absence of-> None
should never result in an error message here
concluding in
gvanrossum added a commit that referenced this issue on Oct 1, 2018 [...] Make return type implicitly
None
for type checked__init__
Long story short, if a linter determines that static type checking is possible for a given __init__
(in your case by adding an n: int
), it will not - and should not - complain on the absence of a -> None
and will infer that.
Upvotes: 3
Reputation: 532003
The main reason is to allow static type checking. By default, mypy
will ignore unannotated functions and methods.
Consider the following definition:
class Foo:
def __init__(self):
return 3
f = Foo()
mypy
, a static type analysis tool, sees nothing wrong with this by default:
$ mypy tmp.py
Success: no issues found in 1 source file
but it produces a runtime TypeError
(note that python
here is Python 3.8.6):
$ python tmp.py
Traceback (most recent call last):
File "tmp.py", line 5, in <module>
f = Foo()
TypeError: __init__() should return None, not 'int'
If you add the annotation -> None
, then mypy
will type-check the method and raise an error:
$ mypy tmp.py
tmp.py:3: error: No return value expected
Found 1 error in 1 file (checked 1 source file)
mypy
will even complain if you try to circumvent the the check by declaring def __init__(self) -> int:
instead:
$ mypy tmp.py
tmp.py:2: error: The return type of "__init__" must be None
Found 1 error in 1 file (checked 1 source file)
It's also worth noting that any annotation will make mypy
pay attention; the lack of a return type is the same as -> None
if you have at least one annotated argument:
def __init__(self, x: int):
return x
will produce the same "No return value expected" error as an explicit -> None
. The explicit return type, though, is often easier to provide than any artificial argument type hints, and is arguably clearer than trying to type self
.
Upvotes: 29
Reputation: 77387
It comes down to the fist sentence in PEP 484 - The meaning of annotations Any function without annotations should be treated as having the most general type possible, or ignored, by any type checker. def __init__(self, n):
won't be checked but def __init__(self, n) -> None:
will. Even though we know that __init__
should only return None
, a checker is not supposed to special-case it. The reason is that you don't know if the author intended to have def __init__(self):
checked or not.
Upvotes: 1
Reputation: 54
In python 3.5 appeared type annotation option. def __init__(self, n) -> None:
means that __init__
should always return NoneType and it can be quite helpful if you accidentally return something different from None especially if you use mypy or other similar things. But you can ignore it if you prefer the old way to do it.
Upvotes: 2
Reputation: 3780
This only matters if you care about type-annotations and can be skipped if you don't. It doesn't change functionality in runtime (other than adding information in the private __annotations__
property).
What does it do then?
->
Is used to document the type of the data that a function returns.
The type then follows after, in your case the type is None
.
So it says that the method doesn't return anything, or if it does return something it's always None
.
If you would return something you'd change it to the type of the return set.
Upvotes: 0