Рассмотрим скрипты python (3.x):
main.py:
from test.team import team
from test.user import user
if __name__ == '__main__':
u = user()
t = team()
u.setTeam(t)
t.setLeader(u)
Тест/user.py:
from test.team import team
class user:
def setTeam(self, t):
if issubclass(t, team.__class__):
self.team = t
Тест/team.py:
from test.user import user
class team:
def setLeader(self, u):
if issubclass(u, user.__class__):
self.leader = u
Теперь, конечно, у меня есть круговой импорт и великолепный ImportError.
Итак, не будучи pythonista, у меня есть три вопроса. Прежде всего:
я. Как я могу заставить эту работу работать?
И, зная, что кто-то неизбежно скажет: "Циркулярный импорт всегда указывает на проблему дизайна", возникает второй вопрос:
II. Почему этот дизайн плохой?
И наконец, третий:
III. Что было бы лучше альтернативой?
Чтобы быть точным, проверка типа, как указано выше, является лишь примером, существует также индексный слой, основанный на классе, который позволяет, например,. найти всех пользователей, являющихся членами одной команды (класс пользователя имеет много подклассов, поэтому индекс удваивается, для пользователей в целом и для каждого конкретного подкласса) или все команды, предоставившие пользователю в качестве участника
Edit:
Надеюсь, что более подробный пример прояснит, чего я пытаюсь достичь. Файлы, опущенные для чтения (но наличие одного исходного файла в 300 КБ меня как-то пугает, поэтому, пожалуйста, предположите, что каждый класс находится в другом файле)
# ENTITY
class Entity:
_id = None
_defs = {}
_data = None
def __init__(self, **kwargs):
self._id = uuid.uuid4() # for example. or randint(). or x+1.
self._data = {}.update(kwargs)
def __settattr__(self, name, value):
if name in self._defs:
if issubclass(value.__class__, self._defs[name]):
self._data[name] = value
# more stuff goes here, specially indexing dependencies, so we can
# do Index(some_class, name_of_property, some.object) to find all
# objects of some_class or its children where
# given property == some.object
else:
raise Exception('Some misleading message')
else:
self.__dict__[name] = value
def __gettattr__(self, name):
return self._data[name]
# USERS
class User(Entity):
_defs = {'team':Team}
class DPLUser(User):
_defs = {'team':DPLTeam}
class PythonUser(DPLUser)
pass
class PerlUser(DPLUser)
pass
class FunctionalUser(User):
_defs = {'team':FunctionalTeam}
class HaskellUser(FunctionalUser)
pass
class ErlangUser(FunctionalUser)
pass
# TEAMS
class Team(Entity):
_defs = {'leader':User}
class DPLTeam(Team):
_defs = {'leader':DPLUser}
class FunctionalTeam(Team):
_defs = {'leader':FunctionalUser}
и теперь некоторое использование:
t1 = FunctionalTeam()
t2 = DLPTeam()
t3 = Team()
u1 = HaskellUser()
u2 = PythonUser()
t1.leader = u1 # ok
t2.leader = u2 # ok
t1.leader = u2 # not ok, exception
t3.leader = u2 # ok
# now , index
print(Index(FunctionalTeam, 'leader', u2)) # -> [t2]
print(Index(Team, 'leader', u2)) # -> [t2,t3]
Итак, он отлично работает (детали реализации опущены, но нет ничего сложного) помимо этой нечестивой круговой импортной вещи.