I would recommend using the first version, where you assign types to your __init__ method parameters for most cases.
This particular method has the least amount of redundancy, while still allowing type inspectors to verify that you are calling this __init__ method correctly elsewhere in your code.
I would recommend using either the second or third version, where you explicitly annotate your fields (inside or outside __init__ ), when your __init__ method has become quite complicated to the point where one or more of the following statements apply:
- Itβs not so clear what exactly your fields should begin with
- There is no longer a mapping between your parameters and your fields
- You have complex initialization logic that hides how your fields are assigned.
However, it was not clear to me whether the second or third version is preferable - I personally prefer the third version because it is more conceptually clean and does not seem to confuse the concept of instance attributes with a class, but I canβt deny that the second version looks cleaner.
I asked about this on the gitter βinputβ channel and received the following response from Guido (which, regardless of what you did not know, made Python and is currently working on mypy and is compiling similar materials):
It seems that in any case there are strong opinions. I really prefer to add attribute annotations to the body of the class, rather than spatter them across all __init__ and other methods. I also think that with PEP 526 this will be the future (also with things like class-based NamedTuple declarations and possibly https://github.com/ericvsmith/dataclasses ).
( link to quote )
So, it seems that the second version is recommended compared to the third, and that the definition of classes in this way will become more deeply integrated into the Python language itself at some point in the future!
Edit: PEP 557, data classes was recently adopted and appears to be included for inclusion in Python 3.7.
source share