Круговая зависимость Python с включением функций-членов - PullRequest
0 голосов
/ 08 мая 2019

Проблема здесь возникает, когда я пытаюсь включить существующую функцию в класс как функцию-член. У меня есть настройки, подобные этой:

Классы:

base(object)
    primitive(base)
        square(primitive)
        union(primitive)

У меня есть функция с именем union, которую пользователь вызывает, которая возвращает union примитивный объект.

obj1 = square()
obj2 = square()
obj3 = union(obj1, obj2) #this is the union function which returns a union primitive

Я хочу, чтобы пользователь тоже мог это сделать

obj3 = obj1.union(obj2)

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

EDIT:

Для ясности, как структурирован код:

операций / union.py (функция)

from objects import union as _union #the union class
def union(obj1, obj2): #the union function
    #CODE
    return _union(args)

objects / union.py (класс)

from objects import primitive
class union(primitive):
    #CODE

объекты / primitive.py

from operations import union #the function
class primitive(base):
    #CODE
    def union(self, obj2):
        return union(self, obj2)

Существует класс с именем union, который является объектом, который содержит информацию об объединенных входных объектах. Пользователь не взаимодействует с этим. Затем есть функция union, которую пользователь может вызвать, которая возвращает объект union. Я хочу, чтобы класс primitive содержал функцию-член под названием union, которая использует функцию union, которую я уже написал. Проблема в том, что функция union возвращает объект union, который наследуется от класса primitive. Это вызывает проблему круговой зависимости. Я могу удалить функцию-член union, но тогда пользователь не сможет сделать это

obj3 = obj1.union(obj2)

Ответы [ 2 ]

1 голос
/ 08 мая 2019

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

from objects.primitive import Primitive
class Union(Primitive):
    @classmethod
    def union(cls, a, b):
        return Union(a, b)

Но primitive требует только Union в одном методе, а не создавать что-либо в области видимости модуля, поэтому все, что вам нужно, - это чтобы импортированный модуль существовал к моменту вызова метода. Это означает, что вы можете сделать это:

class Primitive(Base):
    #CODE
    def union(self, obj2):
        return union.Union.union(self, obj2)

from objects import union

Причина, по которой необходимо завершить импорт, заключается в том, чтобы убедиться, что он работает независимо от того, какой модуль импортируется первым. Если вы импортируете objects.union, он будет правильно импортировать objects.primitive, прежде чем попадет в тело модуля. Если вы сначала импортируете objects.primitive, он попытается импортировать objects.union, для чего требуется, чтобы класс Primitive уже существовал. Отсюда импорт после тела класса.

Я рекомендую сделать union @classmethod из Union, чтобы вы могли правильно использовать его в качестве альтернативного конструктора. Кроме того, использование соглашения Python о написании имен классов в CamelCase делает наименование намного менее запутанным.

1 голос
/ 08 мая 2019

Звучит так, как будто вы сами создали много проблем, определив primitive и square в отдельных модулях / файлах.Если вы определили их в одном модуле, я сомневаюсь, что у вас возникнут какие-либо проблемы.Например, следующее работает нормально:

class Primitive:
    pass

class Square(Primitive):
    def union(self, other):
        return Union(self, other)

class Union(Primitive):
    def __init__(self, *members):
        self.members = members

obj1 = Square()
obj2 = Square()
obj3 = obj1.union(obj2)

print(type(obj3))
print(obj3.members)

Если вы настаиваете на том, чтобы поместить ваши классы в разные файлы, вы можете сделать что-то вроде этого:

primitive.py:

    class Primitive:
        pass

square.py:

    from .primitive import Primitive

    class Square(Primitive):
        def union(self, other):
            from .union import Union
            return Union(self, other)

union.py:

    from .primitive import Primitive

    class Union(Primitive):
        def __init__(self, *members):
            self.members = members

test.py:

    from .square import Square

    obj1 = Square()
    obj2 = Square()
    obj3 = obj1.union(obj2)

    print(type(obj3))
    print(obj3.members)

Ключевой моментперемещение оператора from .union import Union внутри метода union(), где он не будет вызываться до тех пор, пока он не понадобится.

Вот хороший хороший ресурс о круговом импорте Python.

...