Search code examples
pythonbitwise-operatorsoperator-keywordbitwise-or

combining bitwise inverse with bitwise or


Given the following class:

import operator
class Foo(object):
    def __init__(self, bah):
        self.bah = bah      

    def __invert__(self):
        return {'not': self.bah}

    def __repr__(self):
        return self.bah

    def __or__(self, other):
        return {'or': [self.bah, other]}    


x = Foo('obj1')
y = Foo('obj2')

I can do:

operator.inv(x) # ~x

which gives me:

{'not': 'obj1'}

I can do:

operator.or_(x, ~y) # x | ~y

which gives me:

{'or': ['obj1', {'not': 'obj2'}]}

But why I cannot do:

operator.or_(~x, y) # ~x | y

which throws the following error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-175-92fdd35dc3b3> in <module>
----> 1 operator.or_(~x, y)

TypeError: unsupported operand type(s) for |: 'dict' and 'Foo'

And how would I be able to output the following?

{'or': [{'not': 'obj1'}, 'obj2']}

Solution

  • You need to overload __ror__ in this case. See this post for details on how Python evaluates operators.

    Basically, this statement

    operator.__or__(~x, y)
    

    is the same as

    x.__invert__().__or__(y)
    

    Since __or__ is not defined for dict objects returned by x.__invert__(), the call fails. Defining __ror__ would make the Python interpreter try to evaluate

    y.__ror__(x.__invert__())
    

    for ~x | y after the first attempt fails.