让我们考虑一下python(3.x)脚本:
主.py:
from test.team import team
from test.user import user
if __name__ == '__main__':
u = user()
t = team()
u.setTeam(t)
t.setLeader(u)
测试/用户.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
现在,当然,我有循环进口和精彩进口。
所以,不是Python,我有三个问题。首先:
我怎样才能让这件事成功?
而且,知道有人会不可避免地说“循环导入总是表示设计问题”,第二个问题来了:
二。为什么这个设计不好?
最后,第三个:
三、还有什么更好的选择?
准确地说,如上所述的类型检查只是一个例子,还有一个基于类的索引层,它允许发现所有用户都是一个团队的成员(用户类有许多子类,因此索引加倍,对于一般用户和每个特定子类)或所有将用户作为成员的团队
编辑:
我希望更详细的例子将阐明我试图实现的目标。为了可读性而省略的文件(但是有一个300kb的源文件不知怎么的让我害怕,所以请假设每个类都在不同的文件中)
# 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]
所以,除了这个不道德的循环导入之外,它工作得很好(编写了实现细节,但并不复杂)。
坏习惯/臭味有以下几种:
my_team.leader=user_b
和user_b.team=my_team
(my_team.leader.team!=my_team)
?为了让它工作,你可以使用延迟导入。一种方法是不使用user.py,而将team.py更改为:
iii.作为替代方案,为什么不将团队和用户类放在同一个文件中?
循环进口并不是一件坏事。当
user
使用team
时,team
代码依赖user
是很自然的。这里更糟糕的做法是
from module import member
。team
模块试图在导入时获取user
类,user
模块试图获取team
类。但是team
类还不存在,因为在运行user.py
时,您仍然位于team.py
的第一行。相反,只导入模块。这将导致更清晰的名称空间,使以后的monkey补丁成为可能,并解决了导入问题。因为您只在导入时导入模块,所以您并不关心它内部的类还没有定义。等你开始使用这个课程的时候,它就可以了。
所以,test/users.py:
测试/团队.py:
如果您想少写
test
,那么teams.Team
也可以。仍然在导入一个模块,而不是一个模块成员。另外,如果
Team
和User
相对简单,则将它们放在同一个模块中。您不需要遵循Java的“每个文件一个类”习惯用法。对我来说,isinstance
测试和set
方法也会发出不符合语法的Java wart的尖叫;根据您正在做的工作,您最好使用一个简单的、非类型检查的@property
。相关问题 更多 >
编程相关推荐