I'm unsure of the Python convention for type hinting instance variables - I've been doing them within the __init__
constructor arguments like seen here:
class LoggedVar(Generic[T]):
def __init__(self, value: T, name: str, logger: Logger) -> None:
self.name = name
self.logger = logger
self.value = value`
But I also see the PEP conventions of annotating instance variables as such (snippet below) and then also doing type hinting within the __init__
arguments:
class BasicStarship:
captain: str = 'Picard' # instance variable with default
damage: int # instance variable without default
stats: ClassVar[Dict[str, int]] = {} # class variable`
def __init__(self, damage: int, captain: str = None):
self.damage = damage
if captain:
self.captain = captain # Else keep the default
Lastly, later on in the PEP 526 article they say one can do the following for convenience and convention:
class Box(Generic[T]):
def __init__(self, content):
self.content: T = content
(Both of the above code snippets are from here.)
So — is one of these conventions better/more widely accepted than the others that I should try to stick to (better readability etc..)?
I would recommend using the first version, where you assign types to your __init__
method's parameters, for most circumstances.
That particular method has the least amount of redundancy while still allowing type checkers to verify that you're calling that __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 grown complex enough to the point where one or more of the following apply:
However, it was unclear to me whether the second or third version was preferred -- I personally prefer the third version because it's more conceptually cleaner and doesn't seem to mix the notion of instance vs class attributes, but I can't deny the second version looks cleaner.
I asked about it on the 'typing' gitter channel, and got the following response from Guido (who, on the off-chance you didn't know, made Python and is currently working on mypy and typing related stuff):
There seem to be strong opinions either way. I do indeed prefer putting attribute annotations in the class body rather than sprinkling them throughout
__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).
So, it seems like the second version is recommended over the third, and that defining classes in that manner will become more deeply integrated into the Python language itself at some point in the future!
Edit: PEP 557, data classes was recently accepted and appears to be on-track (?) to be included with Python 3.7.