1

I am trying to implement a very basic Java-like Dimension-Class in Python:

class Dimension(object):
    def __init__(self, width, height):
        self.__width = width
        self.__height = height

    @property
    def width(self):
        return self.__width
    @property
    def height(self):
        return self.__height
d = Dimension(800, 400)

print d.width
print d.height

This works fine: d.width returns an int=800, d.height returns an int=400. But how do I define, that d should return a tuple=(800,400) instead of <__main__.Dimension object at 0xXXXXXXXX>?

Is there an in-built class function similar to __repr__ for it? How do I define the returned value of a custom class? Or do I have to implement a new type?

Thank you

6
  • You can make __init__ return a tuple width, height but I guess that's not what you want, since you can't use all the instance methods then. If you want to implement conversion to a tuple then you should implement the __iter__ method: return (self.width, self.height). Commented Jan 17, 2017 at 14:58
  • d doesn't return anything; that is what it is. (Try the same thing with a function.) Methods & functions return values when called; you don't call a class. If you want a method to call to get this type of value, add it to your class. Commented Jan 17, 2017 at 15:02
  • 1
    @ a_guest I don't know what you expect that to do, but __init__ must return None, or you'll get TypeError when you try to create an instance of the class. For your example, you'd get TypeError: __init__() should return None, not 'tuple'. Commented Jan 17, 2017 at 15:13
  • BTW, @property should only be used when you need to evaluate some expression. Don't use it when a simple attribute lookup will suffice. Python isn't Java. Only create getters or setters when you really need them. Commented Jan 17, 2017 at 15:17
  • On a similar note, don't use leading double-underscore names like .__width unless you really need to invoke Python's name-mangling machinery. If you need private attributes (which you probably don't in this case), use a single leading underscore. And if you need to ask if you need Python's name-mangling machinery in a particular case, you probably don't. ;) Commented Jan 17, 2017 at 15:20

3 Answers 3

4

If you want your class to behave as a tuple, inherit from tuple:

class Dimension(tuple):

then override the __new__ method to manipulate the creation:

def __new__(cls, width, height):
    tuple.__new__(cls, (width, height))

Leaving you with:

class Dimension(tuple):

    def __new__(cls, width, height):
        return tuple.__new__(cls, (width, height)) # create tuple with 2 items

    def __init__(self, *args):
        self.width = args[0] # width is the first argument passed
        self.height = args[1] # height is the next

>>> d = Dimension(800, 400)
>>> print(d)
(800, 400)
>>> print(d.width)
800
>>> print(d.height)
400
Sign up to request clarification or add additional context in comments.

2 Comments

I thought inheriting from tuple would be a nice idea, so I suggested it... but now its looks like an overkill and some black magic :) Nevertheless, this solution is quite nice, depending on the use case
I agree, it's exactly what I searched for, but it looks really unconventional. Second opinion on this?
2

The closest thing that i can think of to what you described is using namedtuples

In [1]: from collections import namedtuple

In [2]: Dimension = namedtuple("Dimension", ('width', 'height'))

In [4]: d = Dimension(800, 400)

In [5]: d.width
Out[5]: 800

In [6]: d.height
Out[6]: 400

In [7]: d
Out[7]: Dimension(width=800, height=400)

In [8]: tuple(d)
Out[8]: (800, 400)

In [11]: w, h = d

In [12]: w, h
Out[12]: (800, 400)

Does this work for you? You could find more info about namedtuples here: https://docs.python.org/2/library/collections.html#collections.namedtuple

3 Comments

Isn't it possible to work around the "tuple(d)" part?
You can use it like a regular tuple (see w, h = d part), if you could tell me where do you want to use this, maybe i can help you more.
Actually I asked without testing. I assumed that d[0] wound not work, which was wrong. Works perfectly fine. Thank you
0

I suggest implementing __iter__ for conversion to tuple:

class Dimension:
    # Other code goes here.

    def __iter__(self):
        return iter([self.width, self.height])

Note that I made width and height direct attributes of Dimension instead of using @property.

Example:

>>> d = Dimension(1, 2)
>>> tuple(d)
(1, 2)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.