Consideremos Python (3.x): guionespitón importaciones circulares, una vez más (también conocido como lo que está mal con este diseño)
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)
prueba/user.py:
from test.team import team
class user:
def setTeam(self, t):
if issubclass(t, team.__class__):
self.team = t
prueba/team.py:
from test.user import user
class team:
def setLeader(self, u):
if issubclass(u, user.__class__):
self.leader = u
n w, por supuesto, tengo importación circular y espléndido ImportError.
Por lo tanto, al no ser pythonista, tengo tres preguntas. En primer lugar:
i. ¿Cómo puedo hacer que esto funcione?
Y, sabiendo que alguien dirá inevitable "importaciones circulares siempre indica un problema de diseño", la segunda pregunta es:
ii. ¿Por qué este diseño es malo?
Y finalmente, el tercero:
iii. ¿Cuál sería la mejor alternativa?
Para ser precisos, el tipo de comprobación como arriba es solo un ejemplo, también hay una capa de índice basado en clase, que permite decir. encontrar todos los usuarios que son miembros de un equipo (clase de usuario tiene muchas subclases, por lo que se duplica el índice, para los usuarios en general y para cada subclase específica) o todos los equipos que tengan determinado usuario como miembro
Editar:
Espero que un ejemplo más detallado aclare lo que intento lograr. Archivos omitidos por readibility (pero tener archivo de origen uno 300kb me asusta de alguna manera, así que por favor asuma que todas las clases se encuentra en archivo diferente)
# 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}
y ahora algunos de uso:
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]
Por lo tanto, funciona muy bien (detalles de implementación omitidos, pero no hay nada complicado) además de esta cosa impía circular de importación.
Se considera una buena práctica capitalizar sus clases-- Equipo/Usuario. – snapshoe
También: echa un vistazo a [propiedades] de python (http://docs.python.org/library/functions.html#property) para la alternativa preferida para declarar setters y getters. – intuited
@intuited: YO SOY decoradores Amoroso, pero al parecer no funciona muy bien con __setattr__/__getattr__ (ejemplo anterior es bastante simplificado) –