关于简单键值存储,Python使用字典还是对象的最佳实践是什么?

6 投票
4 回答
3992 浏览
提问于 2025-04-17 12:19

在用Javascript编程一段时间后,我对对象和关联数组(字典)之间的关系产生了一些兴趣:

//Javascript
var stuff = { a: 17, b: 42 };

stuff.a;    //direct access    (good sugar for basic use)
stuff['a']; //key based access (good for flexibility and for foreach loops)

在Python中,基本上有两种方式可以做到这一点(就我所知)

字典:

stuff = { 'a': 17, 'b':42 };

# no direct access :(
stuff['a'] #key based access

或者对象:

#use a dummy class since instantiating object does not let me set things
class O(object):
    pass

stuff = O()
stuff.a = 17
stuff.a = 42

stuff.a #direct access :)
getattr(stuff, 'a') #key based access

补充:一些回答还提到命名元组,这是创建轻量级不可变对象类的一种内置方法。


所以我的问题是:

  1. 关于我应该使用字典还是对象来存储简单的、没有方法的键值对,有没有什么公认的最佳实践?

  2. 我可以想象有很多方法可以创建小的辅助类,让对象的使用看起来不那么丑陋(例如,创建一个构造函数接收字典,然后重写__getattribute__)。这样做是个好主意吗,还是我想太多了?

    • 如果这样做是好的,那最好的方法是什么?另外,有没有好的Python项目使用这种方法,我可以从中获得灵感?

4 个回答

4

好吧,如果你事先知道了所有的键(其实即使不知道也没关系),你可以使用命名元组。命名元组就是一种可以很方便创建的对象,你可以自定义它的字段。主要的限制是,你必须在创建元组类的时候就知道所有的键,而且这些键是不可变的(不过你可以得到一个更新后的副本)。

http://docs.python.org/library/collections.html#collections.namedtuple

另外,你几乎可以肯定地创建一个类,让你可以动态地创建属性。

6

这是我在选择使用 dict 还是 object 来存储简单的键值对时的思路:

  1. 我需要遍历我的键值对吗?
    • 需要:用 dict
    • 不需要:去看第2条。
  2. 我会有多少个键?
    • 很多:用 dict
    • 不多:去看第3条。
  3. 键的名称重要吗?
    • 不重要:用 dict
    • 重要:去看第4条。
  4. 我想要把这些重要的键名称固定下来吗?
    • 不想:用 dict
    • 想要:用 object

看看 dis 展示的区别也很有意思:

>>> def dictf(d):
...     d['apple'] = 'red'
...     return d['apple']
... 
>>> def objf(ob):
...     ob.apple = 'red'
...     return ob.apple
... 
>>> dis.dis(dictf)
  2           0 LOAD_CONST               1 ('red') 
              3 LOAD_FAST                0 (d) 
              6 LOAD_CONST               2 ('apple') 
              9 STORE_SUBSCR         

  3          10 LOAD_FAST                0 (d) 
             13 LOAD_CONST               2 ('apple') 
             16 BINARY_SUBSCR        
             17 RETURN_VALUE         
>>> dis.dis(objf)
  2           0 LOAD_CONST               1 ('red') 
              3 LOAD_FAST                0 (ob) 
              6 STORE_ATTR               0 (apple) 

  3           9 LOAD_FAST                0 (ob) 
             12 LOAD_ATTR                0 (apple) 
             15 RETURN_VALUE
9

我不太确定什么是“公认的最佳实践”,但我通常是这样做的:

  1. 如果所有的值都是同一种类型,比如说都是数字,那就用字典(dict)。
  2. 如果值的类型不一样,但映射的键基本上是固定的,那就用对象(object)。最好用一个真正的类,因为这看起来更像是一种数据类型。
  3. 如果值的类型不一样,而且映射中的键会变化,那就随便吧,掷个硬币决定。我不太确定这种情况在Python中出现的频率有多高,这种字典在JavaScript中常常用来“伪装”带有关键字参数的函数。Python本身就有这些功能,而**kwargs其实就是一个字典,所以我会选择用字典。

换句话说,用对象来表示数据类型的实例,用字典来表示临时的或临时的映射。接受使用['key']这种语法——让我觉得Python像JavaScript一样有点勉强。

撰写回答