You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We had a discussion with @HGSilveri about where instance attributes should be type annotated. I dug a bit more on the subject, and here is what I can come with:
declare attributes at class scope:
classA:
x: int# pro: all instance attributes grouped here,# making it easy to see them all at a glancedef__init__(self): self.x=0# cons: self.x = 0 could be absent and mypy wouldn't complain
declare attributes at the top of __init__ (what is done here): same pro in a weaker form, and identical cons
keep attributes sparsed inside __init__:
classA:
# cons: need to read the whole class to find all instance attributesdef__init__(self): self.x: int=0# pro: x declared and defined at once, helping not to forget to define it
attributes could be both declared and defined at the class scope, which would be correct for static type checking, but would also create class attributes:
classA:
x: int=0# pros: all instance attributes grouped here, and it's clear that x is defined (only works for defaults)A.x# cons: this worksvars(A()) # cons: this is empty# big cons: default value is a class attribute, until a new value is provided,# so all instances share it by default until they are given their ownclassB:
x: list= []
b1=B()
b2=B()
b1.x.append(1)
b2.x# also contains 1b2.x= [] # b2 has finally its own instance attribute
The options 1 and 3 are probably the best ones between which we should choose (I would personnally go for the 1).
In all cases, I think we should avoid instance attribute declarations that are neither at the classe scope, neither inside __init__, but inside another method, because this basically cumulates cons of 1 and 3, and doesn't have any of the mentioned pros.
The text was updated successfully, but these errors were encountered:
It’s easy to prevent 4.: just never ever use a mutable default value
classC:
x: list=None# doy: list= [] # don'ta, b=C(), C()
a.x.append(1) # fails, since it is type Nonea.x= [1]
print(a.x, "and", b.x)
## [1] and None# otherwise same problem for a.y, b.y
While 1. Is the most readable and pleasing to me—and I would really like to be able to do so blindly—I think 3. is the safest and simplest choice.
Otherwise there is a great confusion between the instances and class attributes, and we are dangerously close to case 4 with bad bugs.
Moreover if you have many properties defined on your class, the whole point of grouping attributes makes little sense.
The (public) instance attributes should be listed in the class docstring with their types, à la Google.
I think most IDEs do a good job at discovering objects attributes. Together with the class docstring this should be enough.
I'm with @lvignoli - I like the cleanliness of option 1., but I don't think it's worth the potential for confusion. I would go with 3. too.
My only qualm with making a style decision of this type is enforcing it. Would this come with a checker for CI? If not, I find it very hard as a reviewer to remember to check for this.
We had a discussion with @HGSilveri about where instance attributes should be type annotated. I dug a bit more on the subject, and here is what I can come with:
__init__
(what is done here): same pro in a weaker form, and identical cons__init__
:The options 1 and 3 are probably the best ones between which we should choose (I would personnally go for the 1).
In all cases, I think we should avoid instance attribute declarations that are neither at the classe scope, neither inside
__init__
, but inside another method, because this basically cumulates cons of 1 and 3, and doesn't have any of the mentioned pros.The text was updated successfully, but these errors were encountered: