?

Log in

No account? Create an account
Previous Entry Share Next Entry
Incompatabilities between classic and new-style Python classes
jcalderone

radix asked me if I had a blog post about why changing a class from classic to new-style is a bad idea. After I told him that I didn't he insisted that I should write one. Since doing so will take less work than finding something else to distract his attention, here it is:

  • attribute lookup

    Attributes on instances of classic classes override attributes of the same name on their class. For example:

    >>> class SimpleDescriptor(object):
    ...     def __get__(self, instance, type):
    ...             print 'getting'
    ...             return instance.__dict__['simple']
    ...     def __set__(self, instance, value):
    ...             print 'setting'
    ...             instance.__dict__['simple'] = value
    ...
    >>> class classic:
    ...     simple = SimpleDescriptor()
    ...
    >>> x = classic()
    >>> x.simple = 10
    >>> x.simple
    10
    >>> class newstyle(object):
    ...     simple = SimpleDescriptor()
    ...
    >>> x = newstyle()
    >>> x.simple
    getting
    Traceback (most recent call last):
      File "", line 1, in ?
      File "", line 4, in __get__
    KeyError: 'simple'
    >>> x.simple = 10
    setting
    >>> x.simple
    getting
    10
    
    As you can see, the descriptor on the new-style class can both handle the setattr and continue to operate after shadowing itself with an instance variable.

  • Special methods

    A particularly interesting consequence of the previous point is that the behavior of special methods changes in some cases:

    >>> class x:
    ...     def __init__(self):
    ...             self.__eq__ = lambda other: True
    ...
    >>> x() == 10
    True
    >>> class x(object):
    ...     def __init__(self):
    ...             self.__eq__ = lambda other: True
    ...
    >>> x() == 10
    False
    >>>
    

  • MRO

    Rules for determining the method resolution forbid new-style classes in places where classic classes are acceptable. Consider:

    >>> class x: pass
    ...
    >>> class y(object, x): pass
    ...
    >>> class x(object): pass
    ...
    >>> class y(object, x): pass
    ...
    Traceback (most recent call last):
      File "", line 1, in ?
    TypeError: Error when calling the metaclass bases
        Cannot create a consistent method resolution
    order (MRO) for bases object, x
    >>>
    

Hopefully that's enough to satisfy radix. Know of other incompatibilities? Please comment.


Comments Disabled:

Comments have been disabled for this post.