15
votes

I've the following class:

class MySet(set):

    def __init__(self, arg=None):
        if isinstance(arg, basestring):
            arg = arg.split()
        set.__init__(self, arg)

This works as expected (initialising the set with the words of the string rather than the letters). However when I want to do the same with the immutable version of set, the __init__ method seems to be ignored:

class MySet(frozenset):

    def __init__(self, arg=None):
        if isinstance(arg, basestring):
            arg = arg.split()
        frozenset.__init__(self, arg)

Can I achieve something similar with __new__ ?

1
I think the reason that __new__(..) takes the initiative when it comes to sculpting instances of immutable types is to take advantage of the immutability and reserve an opportunity to return an existing instance if available. (But if one doesn't want that advantage, then they could make an immutable type without messing with __new__(..). In particular, __new__(..) doesn't offer any special context. One would still have to modify immutable fields via object.__setattr__(..) or similar, whether that's within __new__(..) or __init_(..).) - Evgeni Sergeev

1 Answers

14
votes

Yes, you need to override __new__ special method:

class MySet(frozenset):

    def __new__(cls, *args):
        if args and isinstance (args[0], basestring):
            args = (args[0].split (),) + args[1:]
        return super (MySet, cls).__new__(cls, *args)

print MySet ('foo bar baz')

And the output is:

MySet(['baz', 'foo', 'bar'])