Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > int.__init__ incompatible in Python 3.3

Reply
Thread Tools

int.__init__ incompatible in Python 3.3

 
 
Ulrich Eckhardt
Guest
Posts: n/a
 
      11-08-2012
Hi!

Preparing for an upgrade from 2.7 to 3, I stumbled across an
incompatibility between 2.7 and 3.2 on one hand and 3.3 on the other:

class X(int):
def __init__(self, value):
super(X, self).__init__(value)
X(42)

On 2.7 and 3.2, the above code works. On 3.3, it gives me a "TypeError:
object.__init__() takes no parameters". To some extent, this makes sense
to me, because the int subobject is not initialized in __init__ but in
__new__. As a workaround, I can simple drop the parameter from the call.
However, breaking backward compatibility is another issue, so I wonder
if that should be considered as a bug.

Bug? Feature? Other suggestions?


Uli


 
Reply With Quote
 
 
 
 
Ian Kelly
Guest
Posts: n/a
 
      11-08-2012
On Thu, Nov 8, 2012 at 8:55 AM, Ulrich Eckhardt
<> wrote:
> Hi!
>
> Preparing for an upgrade from 2.7 to 3, I stumbled across an incompatibility
> between 2.7 and 3.2 on one hand and 3.3 on the other:
>
> class X(int):
> def __init__(self, value):
> super(X, self).__init__(value)
> X(42)
>
> On 2.7 and 3.2, the above code works. On 3.3, it gives me a "TypeError:
> object.__init__() takes no parameters". To some extent, this makes sense to
> me, because the int subobject is not initialized in __init__ but in __new__.
> As a workaround, I can simple drop the parameter from the call. However,
> breaking backward compatibility is another issue, so I wonder if that should
> be considered as a bug.
>
> Bug? Feature? Other suggestions?


A similar change was made to object.__init__ in 2.6, so this could
just be bringing the behavior of int into line with object. There's
nothing about it in the whatsnew document, though. I say open a bug
report and let the devs sort it out.
 
Reply With Quote
 
 
 
 
Terry Reedy
Guest
Posts: n/a
 
      11-08-2012
On 11/8/2012 12:13 PM, Ian Kelly wrote:
> On Thu, Nov 8, 2012 at 8:55 AM, Ulrich Eckhardt
> <> wrote:


>> Preparing for an upgrade from 2.7 to 3, I stumbled across an incompatibility
>> between 2.7 and 3.2 on one hand and 3.3 on the other:
>>
>> class X(int):
>> def __init__(self, value):
>> super(X, self).__init__(value)


This is a bug. Subclasses of immutables should not define __init__.
>>> int.__init__ is object.__init__

True

object.__init__(self) is a dummy placeholder function that takes no args
and does nothing.

>> X(42)
>>
>> On 2.7 and 3.2, the above code works.


That is a bug. It is documented that calling with the wrong number of
args is an error.

>> On 3.3, it gives me a "TypeError: object.__init__() takes no parameters".
>> To some extent, this makes sense to
>> me, because the int subobject is not initialized in __init__ but in __new__.
>> As a workaround, I can simple drop the parameter from the call.


Just drop the do-nothing call.

>> breaking backward compatibility is another issue, so I wonder if that should
>> be considered as a bug.


Every bug fix breaks backward compatibility with code that depends on
the bug. Such breakage is not a bug, but, as in this case, some fixes
are not put in bugfix releases because of such breakage.

>> Bug? Feature? Other suggestions?


Intentional bugfix.
http://bugs.python.org/issue1683368
There was additional discussion on pydev or python-ideas lists before
the final commit. This fix was not back-ported to 2.7 or 3.2.

> A similar change was made to object.__init__ in 2.6, so this could
> just be bringing the behavior of int into line with object. There's
> nothing about it in the whatsnew document, though.


What's New is a summary of *new* features. It does not list bug fixes.
At the top it says " For full details, see the Misc/NEWS file." The last
patch on the issue added this entry.
'''
Core and Builtins
-----------------

- Issue #1683368: object.__new__ and object.__init__ raise a TypeError
if they are passed arguments and their complementary method is not
overridden.
'''

