Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Problem subclassing tuple

168 views
Skip to first unread message

John Wilson

unread,
Apr 29, 2003, 11:55:21 AM4/29/03
to
Given this class:

class Holder(tuple):
def __init__(self, *values):
tuple.__init__(self, values)


When I try to create an instance:

Holder(1, 2)

I get:

TypeError: tuple() takes at most 1 argument (2 given)

It looks like the constructor for the superclass is being called rather than
the __init__ method on Holder.

I'm obviously missing something here. Do I have to supply a __new__ method?
Any help would be appreciated.

John Wilson
The Wilson Partnership
http://www.wilson.co.uk


Aahz

unread,
Apr 29, 2003, 12:22:14 PM4/29/03
to
In article <mailman.1051631814...@python.org>,

John Wilson <t...@wilson.co.uk> wrote:
>
>class Holder(tuple):
> def __init__(self, *values):
> tuple.__init__(self, values)
>
>When I try to create an instance:
>
>Holder(1, 2)
>
>I get:
>TypeError: tuple() takes at most 1 argument (2 given)

Use __new__ instead of __init__.
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/

"In many ways, it's a dull language, borrowing solid old concepts from
many other languages & styles: boring syntax, unsurprising semantics,
few automatic coercions, etc etc. But that's one of the things I like
about it." --Tim Peters on Python, 16 Sep 93

Terry Reedy

unread,
Apr 29, 2003, 12:48:48 PM4/29/03
to

"John Wilson" <t...@wilson.co.uk> wrote in message
news:mailman.1051631814...@python.org...

> Given this class:
>
> class Holder(tuple):
> def __init__(self, *values):
> tuple.__init__(self, values)
>
>
> When I try to create an instance:
>
> Holder(1, 2)
>
> I get:
>
> TypeError: tuple() takes at most 1 argument (2 given)
>
> It looks like the constructor for the superclass is being called
rather than
> the __init__ method on Holder.
>
> I'm obviously missing something here. Do I have to supply a __new__
method?
> Any help would be appreciated.


Because tuples are immutable, one cannot mutate them in an init
method, even to set the initial values. So, as you apparently
suspected, they are initialized in the __new__ method from a sequence.
This is the source of the exception (see below). tuple.__init__ should
be a no op.

>>> class Holder(tuple):
... def __init__(self, *values):
... print "Holder init entered"
...
>>> Holder(1,2)
Traceback (most recent call last):
File "<stdin>", line 1, in ?


TypeError: tuple() takes at most 1 argument (2 given)

# init not entered
>>> Holder((1,2))
Holder init entered
(1, 2)

While Holder.__init__() cannot modify the value of self, it *can* add
attributes (which surprised me a bit) so it can have a use.

>>> class Holder(tuple):
... def __init__(self, seq):
... self.y = 1
...
>>> a=Holder((1,2))
>>> a.y
1

I don't know what more you could do in a __new__ method.

Terry J. Reedy


sism...@hebmex.com

unread,
Apr 29, 2003, 11:56:17 AM4/29/03
to
> From: John Wilson [mailto:t...@wilson.co.uk]
> Sent: Tuesday, April 29, 2003 10:55 AM

>
> Given this class:
>
> class Holder(tuple):
> def __init__(self, *values):
> tuple.__init__(self, values)
>
>
> When I try to create an instance:
>
> Holder(1, 2)
>
> I get:
>
> TypeError: tuple() takes at most 1 argument (2 given)
>
> It looks like the constructor for the superclass is being
> called rather than the __init__ method on Holder.
>
> I'm obviously missing something here. Do I have to supply a
> __new__ method? Any help would be appreciated.
>
> John Wilson
>

Howdy.

First of all... What are you trying to do? :-)

Second. If that's the full definition and intention
of "Holder", then you might want to know (or are
overlooking) the fact that "values", inside __init__,
is already a tuple.

Instead of a class Holder, you could build a function
holder() which simply returns the tuple it receives:

def holder(*values):
return values

One of the most useful functions I've encountered
which simplified my (programming) life in small but
noticeable ways, is the following:

def Dict(**values):
return values

This allows me to define dictionaries like this:

d = Dict(one=1, two="Two", three=...)

instead of this:

d = { "one":1, "two":"Two", ... }

So...

hth.

-gus

sism...@hebmex.com

unread,
Apr 29, 2003, 12:16:03 PM4/29/03
to
>
> I'm really quite interested in why this doesn't work. I *thought* I'd
> grasped the concept of the new style classes but this seems
> to demonstrate
> that I haven't!
>
> Thanks for the response.

>
> John Wilson
> The Wilson Partnership
> http://www.wilson.co.uk
>

