Differences between revisions 8 and 20 (spanning 12 versions)
Revision 8 as of 2006-01-11 02:12:57
Size: 5274
Editor: bluepill
Comment: removed wikispam
Revision 20 as of 2014-05-07 22:26:07
Size: 5528
Comment: spam
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
WARNING: First draft, not all yet verified.

Line 32: Line 29:
* New Style classes can use descriptors (including slots), and Old Style classes cannot. Normally, this is just an advantage for New Classes, but it can affect lookup. An old-style class will always find an attribute on an instance before it looks in the hierarchy. (So you can hide a method.) A new-style class will let the class definition win if it is a writeable descriptor, so you may not be able to (effectively) store data on an instance. [http://www.python.org/2.2.2/descrintro.html#property More information on slots and descriptors.]  * New Style classes can use descriptors (including {{{__slots__}}}), and Old Style classes cannot. Normally, this is just an advantage for New Style Classes, but it can affect lookup. An old-style class will always find an attribute on an instance before it looks in the hierarchy. (So you can hide a method.) A new-style class will let the class definition win if it is a writeable descriptor, so you may not be able to (effectively) store data on an instance. [[http://www.python.org/2.2.2/descrintro.html#property|More information on slots and descriptors.]]
Line 34: Line 31:
Warning: In 2.5, magic names (those with a double underscore at both ends of the name) may look at the class rather than the instance even for old-style classes. I say this based on some python-dev discussion; I didn't notice how solidly the final decision was made. Warning: In 2.5, magic names (typically those with a double underscore (DunderAlias) at both ends of the name) may look at the class rather than the instance even for old-style classes. I say this based on some python-dev discussion; I didn't notice how solidly the final decision was made.  Later discussion extended it to "next" (despite the lack of underscore) and Guido said not to count on it in either direction. Since magic names are supposed be generally reserved anyhow, normal code should not care.
Line 36: Line 33:
* Magic names have changed a little. Old classes don't have an __mro__, new classes (generally) don't have __members__ or __methods__. New classes generally won't let you change the class's __bases__ or __name__ (though you can still call it whatever you want in your namespace) and are pickier about changing an object's __class__. See http://www.python.org/2.2.2/bugs.html for a list of expected converting-an-old-class-to-a-new-class problems.  * Magic names (which ones even exist) have changed a little. Old classes don't have an {{{__mro__}}}, new classes (generally) don't have {{{__members__}}} or {{{__methods__}}}. New classes generally won't let you change the class's {{{__bases__}}} or {{{__name__}}} (though you can still call it whatever you want in your namespace) and are pickier about changing an object's {{{__class__}}}. See http://www.python.org/2.2.2/bugs.html for a list of expected converting-an-old-class-to-a-new-class problems.
Line 38: Line 35:
* When numeric operations (including "*", or "%") are applied to objects of different types, there is a fairly complex chain of logic to decide what should eventually happen. For old-style classes, there is often an attempt to Coerce the objects to the same type; for new style classes, there is no automatic call to __coerce__. (Really just an important example of the magic names change.)  * When numeric operations (including "*", or "%") are applied to objects of different types, there is a fairly complex chain of logic to decide what should eventually happen. For old-style classes, there is often an attempt to Coerce the objects to the same type; for new style classes, there is no automatic call to {{{__coerce__}}}. (Really just an important example of the magic names change.)
Line 40: Line 37:
* An Exception cannot be a New-Style class. This is a wart that may change in the future; for the moment it is required because of some complex backward compatibility dances involving (deprecated) string exceptions and whether a raised object should be treated as a Class or as an Instance of a Class. Note that you can inherit from both Exception and object; you just can't raise the result.  * An Exception cannot be a New-Style class. This is a wart that will probably be removed in 2.5. (As of 2.5a1, Exception is New Style.) Previously it was required because of some complex backward compatibility dances involving (deprecated) string exceptions and whether a raised object should be treated as a Class or as an Instance of a Class. Note that you can inherit from both Exception and object; you just can't raise the result.
Line 43: Line 40:
>>> class NewException(Exception, object): >>> class NewException(Exception, object):
Line 46: Line 43:
>>> raise NewException >>> raise NewException
Line 49: Line 46:
  File "&lt;pyshell#22&gt;", line 1, in -toplevel-   File "<pyshell#22>", line 1, in -toplevel-
Line 53: Line 50:
&gt;&gt;&gt; raise NewException() >>> raise NewException()
Line 56: Line 53:
  File "&lt;pyshell#23&gt;", line 1, in -toplevel-   File "<pyshell#23>", line 1, in -toplevel-
Line 61: Line 58:
* MRO; [http://www.python.org/2.3/mro.html Method Resolution Order]  * MRO; [[http://www.python.org/2.3/mro.html|Method Resolution Order]]
Line 63: Line 60:
New Style classes search each base class only once. New Style classes search each base class only once, and the order may slightly different than you would get with an ambiguous Old Style class.
Line 66: Line 63:
&gt;&gt;&gt; class Old: pass
&gt;&gt;&gt; class O1(Old): pass
&gt;&gt;&gt; class O2(Old): pass
&gt;&gt;&gt; class OD(O1, O2): pass
>>> class Old: pass
>>> class O1(Old): pass
>>> class O2(Old): pass
>>> class OD(O1, O2): pass
Line 71: Line 68:
&gt;&gt;&gt; OD.__mro__ >>> OD.__mro__
Line 73: Line 70:
  File "&lt;pyshell#24&gt;", line 1, in -toplevel-   File "<pyshell#24>", line 1, in -toplevel-
Line 84: Line 81:
&gt;&gt;&gt; class New(object): pass
&gt;&gt;&gt; class N1(New): pass
&gt;&gt;&gt; class N2(New): pass
&gt;&gt;&gt; class ND(N1, N2): pass
&gt;&gt;&gt; ND.__mro__
(&lt;class '__main__.ND'&gt;, &lt;class '__main__.N1'&gt;, &lt;class '__main__.N2'&gt;, &lt;class '__main__.New'&gt;, &lt;type 'object'&gt;)
>>> class New(object): pass
>>> class N1(New): pass
>>> class N2(New): pass
>>> class ND(N1, N2): pass
>>> ND.__mro__
(<class '__main__.ND'>, <class '__main__.N1'>, <class '__main__.N2'>, <class '__main__.New'>, <type 'object'>)
Line 92: Line 89:
So New (and it's own base, object) is only searched once -- after *all* of its own subclasses have already been searched. So New (and its own base, object) is only searched once -- after *all* of its own subclasses have already been searched.

A "New Class" is the recommended way to create a class in modern Python.

A "Classic Class" or "old-style class" is a class as it existed in Python 2.1 and before. They have been retained for backwards compatibility. This page attempts to list the differences.

The syntax for the two types looks the same; "new-style", "old style", "classic", and variants are just descriptions that various people have used; Python hasn't yet settled on a specific official choice for the terminology.

The minor syntactic difference is that New Style Classes happen to inherit from object.

class Old1:
    ...

class Old2(Old1, UserDict): # Assuming UserDict is still old-style
    ...

vs

class New1(object):
    ...
class New2(New1):
    ...
class New3(Old1, New2):
    ...
class New4(dict, Old1):  # dict is a newstyle class
    ...
  • New Style classes can use descriptors (including __slots__), and Old Style classes cannot. Normally, this is just an advantage for New Style Classes, but it can affect lookup. An old-style class will always find an attribute on an instance before it looks in the hierarchy. (So you can hide a method.) A new-style class will let the class definition win if it is a writeable descriptor, so you may not be able to (effectively) store data on an instance. More information on slots and descriptors.

Warning: In 2.5, magic names (typically those with a double underscore (DunderAlias) at both ends of the name) may look at the class rather than the instance even for old-style classes. I say this based on some python-dev discussion; I didn't notice how solidly the final decision was made. Later discussion extended it to "next" (despite the lack of underscore) and Guido said not to count on it in either direction. Since magic names are supposed be generally reserved anyhow, normal code should not care.

  • Magic names (which ones even exist) have changed a little. Old classes don't have an __mro__, new classes (generally) don't have __members__ or __methods__. New classes generally won't let you change the class's __bases__ or __name__ (though you can still call it whatever you want in your namespace) and are pickier about changing an object's __class__. See http://www.python.org/2.2.2/bugs.html for a list of expected converting-an-old-class-to-a-new-class problems.

  • When numeric operations (including "*", or "%") are applied to objects of different types, there is a fairly complex chain of logic to decide what should eventually happen. For old-style classes, there is often an attempt to Coerce the objects to the same type; for new style classes, there is no automatic call to __coerce__. (Really just an important example of the magic names change.)

  • An Exception cannot be a New-Style class. This is a wart that will probably be removed in 2.5. (As of 2.5a1, Exception is New Style.) Previously it was required because of some complex backward compatibility dances involving (deprecated) string exceptions and whether a raised object should be treated as a Class or as an Instance of a Class. Note that you can inherit from both Exception and object; you just can't raise the result.

>>> class NewException(Exception, object):
        pass

>>> raise NewException

Traceback (most recent call last):
  File "<pyshell#22>", line 1, in -toplevel-
    raise NewException
TypeError: exceptions must be classes, instances, or strings (deprecated), not type

>>> raise NewException()

Traceback (most recent call last):
  File "<pyshell#23>", line 1, in -toplevel-
    raise NewException()
TypeError: exceptions must be classes, instances, or strings (deprecated), not NewException

Old Style classes search each base class, including the bases of the bases, Left To Right. New Style classes search each base class only once, and the order may slightly different than you would get with an ambiguous Old Style class.

>>> class Old: pass
>>> class O1(Old): pass
>>> class O2(Old): pass
>>> class OD(O1, O2): pass

>>> OD.__mro__
Traceback (most recent call last):
  File "<pyshell#24>", line 1, in -toplevel-
    O.__mro__
AttributeError: class O has no attribute '__mro__'

OK, but write some methods to figure it out... and the effective MRO is

OD, O1, Old, O2, Old

So that Old is searched before its own derived class O2, then (uselessly) searched again at the end.

>>> class New(object): pass
>>> class N1(New): pass
>>> class N2(New): pass
>>> class ND(N1, N2): pass
>>> ND.__mro__
(<class '__main__.ND'>, <class '__main__.N1'>, <class '__main__.N2'>, <class '__main__.New'>, <type 'object'>)

So New (and its own base, object) is only searched once -- after *all* of its own subclasses have already been searched.

Generally, the New MRO is better, but they aren't the same, and it can be painful to inherit from both types of class in the same derived class.

One time when the older method did work better was mixin classes -- if you assume that methods will always be completely overridden (not just extended), then the old conventions are simpler and cleaner. If you need to combine methods, the old conventions (to explicitly call Base.method(self, args)) required a fragile knowledge of the inheritance hierarchy.


CategoryDocumentation

NewClassVsClassicClass (last edited 2019-10-19 23:41:13 by FrancesHocutt)

Unable to edit the page? See the FrontPage for instructions.