1

I have two files, both of which define a class.

project/
    __init__.py
    thing.py
    thinglist.py

thing.py defines a class Thing, which can output lists of other Things:

# thing.py
from project.thinglist import ThingList
class Thing:
    def make_more_things(self):
        return ThingList(Thing(), Thing())

A ThingList is a list of Thing objects, which extends list with some other functions sprinkled in:

# thinglist.py
from project.thing import Thing
class ThingList(list):
    def __init__(self, *args):
        list.__init__(self, *args)
        assert all([isinstance(t, Thing) for t in self])
    def some_other_method: pass

Instantly we have a problem: a circular dependency. Thing needs ThingList in order to construct ThingLists. ThingList needs Thing in order to verify that it is made of and only of Things. But Python won't let me import Thing into thinglist.py.

To get around this, I could put both classes into the same file. But they're both pretty lengthy and for the sake of my own sanity I really don't want to do that. I could also just omit the isinstance check, but then I might be getting errors down the line that could easily be solved right now.

How can I avoid this circular dependency without combining the two files?

snazzybouche
  • 2,241
  • 3
  • 21
  • 51
  • 1
    Does importing Thing inside of the ThingList class solves this? – Ron Serruya Aug 14 '19 at 12:59
  • 1
    @RonSerruya It.... does? Importing it during \_\_init\_\_ works just fine. Python sure is a strange place - thank you so much! Add an answer and I'll mark it as solved. – snazzybouche Aug 14 '19 at 13:06

1 Answers1

1

If the only purpose of specifying the container data type is to perform tests, you can write a template-like class Container with all the logic (append, type checks) and only subclass it with Thing as container type later in thing.py.

For example, in thinglist.py you would have

class Container:

    def __init__(self):
        if not hasattr(self, 'type_ref'):
            raise NotImplementedError("Type should be set in subclass")
        self._data = []

    def append(self, elt):
        if not isinstance(elt, self.type_ref):
            raise TypeError(f'Element should be of type {self.type_ref}')
        self._data.append(elt)

    ... # rest of the logic

and in thing.py

from thinglist import Container

class ThingList(Container):
    type_ref = Thing
aripy887
  • 107
  • 1
  • 4