> I say open a bug report and let the devs sort it out.


Please do not. The current situation is the result of 'sorting it out'
over several years.


--
Terry Jan Reedy

 
Reply With Quote
 
Ulrich Eckhardt
Guest
Posts: n/a
 
      11-09-2012
Am 08.11.2012 21:29, schrieb Terry Reedy:
> On Thu, Nov 8, 2012 at 8:55 AM, Ulrich Eckhardt
> <> wrote:
>>> On 3.3, it gives me a "TypeError: object.__init__() takes no
>>> parameters". To some extent, this makes sense to me, because the
>>> int subobject is not initialized in __init__ but in __new__. As a
>>> workaround, I can simple drop the parameter from the call.

>
> Just drop the do-nothing call.


Wait: Which call exactly?

Do you suggest that I shouldn't override __init__? The problem is that I
need to attach additional info to the int and that I just pass this to
the class on contstruction.

Or, do you suggest I don't call super().__init__()? That would seem
unclean to me.

Just for your info, the class mimics a C enumeration, roughly it looks
like this:

class Foo(int):
def __init__(self, value, name):
super(Foo, self).__init__(value)
self.name = name

def __str__(self):
return self.name

Foo.AVALUE = Foo(1, 'AVALUE')
Foo.BVALUE = Foo(2, 'BVALUE')

Note that even though I derive from an immutable class, the resulting
class is not formally immutable. Maybe exactly that is the thing that
the developers did not want me to do? I didn't understand all the
implications in the bug ticket you quoted, to be honest.

Thank you for your time!

Uli
 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      11-09-2012
On Fri, 09 Nov 2012 08:56:22 +0100, Ulrich Eckhardt wrote:

> Am 08.11.2012 21:29, schrieb Terry Reedy:
>> On Thu, Nov 8, 2012 at 8:55 AM, Ulrich Eckhardt
>> <> wrote:
>>>> On 3.3, it gives me a "TypeError: object.__init__() takes no
>>>> parameters". To some extent, this makes sense to me, because the int
>>>> subobject is not initialized in __init__ but in __new__. As a
>>>> workaround, I can simple drop the parameter from the call.

>>
>> Just drop the do-nothing call.

>
> Wait: Which call exactly?
>
> Do you suggest that I shouldn't override __init__? The problem is that I
> need to attach additional info to the int and that I just pass this to
> the class on contstruction.


No, of course not. If you need to override __init__, you need to override
__init__.


> Or, do you suggest I don't call super().__init__()? That would seem
> unclean to me.


On the contrary: calling super().__init__ when the superclass does
something you don't want (i.e. raises an exception) is unclean.

Since the superclass __init__ does nothing, you don't need to call it.
Only inherit behaviour that you actually *want*.

In Python 3.3:

py> class X(int):
.... def __init__(self, *args):
.... super().__init__(*args) # does nothing, call it anyway
....
py> x = X(22)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
TypeError: object.__init__() takes no parameters


It is apparently an oversight, or a bug, that it ever worked in older
versions.


> Note that even though I derive from an immutable class, the resulting
> class is not formally immutable. Maybe exactly that is the thing that
> the developers did not want me to do?


Nope, that's irrelevant. Attaching attributes to an otherwise immutable
object is fine.



--
Steven
 
Reply With Quote
 
Ulrich Eckhardt
Guest
Posts: n/a
 
      11-09-2012
Am 09.11.2012 12:37, schrieb Steven D'Aprano:
> On Fri, 09 Nov 2012 08:56:22 +0100, Ulrich Eckhardt wrote:
>> Or, do you suggest I don't call super().__init__()? That would seem
>> unclean to me.

>
> On the contrary: calling super().__init__ when the superclass does
> something you don't want (i.e. raises an exception) is unclean.
>
> Since the superclass __init__ does nothing, you don't need to call it.
> Only inherit behaviour that you actually *want*.



That one's hard to swallow for me, but maybe this is because I don't
understand the Python object model sufficiently. The problem I have here
is that not forwarding the __init__() to the baseclass could mean that
necessary initializations are not performed, although in this very
specify case I see that there aren't any. It still seems a bit like
relying on an implementation details.

