Search code examples
pythonclass-designforward-declarationmethod-resolution-order

Foward declaration of classes in Python


The following program can run successfully:

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

    def __add__(self, other):
      c = Composite()
      c._members.append(self)
      c._members.append(other)
      return c

    def __repr__(self):
      return "Simple('%s')" % self.name

class Composite(object):
    def __init__(self):
      self._members = []

    def __add__(self, obj):
      if isinstance(obj, Simple):
        out = Composite()
        out._members = [k for k in self._members] + [obj]
      elif isinstance(obj, Composite):
        out = Composite()
        out._members = [k for k in self._members + obj._members]
      else:
        raise TypeError
      return out

if __name__ == "__main__":
    s1 = Simple('one')
    s2 = Simple('two')
    s3 = Simple('three')
    c1 = s1 + s2
    c2 = c1 + s3
    print c1._members
    print c2._members
    # output:
    # [Simple('one'), Simple('two')]
    # [Simple('one'), Simple('two'), Simple('three')]

I would like to keep the definition of Simple, Composite, and __main__ in three different files, but I cannot do it because I cannot import Simple into composite.py and I cannot import Composite into simple.py.

How would you modify the class definition such that you can keep separate files?

Thank you.

PS. I've read several answers related to "forward declaration" but could not find an answer to my specific problem.


Solution

  • Since none of the references are needed until the methods are called, circular imports can work here. The trick is to use fully-qualified references.

    import composite
    
    class Simple(object):
       ...
      def __add__(self, other):
        c = composite.Composite()
        c._members.append(self)
        c._members.append(other)
        return c