class inheritance python2.7 vs python3.3

J

jwe.van.dijk

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 __name__ == '__main__:
y = y = 'x_0 * x_1 + x_2'
stats1 = LPU1(y)
stats3 = LPU3(y)

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

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.

Many thanks, Janwillem
 
C

Chris Angelico

class LPU3(LPU1):
def __new__(self):
"""
the same functions as LPU1 but some added functions
and some functions redefined
"""

You probably don't want to be using __new__ here. Try using __init__
instead, or simply not defining __new__ at all.

I suspect that the reason that appears to work under Py2 is that
you're using an old-style class, there. That means it'll be subtly
different on the two versions. To make them do the same thing,
explicitly subclass object:

class LPU1(object):

In Python 3, that's redundant - subclassing object is the default. In
Python 2, though, it's important.

ChrisA
 
D

Dave Angel

I have problems with these two classes:

class LPU1() :

You forgot to derive from object. That's implied on 3.x, but you say
you're also running on 2.7 Without naming your base class you're
asking for an old style class which has been obsolete maybe 10 years.
I sure don't recall how it differs.
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

You don't show where you call super, so we can't tell what you had in
mind. And did you actually mean __new__ here or should you have
defined __init__ as you did in the base class?
if __name__ == '__main__:
y = y = 'x_0 * x_1 + x_2'
stats1 = LPU1(y)
stats3 = LPU3(y)

And where did you expect that y to go?

Worked perfectly on Python 2.7.5+ but on Python 3.3.2+ I get on
instantiatiating stat3:

I don't see anything called stat3. Presumably you mean stats3, but
you're not instantiating it you're instantiating LPU3.
TypeError: __new__() takes 1 positional argument but 2 were given

You forgot to include the rest of the stack trace.


I think the real problem is you forgot to include the second
parameter on the misnamed __init__ method. It should have parameters
self and arg, and pass arg up through super.
 
S

Steven D'Aprano

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.
 
J

jwe.van.dijk

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 __name__ == '__main__:

y = y = 'x_0 * x_1 + x_2'

stats1 = LPU1(y)

stats3 = LPU3(y)



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



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.



Many thanks, Janwillem

Thanks for all the contributions. I now have:
class LPU1(object):
def __init__(self, formula):
... ...
and
class LPU3(LPU1):
def __init__(self, y):
LPU1.__init__(self, y)
... ...

which gives the correct results both on 2.7 and 3.3.
Is that more or less good practice?
Now I stumble on a SymPy problem under 3.3 but that obviously is an other topic
Cheers, janwillem
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top