I have the situation where I have two classes (Empire and City). An empire consists of many cities, so an instance of empire has a list of cities as an attribute. The city itself has an attribute of owner which links back to the empire. At present my code looks something like this:
Empire.py
import City
class Empire:
def get_city_list(self):
return self.city_list
def add_city(self, city):
assert(isinstance(city, City.City)), "Invalid city added to empire"
self.city_list.append(city)
city.owner = self
def do_all_cities(self):
for city in self.get_city_list():
city.do_some_stuff()
City.py
class City:
def __init__(self):
self.owner = None
def get_owner(self):
return self.owner
def do_some_stuff(self):
pass
def do_some_other_stuff_that_requires_owner(self):
pass
This all works fine, provided that I always use the add_city() method or manually set the owner of a city everytime I create one. If I don't, then I would have None as the owner and do_some_other_stuff_that_requires_owner would break down. I'd like to prevent this possible source of errors by having something like
City.py
import Empire
class City:
def __init__(self, owner):
assert(isinstance(owner, Empire.Empire)), "Invalid empire as owner"
self.owner = owner
....
This makes me more comfortable that everything is of the right type (even if it is less pythonic). The problem with this is the circular import. While it does work, circular imports make me nervous and I was under the impression that they should be avoided.
What is the correct way of solving this problem? I have two separate modules that each need to check that an object is an instance of a class belonging another module.
[PS: I know getters and setters aren't very pythonic, but I'm doing this project partly to get to know OOP well and to get into some good habits]
EDIT: One possible answer has been suggested, which is various ways of having circular imports. From casual discussions, I've heard that circular imports are a sign that the code is badly structured and should be refactorised. Is this preferable? If so, how should it be done here?