A class is a callable object that produces instances; each instance has its own dict and shares the class's attributes
A class is itself an object: it is created by the class statement (or by calling type()) and is an instance of a metaclass. It defines shared attributes and behavior in its own dict. An instance is a separate object produced by calling the class. Attribute lookup on an instance first checks the instance dict, then the class and its MRO. That is why class attributes are shared by default and assigning to self.attr creates a per-instance attribute that shadows the class one, whereas assigning to ClassName.attr changes it for everyone that has not shadowed it.
Class: blueprint plus runtime object; stores methods, class variables, and annotations.
Instance: independent namespace; stores per-object state in obj.dict.
Mutable class attributes are the classic trap: a list defined on the class is shared by every instance unless each instance assigns its own.
Trade-off: shared class state saves memory and enables registry patterns; per-instance state is safer for anything mutable.
Common mistake: assuming methods are copied into each instance. They live on the class and are bound on access through the descriptor protocol.
Version note: since Python 3, all classes are new-style; the old-style class distinction from Python 2 is gone.
0-2 years experience
2-5 years experience
5-8 years experience
8+ years experience