Как избежать бесконечной __eq__ рекурсии, когда член класса содержит других членов того же класса - PullRequest
0 голосов
/ 05 февраля 2020

Мне нужно сопоставить объекты с объектами и, таким образом, попытаться инкапсулировать данные объектов и список других объектов, которые соответствуют друг другу на основе определенных критериев.

Я хотел написать пользовательскую функцию dunder eq , чтобы иметь возможность сравнивать мой класс по значению, поэтому, если данные и объекты, с которыми они сопоставляются, совпадают, то два экземпляра будут равны.

Мой класс:

class Data:
    def __init__(self, value):
        self.value = value
        self.matched_to = []

    def __repr__(self):
        return "Value: {}, Matches: {}".format(self.value, self.matched_to)

    def add_match(self, other: 'Data'):
        self.matched_to.append(other)

    def __eq__(self, other: 'Data'):
        if type(self) != type(other):
            return NotImplemented

        if self.value != other.value:
            return False

        for self_match, other_match in zip(self.matched_to, other.matched_to):
            if self_match != other_match:
                return False

        return True

elem1 = Data(10)
elem2 = Data(10)
elem3 = Data(10)

elem1.add_match(elem2)
elem2.add_match(elem1)
elem3.add_match(elem1)

print(elem1 == elem2)  # False as the value are the same but not the match up
print(elem2 == elem3)  # True as the value and matches are the same

И вывод терминала:

RecursionError: maximum recursion depth exceeded while calling a Python object

Моим первым решением этой проблемы было разделение сопоставить контейнер и данные, но я столкнулся с той же проблемой, поскольку мой член класса все еще содержал бы членов одного класса.

Моя вторая идея состояла в том, чтобы сравнить сопоставленные объекты на основе их id(), как показано ниже код. Тем не менее, я чувствую, что это превосходит всю цель пользовательского равенства, и тогда я должен просто проверить id членов Data с самого начала (таким образом, не реализуя пользовательский dunder eq)

def __eq__(self, other: 'Data'):
        if type(self) != type(other):
            return NotImplemented

        if self.value != other.value:
            return False

        for self_match, other_match in zip(self.matched_to, other.matched_to):
            if id(self_match) != id(other_match):
                return False

        return True

Каким будет лучший способ решить этот мой конструктивный недостаток? Спасибо тебе!

Ответы [ 2 ]

0 голосов
/ 05 февраля 2020

Для вашего понимания ваш код похож на:

l1 = []
l2 = []
l1.append(l2)
l2.append(l1)
l1 == l2

вы получаете ту же ошибку maximum recursion depth exceeded

0 голосов
/ 05 февраля 2020

Проблема не в том, что объекты содержат объекты одного типа, а в том, что у вас есть циклов : elem1 содержит elem2, а elem2 содержит elem1, поэтому невозможно выполнить рекурсивные операции, потому что нет терминального случая к вашей рекурсии.

Не делайте циклов, если вы собираетесь рекурсировать.

...