0

I would like to create a class that, when I call without the double brackets, returns a value in any context, just like what str or int does. For example, what can I do to make this possible:

>>> class color:
...     def __init__(self, r, g, b):
...         self.r = r
...         self.g = g
...         self.b = b
...     def whatever_it_is(self):
...         return (self.r, self.g, self.b) # Class returns tuple
>>> myColor = color(16, 32, 64)
>>> myColor.g
32
>>> myColor
(16, 32, 64)
>>> color(5, 68, 37)
(5, 68, 37)

My goal is to create a color class compatible with Pygame. For example, I could do mySurface.fill(color(16, 32, 64)), which would be the same as mySurface.fill((16, 32, 64)). My color class is like pygame.math.Vector2, but written in Python and not C.

As well as this, I have a bonus question that doesn't need to be answered: How do I make a class that can't be constructed?

Is this possible in Python 3.9?

Final edit: The answer below does not work fully. Here is what I mean:

>>> myColor = color(1, 2, 3)
>>> myColor
(1, 2, 3)
>>> myColor.g
2
>>> myColor.g = 4
>>> myColor
(1, 2, 3)
>>> myColor.g
4

I have found out about the __iter__ magic method and my highest priority was Pygame compatibility by converting a class to a tuple, so... ¯\_(ツ)_/¯

12
  • Does this help you ? Commented Jan 10, 2021 at 12:41
  • How do I make a class that can't be constructed, what do you mean by this? You can just not define a constructor (__init__ method) Commented Jan 10, 2021 at 12:41
  • @limserhane I want to call the class like thisClass to get a value without conversion using tuple() and such. Commented Jan 10, 2021 at 12:43
  • 3
    You could make your class an extension of tuple, or in this case just use the existing namedtuple in collections. Or make your class a sequence, like tuples are. But there's no magic method for what you're asking because how would you distinguish between when you're supposed to be accessing the instance and when the value it wraps? Commented Jan 10, 2021 at 12:45
  • 1
    Why do you want to create a class that works as a tuple if you can simply use tuples? mycol = (16,43,200) and then use mycol ... you can create it as constant somewhere and use it ... creating a class simply to have a class makes no sense to me? Commented Jan 10, 2021 at 12:49

1 Answer 1

3

You want your class to be act like a tuple but you also want to add some custom attributes to reach color codes (i.e myColor.g). In this case you can subclass tuple and write a custom __new__:

class color(tuple):
    def __new__ (cls, r, g, b):
        # Here we are saying that initialize a new tuple with
        # arguments we provided. tuple expects one parameter
        # so we are sending r, g, b as one parameter: (r, g, b)
        return super(color, cls).__new__(cls, (r, g, b))

    def __init__(self, r, g, b):
        # Then we can add whatever attribute we like to our tuple.
        self.r = r
        self.g = g
        self.b = b

>>> myColor = color(16, 32, 64)
>>> myColor.g
32
>>> myColor
(16, 32, 64)
>>> myColor == (16, 32, 64)
True

As suggested by kaya3 in the comments, the same thing can be achieved by using namedtuples:

>>> from collections import namedtuple
>>> color = namedtuple('color', ('r', 'g', 'b'))
>>> myColor = color(16, 32, 64)
>>> myColor.g
32
>>> myColor
color(r=16, g=32, b=64)
>>> myColor == (16, 32, 64)
True
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you so much! I wish you could explain what is happening in the new method. I do not know much about how super() works.
@BlueStaggo You can check the edit. I hope it's more clear now.
This is a longwinded way of creating a collections.namedtuple.
@kaya3 I didn't know namedtuples can do this. I'll edit the post to mention about it. Thanks!
Slightly shorter way: namedtuple('color', 'r g b') since the constructor accepts a string of space-separated attribute names.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.