6

I have a package which contain several files. Each file contains a class and the classes are interdependant. How can I avoid circular dependencies without putting all the code in one file. Is there a better way to refactor the code or is there a way to resolve the circular imports

This is the directory structure

.
|-- Complainant.py
|-- Complaint.py
`-- __init__.py

Complaint.py:

from .Complainant import Complainant

class Complaint(BaseDocument):
    ALL_STATUS = ["waiting","resolved", "rejected"]
    text = TextField()
    timestamp = DateTimeField()
    status = TextField()
    complainant_id = TextField()
    department_ids = ListField(TextField())

    def get_complainant(self):
        db = DBManager.db()
        complainant = Complainant.load(db, self.complainant_id)
        return complainant

Complainant.py

from .Complaint import Complaint

class Complainant(BaseDocument):
    account_type = TextField()
    account_handle = TextField()
    complaint_ids = ListField(TextField())

    def get_complaints(self):
        db = DBManager.db()
        complaints = [Complaint.load(db, i) for i in self.complaint_ids]
        return complaints

init.py

from .Complaint import Complaint
from .Complainant import Complainant

__all__ = [
    Complaint,
    Complainant
]
freeza
  • 368
  • 1
  • 4
  • 13
  • You may put imports into respective class methods. – skovorodkin Oct 04 '16 at 11:11
  • You can also fix it by using `from . import module` and using qualified names (e.g. `module.Class`) rather than just the bare class name. But since these classes are so tightly coupled together, maybe they should be defined in the same module? Python isn't Java, you don't need to put every class in its own file. – Blckknght Oct 04 '16 at 11:13
  • @Blckknght But would putting everything in one file be a good design decision, as there would be a lot of code in one file – freeza Oct 04 '16 at 11:32
  • 1
    It's a matter of style. Many of the modules in the standard library are *very* long. There's certainly a middle ground between every class in its own module and everything in the whole library being in one file. I think having circular dependencies is a good sign that two classes are tightly coupled enough to be defined in the same file. – Blckknght Oct 04 '16 at 19:19

1 Answers1

5

In a system with circular dependencies, to avoid circular imports, you will generally have to put the interdependent parts in the same module.

In your case, only a fraction of the classes Complaint and Complainant are interdependent. You could refactor the modules to put the non-interdependent parts into classes in BaseComplaint.py and BaseComplainant.py, and use a third module to define the child classes Complaint and Complainant.

Directory structure:

.
|-- BaseComplainant.py
|-- BaseComplaint.py
|-- ComplaintComplainant.py
`-- __init__.py

BaseComplaint.py:

class BaseComplaint(BaseDocument):
    ALL_STATUS = ["waiting","resolved", "rejected"]
    text = TextField()
    timestamp = DateTimeField()
    status = TextField()
    complainant_id = TextField()
    department_ids = ListField(TextField())

BaseComplainant.py

class BaseComplainant(BaseDocument):
    account_type = TextField()
    account_handle = TextField()
    complaint_ids = ListField(TextField())

ComplaintComplainant.py (maybe you can find a better name)

from .BaseComplaint import BaseComplaint
from .BaseComplainant import BaseComplainant

class Complaint(BaseComplaint):
    def get_complainant(self):
        db = DBManager.db()
        complainant = Complainant.load(db, self.complainant_id)
        return complainant

class Complainant(BaseComplainant):
    def get_complaints(self):
        db = DBManager.db()
        complaints = [Complaint.load(db, i) for i in self.complaint_ids]
        return complaints

init.py

from .ComplaintComplainant import Complaint, Complainant

__all__ = [
    Complaint,
    Complainant
]
flornquake
  • 3,156
  • 1
  • 21
  • 32