Most prob'ly you've already grasped it; the problem with
the current implementation is that many internal classes
don't "allow" subclassing, because the interpreter's
internal mechanics access the C code for those classes
(and subclasses), so your Python code doesn't get called.

Bummer, really. :-/

-gus

John Wilson

unread,
Apr 29, 2003, 12:27:10 PM4/29/03
to

----- Original Message -----
From: <sism...@hebmex.com>
To: <pytho...@python.org>
Sent: Tuesday, April 29, 2003 5:16 PM
Subject: RE: Problem subclassing tuple


[snip]

> Most prob'ly you've already grasped it; the problem with
> the current implementation is that many internal classes
> don't "allow" subclassing, because the interpreter's
> internal mechanics access the C code for those classes
> (and subclasses), so your Python code doesn't get called.
>
> Bummer, really. :-/

No doubt this will be fixed in the future. I'll just create a class which
delegates the calls I need to support.

Many thanks for your help - at least I know it's not my brain softening :-))

John Wilson

unread,
Apr 29, 2003, 1:18:28 PM4/29/03
to

----- Original Message -----
From: "Aahz" <aa...@pythoncraft.com>
[snip]

>
> Use __new__ instead of __init__.
> --

I tried:

... def __new__(cls, *args, **kargs):
... instance = object.__new__(cls)
... tuple.__init__(instance, args)
...

But I got:

>>> Holder(1, 2)


Traceback (most recent call last):
File "<stdin>", line 1, in ?

File "<stdin>", line 3, in __new__
TypeError: object.__new__(Holder) is not safe, use tuple.__new__()

I'm sure I'm being dense. Can you advise me as what to do in the __new__
method?

John Wilson

unread,
Apr 29, 2003, 12:19:13 PM4/29/03
to

----- Original Message -----
[snip]

>
> Howdy.
>
> First of all... What are you trying to do? :-)

I am trying to add some methods to a tuple. Obviously the example I posted
has been considerably simplified to just demonstrate the problem I'm hitting
;-))

>
> Second. If that's the full definition and intention
> of "Holder", then you might want to know (or are
> overlooking) the fact that "values", inside __init__,
> is already a tuple.

Yes, but I want an object which has all the characteristics of a tuple with
additional methods.

I could use delegation to do this but subclassing appeared to be an easier
way.

I'm really quite interested in why this doesn't work. I *thought* I'd
grasped the concept of the new style classes but this seems to demonstrate
that I haven't!

Thanks for the response.

John Wilson

John Wilson

unread,
Apr 29, 2003, 3:08:39 PM4/29/03
to

----- Original Message -----
From: "Terry Reedy" <tjr...@udel.edu>
Newsgroups: comp.lang.python
To: <pytho...@python.org>
Sent: Tuesday, April 29, 2003 5:48 PM
Subject: Re: Problem subclassing tuple


[snip]

Terry,
I have found that I can subclass list OK.

This will do for what I'm after.

Thanks to all the contributors to this thread for all the info :-))

John Wilson

unread,
Apr 29, 2003, 3:22:11 PM4/29/03
to
Success!!!

class Holder(tuple):
def __new__(cls, *args, **kargs):
return tuple.__new__(cls, args)


is the way to do it for a tuple :))))))

Skip Montanaro

unread,
Apr 29, 2003, 3:45:07 PM4/29/03
to

>> You might want to make it "cooperative", that is, instead of using
>> "tuple.__new__", use "super(Holder,cls).__new__"

>> This delegates the search for the superclass to the function super();
>> and that gives you the ability to have multiple inheritance, since
>> super() will "do the right thing" when getting your current class'
>> superclass; so every class which defines a __new__ method has it
>> called.

I don't believe it matters here. As I recall, builtins don't support
multiple inheritance very well (if at all). The most you can do is add
mixin classes.

Skip

sism...@hebmex.com

unread,
Apr 29, 2003, 3:27:25 PM4/29/03
to
> From: John Wilson [mailto:t...@wilson.co.uk]
> Sent: Tuesday, April 29, 2003 2:22 PM

>
> Success!!!
>
> class Holder(tuple):
> def __new__(cls, *args, **kargs):
> return tuple.__new__(cls, args)
>
>
> is the way to do it for a tuple :))))))
>
> John Wilson
>

Heh, excellent :-)

You might want to make it "cooperative", that is,
instead of using "tuple.__new__", use
"super(Holder,cls).__new__"

This delegates the search for the superclass to the
function super(); and that gives you the ability
to have multiple inheritance, since super() will
"do the right thing" when getting your current
class' superclass; so every class which defines
a __new__ method has it called.

:-)

Like this:

