Цикл в функциях, вызывающих друг друга - PullRequest
0 голосов
/ 01 ноября 2019

У меня есть класс, который представляет человека в семье (FamilyMember).

Я реализовал функцию setParent, которая получает объект FamilyMember и добавляет его в список parent текущего объекта. ,Точно то же самое делается в функции setChild.

Проблема : когда одна функция вызывает другую (если мы устанавливаем родителя нашего текущего объекта, мы должны также установить текущийОбъект, как родительский ребенок), они входят в цикл. => Мне удалось остановить его, проверяя, был ли объект уже в списке. Но это означает, что я всегда выполняю ненужный вызов функции.

    def setParent(self, parent):
        if not isinstance(parent, FamilyMember):
            raise TypeError("Parent must be set to a FamilyMember")
        if parent in self.parents:
            print("parent already in the list")
            return
        self.parents.append(parent) 
        parent.setChild(self)


    def setChild(self, child):

        if not isinstance(child, FamilyMember):
            raise TypeError("child must be set to a FamilyMember")
        if child in self.children:
            print("child already in the list")
            return
        self.children.append(child) 
        child.setParent(self)

Возможное решение, которое мне не нравится : я мог бы сделать еще 2 функции, которые делают то же самое, но не делаютвызовите другую функцию. Но это означает повторение кода и наличие 4 различных функций, что не является хорошей практикой. пример:

    def setParent_no_loop(self, parent):
        if not isinstance(parent, FamilyMember):
            raise TypeError("Parent must be set to a FamilyMember")
        if parent in self.parents:
            print("parent already in the list")
            return
        self.parents.append(parent) 

    def setChild(self, child):
        if not isinstance(child, FamilyMember):
            raise TypeError("child must be set to a FamilyMember")
        if child in self.children:
            print("child already in the list")
            return
        self.children.append(child) 
        self.setParent_no_loop(self)

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

    def setParent_no_loop(self, parent):
        if not isinstance(parent, FamilyMember):
            raise TypeError("Parent must be set to a FamilyMember")
        if parent in self.parents:
            print("parent already in the list")
            return
        self.parents.append(parent)
        parent.children.append(self) 

Вопрос в том, можете ли вы найти элегантный способ решения этой проблемы?

Ответы [ 3 ]

1 голос
/ 01 ноября 2019

Я бы предложил разработать методы следующим образом:

def add_child(self, child):
    self.children.append(child)
    child.parents.append(self)

def add_parent(self, parent):
    parent.add_child(self)

Нет необходимости, чтобы эти методы были рекурсивными или взаимно-рекурсивными. При необходимости добавьте свой собственный код обработки ошибок.

0 голосов
/ 01 ноября 2019

Создайте parents и children наборы вместо списков.

Тогда в каждом методе просто добавляйте и не беспокойтесь об этом.

def setParent(self, parent):
    if not isinstance(parent, FamilyMember):
        raise TypeError("Parent must be set to a FamilyMember")
    self.parents.add(parent) 
    parent.children.add(self)


def setChild(self, child):
    if not isinstance(child, FamilyMember):
        raise TypeError("child must be set to a FamilyMember")
    self.children.add(child) 
    child.parents.add(self)
0 голосов
/ 01 ноября 2019

Вы можете хешировать объекты и проверять, существуют ли они в другом, с помощью сравнения хешей в начале функции set? Я сделал это ниже (потому что это безопаснее, если пользователь сначала забудет сделать сравнение), но вы также можете сделать это перед вызовом функции set, чтобы избежать вызова дополнительной функции.

class FamilyMember(object):
    def __init__(self):
        self.relations = set()
        self.hashval = hash(self)
        self.parents = set()
        self.children = set()

    def knowsAbout(self, otherhash):
        if otherhash in self.relations:
            return True
        else:
            return False

    def setParent(self, newParent):
        if not self.knowsAbout(newParent):
            self.relations.add(newParent.hashval)
            self.parents.add(newParent)
            newParent.addChild(self)

    def setChild(self, newChild):
        if not self.knowsAbout(newChild):
            self.relations.add(newChild.hashval)
            self.children.add(newChild)
            newChild.addParent(self)

Это все еще дополнительный вызов функции, но сравнение хешей, по крайней мере, быстрое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...