class inheritance python2.7 vs python3.3

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Jan 6 13:10:18 EST 2014


jwe.van.dijk at gmail.com wrote:

> I have problems with these two classes:
> 
> class LPU1():
>     def __init__(self, formula):
>         """
>         formula is a string that is parsed into a SymPy function
>         and several derived functions
>         """
>         self.formula = formula
>         ... ...
> 
> class LPU3(LPU1):
>         def __new__(self):
>         """
>         the same functions as LPU1 but some added functions
>         and some functions redefined
>         """
>         ... ...

If this actually is your class, then in Python 2.7 the __new__ method will
do nothing at all.

However, if you actually inherited from object in LPU1, then it (might) work
in Python 2.7. In Python 3.3, it will work regardless. Perhaps you have a
bug in the __new__ method? In Python 2.7, it is never called, and so the
bug never occurs. In Python 3.3, it is called, and the bug occurs.


> Worked perfectly on Python 2.7.5+ but on Python 3.3.2+ I get on
> instantiatiating stat3: TypeError: __new__() takes 1 positional argument
> but 2 were given

And sure enough, that's exactly it.



> What am I doing wrong?
> I must confess I am a bit out of my depth here so any explanation will be
> a learning experience.

Back in the Dark Ages of Python 1.x, built-in types like int, str, list and
so forth were completely independent of classes created with the class
statement. So you couldn't subclass them.

In Python 2.2, Python underwent what was called "class/type unification",
which added a new mechanism to allow built-in types to be subclassed. For
reasons of backward compatibility, the existing classes were left alone,
and were called "old style" or "classic" classes. But a new built-in,
called object, was created. All the other built-in types (str, list, int,
etc.) inherit from object. These became known as "new style classes".

New style classes had extra features that classic classes don't have,
including the __new__ constructor method. (Classic classes don't let you
override the constructor, only the initializer, __init__. New-style classes
let you override both.)

So Python 2.2 and beyond has two distinct models for classes, which *mostly*
work the same but have a few differences -- those that inherit from object
or some other built-in type, and those that don't.

# Python 2 classic class:
class LPU1():
     def __new__(cls): ...

__new__ is dead code here, and won't be called.

# Python 2 new-style class:
class LPU1(object):
     def __new__(cls): ...

__new__ is called.

So when you inherit from LPU1, your LPU3 class gets the same "old"
versus "new" behaviour, and __new__ is either dead code or not.

Now fast forward to Python 3. In Python 3, having two types of classes was
considered one too many. The old-style classes were dropped. Inheriting
from object became optional. Either way, you would get the same behaviour,
and __new__ is always used. So if you have a buggy __new__ method, it could
be ignored in Python 2 and suddenly run in Python 3, giving you an error.



-- 
Steven




More information about the Python-list mailing list