Search code examples
pythonimmutabilitydelegation

Customizing immutable types in Python


Let's say I want a custom frozenset with 2 elements, that iterates, hashes, compares, and has various other nice operations as a frozenset, but prints differently.

>>> p = edge(5, 7)
>>> p == edge(7, 5)
True
>>> p
edge(5, 7)

I can inherit, or I can delegate, but in neither case I get what I want.

If I inherit literally, there seems to be no way I can write __init__, because my parent is immutable. I can just write:

class edge:
    def __new__(cls, a, b):
        return frozenset({a, b})

but then I get a proper frozenset and cannot customize its __repr__, which is what I wanted to do. I cannot make super() to work here in any nice way.

If I delegate, I can override __getattr__ or __getattribute__, but none of them really works when for example __iter__ is sought. I guess special methods are too special here. The only solution I currently have is to manually delegate every special method I can think of, but surely there must be a better way. Any ideas?


Solution

  • Stupid me. It works now. If someone wants to know how to do it, here it is:

    class pair(frozenset):
        def __new__(cls, a, b):
            return super().__new__(cls, {a, b})
        def __repr__(self):
            a, b = sorted(self)
            return "{} & {}".format(a, b)
    

    The error was that I called super().__new__({a, b}) thinking that it will transmogrify my cls in the same way it does with self, when called without arguments. Of course, __new__ being implicitly classmethod didn't help. :-)