On Mon, 12 Dec 2016 07:10 am, Juan C. wrote: > I'm watching a Python course and was presented a topic regarding classes. > One of the examples were: > > box.py > > class Box: > serial = 100 > > def __init__(self, from_addr, to_addr): > self.from_addr = from_addr > self.to_addr = to_addr > self.serial = Box.serial > Box.serial += 1
If you want to distinguish between an instance attribute and a class attribute, you must specify the instance or the class: self.serial # may be the instance attribute, or the class attribute Box.serial # always the class attribute But what happens inside a subclass? class BoxWithLid(Box): pass Generally we expect methods called from the subclass BoxWithLid to refer to the BoxWithLid attribute, not the Box attribute. So Box.serial will be wrong when the method is called from a subclass. type(self).serial # still correct when called from a subclass > The instructor said that the right way to call a class attribute is to use > 'Class.class_attr' notation, That is nearly always wrong, since it will break when you subclass. If you do that, you should document that the class is not expected to be subclasses, and may not work correctly if you do. > but on the web I found examples where people > used 'self.class_attr' to call class attributes. I believe that using the > first notation is better ('Class.class_attr'), this way the code is more > explicit, but is there any rules regarding it? Assignment to self.serial will always create or affect an instance attribute. But merely retrieving self.serial will use inheritance to try returning the instance attribute *if it exists*, and if not, fall back on the class attribute (or a superclass). This is especially useful for read-only defaults, constants or configuration settings. class Document: page_size = A4 def page_area(self): dimensions = list(self.page_size) dimensions[0] -= self.left_margin dimensions[1] -= self.right_margin dimensions[2] -= self.top_margin dimensions[3] -= self.bottom_margin return dimensions doc = Document() # uses the default page size of A4 doc.page_size = Foolscape # override the default It is a matter of taste and context whether you do this, or the more conventional way: class Document: def __init__(self): self.page_size = A4 Use whichever is better for your specific class. So... in summary: When *assigning* to an attribute: - use `self.attribute = ...` when you want an instance attribute; - use `Class.attribute = ...` when you want a class attribute in the same class regardless of which subclass is being used; - use `type(self).attribute = ...` when you want a class attribute in a subclass-friendly way. When *retrieving* an attribute: - use `self.attribute` when you want to use the normal inheritance rules are get the instance attribute if it exists, otherwise a class or superclass attribute; - use `type(self).attribute` when you want to skip the instance and always return the class or superclass attribute. -- Steve “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list