对象与字典:如何组织数据树?

6 投票
4 回答
1439 浏览
提问于 2025-04-16 19:50

我正在编写一个模拟程序,数据以树状结构组织。主要的对象是 World,它包含了一些方法和一个 City 对象的列表。每个 City 对象又有一些方法和一个 Population 对象的列表。而 Population 对象本身没有方法,只是用来存储一些属性。

我想问的是关于 Population 对象的,我可以选择从 object 继承或者创建成字典。哪种方式组织起来更高效呢?

以下是一些让我犹豫的情况:

保存数据
我需要能够保存和加载这个模拟程序的数据,为此我使用了 内置的 json(我希望数据是人类可读的)。因为程序是以树状结构组织的,所以在每个层级保存数据可能会比较麻烦。在这种情况下,最好将人口数据作为字典保存在 City 实例的 population 列表中。这样,保存数据只需将 City 实例的 __dict__ 传递给 Json 就可以了。

使用数据
如果我想操作人口数据,作为类实例会比作为字典更方便。不仅语法简单,而且在编码时我可以更好地享受自省功能。

性能
最后,我不太确定在资源使用上哪种方式更高效。对象和字典之间其实差别不大,因为每个对象都有一个 __dict__ 属性,可以用来访问它的所有属性。如果我用大量的 CityPopulation 对象来运行模拟,使用对象和字典哪个会占用更少的资源呢?

所以,再问一次,组织树状数据的最有效方式是什么?字典还是对象更好?或者说有没有什么秘密可以帮助组织这些数据树呢?

4 个回答

2

我觉得你可以考虑使用一个叫做 namedtuple 的东西(可以查看 Python文档,了解 collections 模块)。这样你就可以像访问普通类的属性一样,通过名字来访问 Population 对象的属性,比如用 population.attribute_name,而不是像字典那样用 population['attribute_name']。因为你在 Population 类里没有放任何方法,这样就足够了。

关于你提到的“保存数据”的需求,还有一个 _asdict 方法,它会返回一个字段名和对应值的字典,你可以把这个字典传给 json。(不过你可能需要注意一下,具体从这个方法得到的是什么,取决于你使用的 Python 版本。有些版本返回的是字典,有些返回的是 OrderedDict。这对你来说可能没什么影响。)

namedtuples 也很轻量,所以它们也符合你“运行模拟”的资源需求。不过,我想提醒你,大家也提到过,不用太担心这个,除非你在做一些复杂的数据处理,否则差别会很小。

2

正如你自己看到的,实际上这两者之间的区别不大。我的看法是,使用单独的、硬编码的属性在对象中稍微简单一些(因为不需要给名字加引号),而字典则更方便地把所有值当作一个集合来处理(比如可以直接对它们求和)。所以我会选择对象,因为人口对象的数据通常是多样的,而且相对独立。

2

为什么不使用混合的 dictobject 呢?

class Population(dict):
    def __getattr__(self, key):
        return self[key]
    def __setattr__(self, key, value):
        self[key] = value

这样你就可以通过属性(比如 foo.bar)轻松访问已知的名称,同时又能保留 dict 的功能,方便访问未知的名称,进行遍历等等,而不需要使用复杂的 getattrsetattr 语法。

如果你想在创建时总是初始化特定的字段,可以添加一个 __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)

撰写回答