对于简单的键值存储,有关dicts vs对象的Python最佳实践是什么?

时间:2012-02-04 15:44:51

标签: javascript python object dictionary associative-array

经过一段时间的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

编辑:有些回复还提到了 namedtuples 作为为不可变对象创建轻量级类的buitin方法。


所以我的问题是:

  1. 是否有关于我是否应该使用dicts或对象存储简单的无方法键值对的最佳实践?

  2. 我可以想象有很多方法可以创建小辅助类来使对象方法不那么难看(例如,在构造函数上接收dict然后覆盖__getattribute__)。这是一个好主意还是我过度思考?

    • 如果这是一件好事,那么最好的方法是什么?此外,是否有任何优秀的Python项目使用我可能从中获取灵感的方法?

4 个答案:

答案 0 :(得分:8)

不确定"已建立的最佳做法",但我所做的是:

  1. 如果值类型是同质的 - 即映射中的所有值都是数字,请使用dict。
  2. 如果值是异构的,并且映射始终具有给定的或多或少的常量键集,请使用对象。 (最好使用实际的类,因为这有点像数据类型。)
  3. 如果值是异质的,但映射中的键会发生变化,请翻转硬币。我不确定这种模式出现在Python上的频率,像这样的字典特别出现在Javascript中,以及#34;假的"函数与关键字参数。 Python已经有了这些,**kwargs是一个词典,所以我选择了dicts。
  4. 或者换句话说,用对象表示数据类型的实例。用dicts表示临时或临时映射。 Swallow不得不使用['key']语法 - 让Python感觉像Javascript一样让我感到被迫。

答案 1 :(得分:4)

好吧,如果密钥是提前知道的(实际上,甚至不是真的),你可以使用命名元组,这些元组基本上都是用你选择的字段轻松创建的对象。主要的限制是你必须在创建元组类时知道所有键,它们是不可变的(但你可以获得更新的副本)。

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

此外,您几乎可以肯定创建一个允许您动态创建属性的类。

答案 2 :(得分:4)

这是我在dictobject 之间决定存储简单,无方法键值对的方法

  1. 我是否需要迭代我的键值对?
    • 是:使用dict
    • 不:转到2。
  2. 我将拥有多少把钥匙?
    • 很多:使用dict
    • 一些:转到3。
  3. 关键名称是否重要?
    • 否:使用dict
    • 是:转到4。
  4. 我是否希望一次又一次地将这个重要的关键名称固定下来?
    • 否:使用dict
    • 是:使用object
  5. 了解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
    

答案 3 :(得分:3)

嗯,这两种方法密切相关!当你这样做

stuff.a

你真正访问

stulff.__dict__['a']

同样,您可以将dict子类化,使__getattr__返回与__getitem__相同的位置,因此stuff.a也适用于您的dict子类。

当您知道映射中的键都是有效Python标识符的简单字符串时,对象方法通常既方便又有用。如果你有更复杂的键,那么你需要一个“真正的”映射。

当您需要的不仅仅是简单的映射时,您当然也应该使用对象。这个“更多”通常是返回值的额外状态或额外计算。

您还应该考虑其他人如何使用您的stuff对象。如果他们知道这是一个简单的dict,那么他们也知道他们可以调用stuff.update(other_stuff)等。如果你给他们一个对象,那就不那么清楚了。基本上:如果您认为他们需要像普通stuff一样操纵dict的键和值,那么您应该将其设为dict

至于最“pythonic”的方式,那么我只能说我见过图书馆使用这两种方法:

  • BeautifulSoup library解析HTML并向您发送一些非常动态的对象,其中属性和项目访问都具有特殊含义。

    他们本可以选择回馈dict个对象,但是每个对象都有很多额外的状态,因此使用真正的类非常有意义。

  • 当然也有很多库只能回馈普通的dict对象 - 它们是许多Python程序的基础。