对象与字典:如何组织数据树?
我正在编写一个模拟程序,数据以树状结构组织。主要的对象是 World
,它包含了一些方法和一个 City
对象的列表。每个 City
对象又有一些方法和一个 Population
对象的列表。而 Population
对象本身没有方法,只是用来存储一些属性。
我想问的是关于 Population
对象的,我可以选择从 object
继承或者创建成字典。哪种方式组织起来更高效呢?
以下是一些让我犹豫的情况:
保存数据
我需要能够保存和加载这个模拟程序的数据,为此我使用了 内置的 json(我希望数据是人类可读的)。因为程序是以树状结构组织的,所以在每个层级保存数据可能会比较麻烦。在这种情况下,最好将人口数据作为字典保存在 City
实例的 population
列表中。这样,保存数据只需将 City
实例的 __dict__
传递给 Json 就可以了。
使用数据
如果我想操作人口数据,作为类实例会比作为字典更方便。不仅语法简单,而且在编码时我可以更好地享受自省功能。
性能
最后,我不太确定在资源使用上哪种方式更高效。对象和字典之间其实差别不大,因为每个对象都有一个 __dict__
属性,可以用来访问它的所有属性。如果我用大量的 City
和 Population
对象来运行模拟,使用对象和字典哪个会占用更少的资源呢?
所以,再问一次,组织树状数据的最有效方式是什么?字典还是对象更好?或者说有没有什么秘密可以帮助组织这些数据树呢?
4 个回答
我觉得你可以考虑使用一个叫做 namedtuple
的东西(可以查看 Python文档,了解 collections
模块)。这样你就可以像访问普通类的属性一样,通过名字来访问 Population
对象的属性,比如用 population.attribute_name
,而不是像字典那样用 population['attribute_name']
。因为你在 Population
类里没有放任何方法,这样就足够了。
关于你提到的“保存数据”的需求,还有一个 _asdict
方法,它会返回一个字段名和对应值的字典,你可以把这个字典传给 json。(不过你可能需要注意一下,具体从这个方法得到的是什么,取决于你使用的 Python 版本。有些版本返回的是字典,有些返回的是 OrderedDict
。这对你来说可能没什么影响。)
namedtuples
也很轻量,所以它们也符合你“运行模拟”的资源需求。不过,我想提醒你,大家也提到过,不用太担心这个,除非你在做一些复杂的数据处理,否则差别会很小。
正如你自己看到的,实际上这两者之间的区别不大。我的看法是,使用单独的、硬编码的属性在对象中稍微简单一些(因为不需要给名字加引号),而字典则更方便地把所有值当作一个集合来处理(比如可以直接对它们求和)。所以我会选择对象,因为人口对象的数据通常是多样的,而且相对独立。
为什么不使用混合的 dict
和 object
呢?
class Population(dict):
def __getattr__(self, key):
return self[key]
def __setattr__(self, key, value):
self[key] = value
这样你就可以通过属性(比如 foo.bar
)轻松访问已知的名称,同时又能保留 dict
的功能,方便访问未知的名称,进行遍历等等,而不需要使用复杂的 getattr
和 setattr
语法。
如果你想在创建时总是初始化特定的字段,可以添加一个 __init__
方法:
def __init__(self, starting=0, birthrate=100, imrate=10, emrate=10, deathrate=100):
self.update(n=starting, b=birthrate, i=imrate, e=emrate, d=deathrate)