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']}
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.