Anyhow, I'll have to do some more reading on the the construction of
objects in Python, maybe then it'll all make sense. Until then, thanks
everybody for nudging me in the right direction!

Uli

 
Reply With Quote
 
Ian Kelly
Guest
Posts: n/a
 
      11-09-2012
On Fri, Nov 9, 2012 at 4:37 AM, Steven D'Aprano
<steve+> wrote:
> In Python 3.3:
>
> py> class X(int):
> ... def __init__(self, *args):
> ... super().__init__(*args) # does nothing, call it anyway
> ...
> py> x = X(22)
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> File "<stdin>", line 3, in __init__
> TypeError: object.__init__() takes no parameters
>
>
> It is apparently an oversight, or a bug, that it ever worked in older
> versions.


After reading through the bug history, I think that this change to int
is incorrect, or at least incomplete. The goal of the change to
object.__init__ is to enable checking for unused arguments when doing
cooperative multiple inheritance, with the idea that each class in the
hierarchy will remove the arguments it uses and pass the rest along.
By the time object.__init__ is reached, any arguments remaining are
unused and extraneous.

In the case of int, int.__new__ takes up to two arguments. Due to the
nature of the type system, these same two arguments are also passed to
int.__init__. If each subclass removes its own arguments per the
convention, then by the time int.__init__ is reached, there are still
up to two *expected* arguments remaining. It should not be the
responsibility of the subclasses (which one? all of them?) to remove
these arguments before calling super().__init__(). The int class
should have the responsibility of accepting and removing these two
arguments *and then* checking that there is nothing left over.

In Python 3.2, int.__init__ happily accepted the int arguments, but
also incorrectly accepted anything else you might pass to it, which
was suboptimal for cooperative multiple inheritance. In Python 3.3,
it no longer accepts unused arguments, but it also rejects arguments
intended for its own class that it should accept, which as I see it
makes int.__init__ *unusable* for cooperative multiple inheritance.

I realize that the recommendation in the bug comments is to use
__new__ instead of __init__ for subclasses of immutable types. But
then why have them call __init__ in the first place? Why even fuss
over what arguments int.__init__ does or does not accept if we're not
supposed to be calling it at all? And why is that deprecation not
mentioned anywhere in the documentation, that I can find?
 
Reply With Quote
 
Ulrich Eckhardt
Guest
Posts: n/a
 
      11-12-2012
Am 09.11.2012 12:37, schrieb Steven D'Aprano:
> In Python 3.3:
>
> py> class X(int):
> ... def __init__(self, *args):
> ... super().__init__(*args) # does nothing, call it anyway
> ...
> py> x = X(22)
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> File "<stdin>", line 3, in __init__
> TypeError: object.__init__() takes no parameters
>
>
> It is apparently an oversight, or a bug, that it ever worked in older
> versions.



I'm not really convinced that the overall behaviour is sound:

py> x = 42
py> x.__init__()
py> x.__init__(1)
py> x.__init__(1,2)
py> x.__init__(1,2,3)
py> x.__init__(1,2,3,4)

Neither of these seem to care about the number and type of parameters.
On the other hand:

py> y = object()
py> y.__init__()
py> y.__init__(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object.__init__() takes no parameters


So, for some reason that I don't understand yet, my call to the
superclass' init function skips a class, but only when called with super().


Confused greetings!

Uli

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Distributing 2 python modules with incompatible API mathieu Python 1 06-04-2008 02:54 PM
Python 2.5 incompatible with Fedora Core 6 - packaging problems again John Nagle Python 15 03-11-2007 01:24 AM
incompatible exit values between python 2.4 and 2.5 Anthon Python 2 09-18-2006 11:51 AM
Field Notice: New 7204VXR and 7206VXR Chassis Are Incompatible With Older PA-8B-S/T Christian Schuetz Cisco 0 07-10-2004 07:17 PM
why am i getting incompatible error MNQ VHDL 5 04-16-2004 07:54 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57