views:

897

answers:

2

The following code works:

class Foo(tuple):

    def __init__(self, b):
        super(Foo, self).__init__(tuple(b))

if __name__ == '__main__':
    print Foo([3, 4])

$ python play.py 
play.py:4: DeprecationWarning: object.__init__() takes no parameters
  super(Foo, self).__init__(tuple(b))
(3, 4)

But not the following:

class Foo(tuple):

    def __init__(self, a, b):
        super(Foo, self).__init__(tuple(b))

if __name__ == '__main__':
    print Foo(None, [3, 4])

$ python play.py 
Traceback (most recent call last):
  File "play.py", line 7, in <module>
    print Foo(None, [3, 4])
TypeError: tuple() takes at most 1 argument (2 given)

Why?

+9  A: 

Because tuples are immutable, you have to override __new__ instead

python docs

object.__new__(cls[, ...])

Called to create a new instance of class cls. __new__() is a static method (special-cased so you need not declare it as such) that takes the class of which an instance was requested as its first argument. The remaining arguments are those passed to the object constructor expression (the call to the class). The return value of __new__() should be the new object instance (usually an instance of cls).

Typical implementations create a new instance of the class by invoking the superclass’s __new__() method using super(currentclass, cls).__new__(cls[, ...]) with appropriate arguments and then modifying the newly-created instance as necessary before returning it.

If __new__() returns an instance of cls, then the new instance’s __init__() method will be invoked like __init__(self[, ...]), where self is the new instance and the remaining arguments are the same as were passed to __new__().

If __new__() does not return an instance of cls, then the new instance’s __init__() method will not be invoked.

__new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.

gnibbler
can someone tell me how to quote the whole block so the double underscores don't mean bold?
gnibbler
Select the whole pasted text and click on the quote icon (black icon on top of the text box).
Sridhar Ratnakumar
Didn't work but it did indent it a little
gnibbler
I replaced them all with _
gnibbler
Inline code-tags are better in this example.
Georg
good idea, thanks
gnibbler
A: 

It looks like you're trying to create basically a "convenience" constructor, which takes a variable number of arguments and creates a tuple containing those arguments in the order they are given (not a bad idea, I wish tuple() and list() did this myself, sometimes). In these cases, a factory function is probably more appropriate:

def tuple_factory(*args):
    return tuple(args)

The syntax *args denotes a variable number of positional arguments; within the function body, args is a list. This list is then passed to the tuple constructor, which already accepts a sequence and returns a tuple containing the items in the sequence.

dcrosta