Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize an instance of a subclass of tuple in Python? [duplicate]

Possible Duplicate:
Subclassing Python tuple with multiple __init__ arguments

I want to define a class which inherits from tuple, and I want to be able to instantiate it using a syntax not supported by tuple. For a simple example, let's say I want to define a class MyTuple which inherits from tuple, and which I can instantiate by passing two values, x and y, to create the (my) tuple (x, y). I've tried the following code:

class MyTuple(tuple):
    def __init__(self, x, y):
        print("debug message")
        super().__init__((x, y))

But when I tried, for example, MyTuple(2, 3) I got an error: TypeError: tuple() takes at most 1 argument (2 given). It seems my __init__ function was not even called (based on the error I got and on the fact my "debug message" was not printed).

So what's the right way to do this?

I'm using Python 3.2.

like image 548
Tom Avatar asked Sep 29 '12 12:09

Tom


People also ask

What is the point of namedtuple?

Python's namedtuple was created to improve code readability by providing a way to access values using descriptive field names instead of integer indices, which most of the time don't provide any context on what the values are. This feature also makes the code cleaner and more maintainable.

What do subclasses inherit Python?

A subclass “inherits” all the attributes (methods, etc) of the parent class. This means that a subclass will have everything that its “parents” have. You can then change (“override”) some or all of the attributes to change the behavior.

What's a namedtuple?

A named tuple is exactly like a normal tuple, except that the fields can also be accessed by . fieldname. Named tuples are still immutable, you can still index elements with integers, and you can iterate over the elements. With a named tuple, you can say record.


2 Answers

class MyTuple(tuple):
    def __new__(cls, x, y):
        return tuple.__new__(cls, (x, y))

x = MyTuple(2,3)
print(x)
# (2, 3)

One of the difficulties of using super is that you do not control which classes's method of the same name is going to be called next. So all the classes' methods have to share the same call signature -- at least the same number of items. Since you are changing the number of arguments sent to __new__, you can not use super.


Or as Lattyware suggests, you could define a namedtuple,

import collections
MyTuple = collections.namedtuple('MyTuple', 'x y')

p = MyTuple(2,3)
print(p)
# MyTuple(x=2, y=3)
print(p.x)
# 2
like image 104
unutbu Avatar answered Oct 13 '22 02:10

unutbu


another approach would be to encapsulate a tuple rather than inheriting from it:

>>> class MyTuple(object):
    count = lambda self, *args: self._tuple.count(*args)
    index = lambda self, *args: self._tuple.index(*args)
    __repr__ = lambda self: self._tuple.__repr__()
    # wrap other methods you need, or define them yourself,
    # or simply forward all unknown method lookups to _tuple
    def __init__(self, x, y):
        self._tuple = x,y


>>> x = MyTuple(2,3)
>>> x
(2, 3)
>>> x.index(3)
1

How practical this is, depends on how many capabilities and modifications you need, and wheter you need to have isinstance(MyTuple(2, 3), tuple).

like image 31
ch3ka Avatar answered Oct 13 '22 01:10

ch3ka