关于简单键值存储,Python使用字典还是对象的最佳实践是什么?
在用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
补充:一些回答还提到命名元组,这是创建轻量级不可变对象类的一种内置方法。
所以我的问题是:
关于我应该使用字典还是对象来存储简单的、没有方法的键值对,有没有什么公认的最佳实践?
我可以想象有很多方法可以创建小的辅助类,让对象的使用看起来不那么丑陋(例如,创建一个构造函数接收字典,然后重写
__getattribute__
)。这样做是个好主意吗,还是我想太多了?- 如果这样做是好的,那最好的方法是什么?另外,有没有好的Python项目使用这种方法,我可以从中获得灵感?
4 个回答
4
好吧,如果你事先知道了所有的键(其实即使不知道也没关系),你可以使用命名元组。命名元组就是一种可以很方便创建的对象,你可以自定义它的字段。主要的限制是,你必须在创建元组类的时候就知道所有的键,而且这些键是不可变的(不过你可以得到一个更新后的副本)。
http://docs.python.org/library/collections.html#collections.namedtuple
另外,你几乎可以肯定地创建一个类,让你可以动态地创建属性。
6
这是我在选择使用 dict
还是 object
来存储简单的键值对时的思路:
- 我需要遍历我的键值对吗?
- 需要:用
dict
- 不需要:去看第2条。
- 需要:用
- 我会有多少个键?
- 很多:用
dict
- 不多:去看第3条。
- 很多:用
- 键的名称重要吗?
- 不重要:用
dict
- 重要:去看第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
我不太确定什么是“公认的最佳实践”,但我通常是这样做的:
- 如果所有的值都是同一种类型,比如说都是数字,那就用字典(dict)。
- 如果值的类型不一样,但映射的键基本上是固定的,那就用对象(object)。最好用一个真正的类,因为这看起来更像是一种数据类型。
- 如果值的类型不一样,而且映射中的键会变化,那就随便吧,掷个硬币决定。我不太确定这种情况在Python中出现的频率有多高,这种字典在JavaScript中常常用来“伪装”带有关键字参数的函数。Python本身就有这些功能,而
**kwargs
其实就是一个字典,所以我会选择用字典。
换句话说,用对象来表示数据类型的实例,用字典来表示临时的或临时的映射。接受使用['key']
这种语法——让我觉得Python像JavaScript一样有点勉强。