Python 2.2 (#28, Dec 21 2001, 12:21:22) [MSC 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class Holder(tuple):
... def __new__(klass, *args, **kwargs):
... return super(Holder,klass).__new__(klass, args)
...
>>> h = Holder(1,2,3)
>>>
>>> h
(1, 2, 3)
>>> type(h)
<class '__main__.Holder'>
>>>


-gus

Bengt Richter

unread,
Apr 29, 2003, 5:07:15 PM4/29/03
to

I suppose you could mess with the value, e.g.,

>>> class H(tuple):
... def __new__(cls, seq):
... return tuple.__new__(cls,seq+seq)
...
>>> H([1,2,3])
(1, 2, 3, 1, 2, 3)
>>> H('abc')
('a', 'b', 'c', 'a', 'b', 'c')
>>> h= H('abc')
>>> h
('a', 'b', 'c', 'a', 'b', 'c')
>>> type(h)
<class '__main__.H'>

Regards,
Bengt Richter

Michele Simionato

unread,
Apr 29, 2003, 5:46:08 PM4/29/03
to
"John Wilson" <t...@wilson.co.uk> wrote in message news:<mailman.105163462...@python.org>...
> <snip> I want an object which has all the characteristics of a tuple with
> additional methods.

What about this ?

class Holder(tuple):
def additionalmethod(self):
print "ciao ciao"

t=Holder((1,2))

print t #=> (1,2)

t.additionalmethod() #=> ciao ciao

If you want to avoid the parenthesis, here is the solution:

class Holder(tuple):
def __new__(cls,*args):
return tuple.__new__(cls,args)
def additionalmethod(self):
print "ciao ciao"

t=Holder(1,2)

print t # => (1,2)

t.additionalmethod() #=> ciao ciao

Easy, isn't it ?

Michele

Michele Simionato

unread,
Apr 30, 2003, 8:44:24 AM4/30/03
to
Skip Montanaro <sk...@pobox.com> wrote in message news:<mailman.1051645702...@python.org>...

Indeed. According to Guido (see
http://www.python.org/2.2.2/descrintro.html#subclassing):

You can use multiple inheritance, but you can't multiply inherit from
different built-in types (for example, you can't create a type that
inherits from both the built-indict and list types). This is a
permanent restriction; it would require too many changes to Python's
object
implementation to lift it. However, you can create mix-in classes by
inheriting from "object".

Here is an exapmple for the OP's edification:

class Holder(tuple):
def __new__(cls, *args, **kargs):

return super(Holder,cls).__new__(cls, args)

class Pretty(object):
def __str__(self):
return '*** %s ***' % super(Pretty,self).__str__()


class PrettyHolder(Pretty,Holder): pass

t=PrettyHolder(1,2)

print t #=> *** (1, 2) ***

Michael Chermside

unread,
Apr 30, 2003, 12:35:02 PM4/30/03
to
John Wilson writes:
[This doesn't work:

> class Holder(tuple):
> def __init__(self, *values):
> tuple.__init__(self, values)

[...]

> class Holder(tuple):
> def __new__(cls, *args, **kargs):

> return tuple.__new__(cls, args)

> is the way to do it for a tuple :))))))

[...]

> I'm really quite interested in why this doesn't work. I *thought* I'd
> grasped the concept of the new style classes but this seems to demonstrate
> that I haven't!

Actually, you've discovered the original reason for the invention
of __new__. Guido invented __new__ because __init__ wouldn't work
for classes like tuple that were immutable. The combination of __new__
and __init__ is what is called "two stage initialization" -- the
__new__ method is the "factory", that just creates the empty object,
while __init__ is the "initializer" that sets up the object. Normally,
you want to override __init__ -- the only exceptions are those cases
where you NEED __new__. For instance, if you want to return objects
of different types depending on some parameters, then you'll need to
use __new__ (or just use a factory function instead of a constructor!).
Or if you want to "initialize" an immutable object, then it'll have
to be done in __new__ (that's your situation).

For more about it, including some discussion of why two stage
initialization is so good, see
http://cocoa.mamasam.com/MACOSXDEV/2003/03/1/58013.php (and I thought
I'd heard a discussion of the subject in Python recently, but couldn't
find a link).

-- Michael Chermside


John Wilson

unread,
Apr 30, 2003, 1:14:57 PM4/30/03
to

----- Original Message -----
From: "Michael Chermside" <mch...@mcherm.com>
[snip]
> For more about it, including some discussion of why two stage
> initialization is so good, see
> http://cocoa.mamasam.com/MACOSXDEV/2003/03/1/58013.php (and I thought
> I'd heard a discussion of the subject in Python recently, but couldn't
> find a link).

Thanks - the discussion looks very interesting.

0 new messages