комбинируя побитовое обратное с побитовым или - PullRequest
0 голосов
/ 26 сентября 2019

Учитывая следующий класс:

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')

Я могу сделать:

operator.inv(x) # ~x

, что дает мне:

{'not': 'obj1'}

Я могу сделать:

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

, который дает мне:

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

Но почему я не могу сделать:

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

, который выдает следующую ошибку:

---------------------------------------------------------------------------
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'

ИКак я мог бы вывести следующее?

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

Ответы [ 3 ]

2 голосов
/ 27 сентября 2019

Вам нужно перегрузить __ror__ в этом случае.См. этот пост для получения подробной информации о том, как Python оценивает операторы.

По сути, этот оператор

operator.__or__(~x, y)

такой же, как

x.__invert__().__or__(y)

Так как__or__ не определено для dict объектов, возвращаемых x.__invert__(), вызов не удался.Определение __ror__ заставит интерпретатор Python попытаться оценить

y.__ror__(x.__invert__())

для ~x | y после неудачной первой попытки.

0 голосов
/ 27 сентября 2019

Чтобы дать другой ответ, основанный на комментариях, я должен вернуть экземпляры Foo

class Foo(object):
    def __init__(self, name):
        self.name = name      

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

    def __repr__(self):
        return str(self.name)

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

    def __and__(self, other):
        return Foo({'and': [self.name, other]})   


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

С этим я могу сделать:

>>> operator.or_(~x, y) # ~x | y
{'or': [{'not': 'obj1'}, 'obj2']}

И даже

>>> operator.or_(~x, ~y) # ~x | ~y
{'or': [{'not': 'obj1'}, {'not': 'obj2'}]}

0 голосов
/ 27 сентября 2019

Кажется, что вызов operator.or_() ищет метод __or__, определенный в указанном вами аргументе first .Вот почему в случае operator.or_(x, ~y) все работает нормально - x - это объект Foo, содержащий __or__.определение.

Во втором, operator.or_(~x, y) случае, однако, вывод ~x представляет собой словарь {'not': 'obj1'}, который не содержит определения __or__.

...