我不确定如何在Python中表示某个数据结构。它由组和用户组成,其中每个用户必须是一个组的成员,并且组应该又包含在容器中,组和用户将仅在此容器中使用。此外,我需要随机访问组和用户。示例数据的JSON表示如下所示:
{
"groupa": {
"name": "groupa",
"description": "bla",
"members": {
"usera": {
"name": "usera",
"age": 38
},
"userb": {
"name": "userb",
"age": 20
}
}
},
"groupb": {
"name": "groupb",
"description": "bla bla",
"members": {
"userc": {
"name": "userc",
"age": 56
}
}
}
}
简单地使用嵌套的dict似乎不合适,因为用户和组都有明确定义的属性。因为组和用户仅在容器中使用,所以我想出了一个嵌套类:
class AccountContainer:
class Group:
def __init__(self, container, group):
self.name = group
self.members = {}
self.container = container
self.container.groups[self.name] = self # add myself to container
class User:
def __init__(self, group, user, age=None):
self.name = user
self.age = age
self.group = group
self.group.members[self.name] = self # add myself to group
def __init__(self):
self.groups = {}
def add_user(self, group, username, age=None):
# possibly check if group exists
self.groups[group].members[username] = AccountContainer.User(self.groups[group], username, age=age)
def add_group(self, group):
self.groups[group] = AccountContainer.Group(self, group)
# creating
c = AccountContainer()
c.add_group("groupa")
c.add_user("groupa", "usera")
# access
c.groups["groupa"].members["usera"].age = 38
# deleting
del(c.groups["groupa"].members["usera"])
对我而言,使用方法创建组或用户,而不是指代dicts,似乎有点不自然。
答案 0 :(得分:5)
我认为,在多范式语言(如C ++或Python之类的语言中,虽然支持类不会限制您在更简单的结构中使用它们时)的大量无行为类,是一种“设计气味” “ - 设计相当于"code smell",虽然是温和的。
如果我正在对此进行代码审查,我会指出这一点,尽管让我坚持重新考虑因素并不是那么糟糕。嵌套类(没有特定的代码 - 行为原因要嵌套)使它复合:它们没有提供特定的好处,另一方面可以“阻碍”,例如,在Python中,通过干扰序列化(酸洗)。
除了优秀的旧词和完整的类之外,Python 2.6还为“结构”提供了namedtuple s的便捷替代方案,其中包含一组预定义的属性;它们似乎特别适合这种用例。
在add...
和__init__
方法中结合使用的方便“将此组/用户添加到该容器/组”功能可以重构为独立功能(访问者也是如此,即使不是一个问题 - 将内部结构隐藏到独立访问器中会让您更接近尊重Law of Demeter)。
答案 1 :(得分:2)
通常很好的做法是不让对象知道包含它们的内容。将用户传递给组,而不是将组传递给用户。仅仅因为您当前的应用程序只使用了一次“用户”,每个组一个,每个帐户一个组,并不意味着您应该使用该知识对所有类进行硬编码。如果要在其他地方重用User类,该怎么办?如果您以后需要支持多个共享用户的AccountContainer,该怎么办?
您可能会从named tuples获得一些里程,特别是对于您的用户:
User = collections.namedtuple('User', ('name', 'age'))
class Group:
def __init__(self, name, users=()):
self.name = name
self.members = dict((u.name, u) for u in users)
def add(user):
self.members[user.name] = user
等等
答案 2 :(得分:1)
使用dicts我会感到很舒服。但是我将列表中的内容作为列表而不是字典将其保持清洁并减少冗余:
[
{
"name": "groupa",
"description": "bla",
"members": [{"name": "usera", "age": 38},
{"name": "userb","age": 20}]
},
{
"name": "groupb",
"description": "bla bla",
"members": [{"name": "userc","age": 56}]
}
]
<强>更新强>:
您仍然可以通过使用随机模块来使用随机元素:
groups_list[random.randrange(len(group_list))]
答案 3 :(得分:0)
回应Alex的回答......这些嵌套的类代码闻到了我的味道。
更简单:
def Group(name=None,description=None,members=None):
if name is None:
name = "UNK!" # some reasonable default
if members is None:
members = dict()
return dict(name = ...., members = ....)
在您的原始提案中,您的对象无论如何都是美化的,并且使用对象(在此代码中)的唯一理由是获得更清晰的 init 来处理空属性。使它们成为返回实际dicts的函数几乎一样干净,也更容易。如前所述,命名元组似乎是一个更好的解决方案。
这种(嵌套的dicts方法)具有从/ dump到json构造的微不足道的好处。