Python dictionary items()系列函数的使用

源自《Python cookbook》第3版7.1节第2个例子:

[python]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. import html    # available only in Python 3.x  
  2.   
  3. def make_elements(name, value, **attrs):  
  4.     keyvals = [' %s="%s"' % item for item in attrs.items()]  
  5.     attr_str = ''.join(keyvals)  
  6.     element = '<{name}{attrs}>{value}</{name}>'.format(  
  7.             name = name,  
  8.             attrs = attr_str,  
  9.             value = html.escape(value))  
  10.     return element  
  11.   
  12. make_elements('item''Albatross', size='large', quantity=6)  
  13.   
  14. make_elements('p''<spam>')  

程序的作用很简单,就是生成HTML标签,注意html这个模块只能在Python 3.x才有。

起初我只是注意到,生成标签属性列表的keyvals这个dictionary类型变量构建的方式很有意思,两个%s对应一个item,所以就查阅了相关的资料,结果扯出了挺多的东西,在此一并总结。

注:下面所有Python解释器使用的版本,2.x 对应的是2.7.3,3.x 对应的是3.4.1

在 Python 2.x 里,官方文档里items的方法是这么说明:生成一个 (key, value) 对的list,就像下面这样:

[python]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. >>> d = {'size''large''quantity'6}  
  2. >>> d.items()  
  3. [('quantity'6), ('size''large')]  

在搜索的过程中,无意看到stackoverflow上这样一个问题:dict.items()和dict.iteritems()有什么区别? ,第一个答案大致的意思是这样的:

“起初 items() 就是返回一个像上面那样的包含dict所有元素的list,但是由于这样太浪费内存,所以后来就加入了(注:在Python 2.2开始出现的)iteritems(), iterkeys(), itervalues()这一组函数,用于返回一个 iterator 来节省内存,但是在 3.x 里items() 本身就返回这样的 iterator,所以在 3.x 里items() 的行为和 2.x 的 iteritems() 行为一致,iteritems()这一组函数就废除了。”

不过更加有意思的是,这个答案虽然被采纳,下面的评论却指出,这种说法并不准确,在 3.x 里 items() 的行为和 2.x 的 iteritems() 不一样,它实际上返回的是一个"full sequence-protocol object",这个对象能够反映出 dict 的变化,后来在 Python 2.7 里面也加入了另外一个函数 viewitems() 和 3.x 的这种行为保持一致

为了证实评论中的说法,我做了下面的测试,注意观察测试中使用的Python版本:


测试1(Python 2.7.3):

[python]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. Python 2.7.3 (default, Feb 27 201419:58:35)   
  2. [GCC 4.6.3] on linux2  
  3. Type "help""copyright""credits" or "license" for more information.  
  4. >>> d = {'size''large''quantity'6}  
  5. >>> il = d.items()  
  6. >>> it = d.iteritems()  
  7. >>> vi = d.viewitems()  
  8. >>> il  
  9. [('quantity'6), ('size''large')]  
  10. >>> it  
  11. <dictionary-itemiterator object at 0x7fe555159f18>  
  12. >>> vi  
  13. dict_items([('quantity'6), ('size''large')])  

测试2(Python 3.4.1):

[python]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. Python 3.4.1 (default, Aug 12 201416:43:01)   
  2. [GCC 4.9.0] on linux  
  3. Type "help""copyright""credits" or "license" for more information.  
  4. >>> d = {'size''large''quantity'6}  
  5. >>> il = d.items()  
  6. >>> it = d.iteritems()  
  7. Traceback (most recent call last):  
  8.   File "<stdin>", line 1in <module>  
  9. AttributeError: 'dict' object has no attribute 'iteritems'  
  10. >>> vi = d.viewitems()  
  11. Traceback (most recent call last):  
  12.   File "<stdin>", line 1in <module>  
  13. AttributeError: 'dict' object has no attribute 'viewitems'  
  14. >>> il  
  15. dict_items([('size''large'), ('quantity'6)])  

可以看到在 Python 3.x 里面,iteritems() 和 viewitems() 这两个方法都已经废除了,而 item() 得到的结果是和 2.x 里面 viewitems() 一致的。

2.x 里 iteritems() 和 viewitems() 返回的内容都是可以用 for 来遍历的,像下面这样

[python]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. >>> for k, v in it:  
  2. ...   print k, v  
  3. ...   
  4. quantity 6  
  5. size large  
  6. >>> for k, v in vi:  
  7. ...   print k, v  
  8. ...   
  9. quantity 6  
  10. size large  

这两者的区别体现在哪里呢?viewitems() 返回的是view object,它可以反映出 dictionary 的变化,比如上面的例子,假如在使用 it 和 vi 这两个变量之前,向 d 里面添加一个key-value组合,区别就很容易看出来了。

[python]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. >>> it = d.iteritems()  
  2. >>> vi = d.viewitems()  
  3. >>> d['newkey'] = 'newvalue'  
  4. >>> d  
  5. {'newkey''newvalue''quantity'6'size''large'}  
  6. >>> vi  
  7. dict_items([('newkey''newvalue'), ('quantity'6), ('size''large')])  
  8. >>> it  
  9. <dictionary-itemiterator object at 0x7f50ab898f70>  
  10. >>> for k, v in vi:  
  11. ...   print k, v  
  12. ...   
  13. newkey newvalue  
  14. quantity 6  
  15. size large  
  16. >>> for k, v in it:  
  17. ...   print k, v  
  18. ...   
  19. Traceback (most recent call last):  
  20.   File "<stdin>", line 1in <module>  
  21. RuntimeError: dictionary changed size during iteration  

在第三行中,我们像 d 里面插入了一个新的元素,vi 可以继续遍历,而且新的遍历能够反映出 d 的变化,但是在遍历 it 的时候,报错提示 dictionary 在遍历的时候大小发生了变化,遍历失败。


总结起来,在 2.x 里面,最初是 items() 这个方法,但是由于太浪费内存,所以加入了 iteritems() 方法,用于返回一个 iterator,在 3.x 里面将 items() 的行为修改成返回一个 view object,让它返回的对象同样也可以反映出原 dictionary 的变化,同时在 2.7 里面又加入了 viewitems() 向下兼容这个特性。

所以在 3.x 里面不需要再去纠结于三者的不同之处,因为只保留了一个 items() 方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值