How to use inherited class method and maintain the subclass

I'm working through the Building Skills in Object Oriented Design in python and am on the wheel section for roulette. We've created a "Bin" class as an extended class from frozenset which will represent each of the positions on the roulette wheel. We then create a tuple of 38 empty "Bins", and now have to create class methods to be able to add odds/outcomes to the Bins.

My problem is that I've not been able to create a method to modify the Bin in position without the result not reverting to the frozenset class.

My desired output is to have:

class Bin(frozenset):
     def add(self, other):
          ....do union of Bin class....

one = Bin(1, 2, 3)
two = Bin(4, 5)
one.add(two)
print(one)
>>> Bin(1, 2, 3, 4, 5)

Stuff I've tried

Extending the frozenset class with no methods defined/overridden

class Bin(frozenset):
     pass

one = Bin([1,2,3])
two = Bin([4,5,6])
print(one|two)
print(type(one|two))

Which returns

frozenset({1, 2, 3, 4, 5, 6})
<class 'frozenset'>   

I would have expected that by extending the class and using one of the extended methods that the output would remain as the "Bin" class.

I've also tried overriding the __ ror__ & union methods with the same result. I've tried to create a method which to brute force return the desired output. This however does not allow me to change the tuple of Bins as it doesn't operate in place

class Bin(frozenset):

def add(self, other):
    self = Bin(self|other)
    return self
one = Bin([1,2,3])
two = Bin([4,5,6])
one.add(two)
print(one)

Which returns

Bin({1, 2, 3})

Any insight into where in falling down in my thinking would and/or recommendations of stuff to read for further insight would be great.

Upvotes: 1

Views: 97

Answers (2)

DeepSpace
DeepSpace

Reputation: 81684

frozenset.__or__ (which is called by the default implementation of Bin.__or__ when 'triggered' by one | two) has no idea that frozenset was subclassed by Bin, and that it should return a Bin instance.

You should implement Bin.__or__ and force it to return a Bin instance:

class Bin(frozenset):
    def __or__(self, other):
        # be wary of infinite recursion if using | incorrectly here,
        # better to use the underlying __or__
        return Bin(super().__or__(other))

one = Bin([1, 2, 3])
two = Bin([4, 5, 6])
print(one | two)
print(type(one | two))

Outputs

Bin({1, 2, 3, 4, 5, 6})
<class '__main__.Bin'>

Upvotes: 1

Mushif Ali Nawaz
Mushif Ali Nawaz

Reputation: 3866

You need to do something like this (to avoid infinite recursion):

class Bin(frozenset):
    def __or__(self, other):
        return Bin(frozenset(self) | other)

Upvotes: 0

Related Questions