由买买提看人间百态

boards

本页内容为未名空间相应帖子的节选和存档,一周内的贴子最多显示50字,超过一周显示500字 访问原贴
Programming版 - 转一篇范文
相关主题
如何用python web.py web service 做 multiple parameters 的 call?StringBuffer
python 的 timeit 问题有没有好的 bootstrap 工具推荐
go 怎么 disable这个replace document body,but js does not run
Dynamic buffer management questionLinux下incrementally地读一个正在被写的file
问个java String问题骂架骂的最有水平的是blaze大侠.
windows下输入流转向求助go为什么没有arraylist?
[合集] What does this mean in C++Go is a pooly designed language
how to assign object rather and 'reference' to a python list?一个system design题:content feed
相关话题的讨论汇总
话题: timeit话题: __话题: out话题: import话题: dtol2
进入Programming版参与讨论
1 (共1页)
j********x
发帖数: 2330
1
我们来比较一下三种写法,我来阐述一下为什么 A最好,C最烂。
A. 初始化成[]然后“笨拙地”逐个append/extend
B. list(chain(*d.iteritems()))
C. list(sum(d.items(),()))


首先,跟 B 和 C 这样的 one liner 相比,A 这种看起来最“笨拙”、
似乎不怎么 "idiomatic" 的写法,实际上理解起来最容易,
几乎没有什么沟通成本和心智负担。

当然 itertools.chain 也是比较直观的,心智负担也不大。

而 sum(d.items(),()) 的问题,首先在于你要意识到 sum 函数第二个参数的存在,
而且这个参数的默认值是整数0,而不是 None, '', (), [], {} 或 set()。
这给大多数阅读代码的人带来了心智负担,降低了理解速度。


其次,我们来看看执行效率。

下面 benchmark 结果显示,在原 dict 稍大时,
裸写 []-extend 最快,chain 稍次之,sum 则完全不能忍受
——因为累加过程中无谓地生成了很多临时tuples,
跟众所周知的 字符串累加慢如蜗牛 一个道理。

In [22]: d = {i:str(i) for i in range(10000)}
...:
...: from itertools import chain
...: from timeit import timeit
...:

In [23]: def dtol1(d):
...: l = []
...: for k,v in d.iteritems():
...: l.append(k)
...: l.append(v)
...: return l
...: timeit('dtol1(d)', number=1000, setup='from __main__ import d,
dtol1')
...:
Out[23]: 3.0787

In [24]: def dtol2(d):
...: l = []
...: for kv in d.iteritems():
...: l.extend(kv)
...: return l
...: timeit('dtol2(d)', number=1000, setup='from __main__ import d,
dtol2')
...:
Out[24]: 1.8849 (Best)

In [25]: def dtol3(d):
...: return list(chain(*((k,v) for k,v in d.iteritems())))
...: timeit('dtol3(d)', number=1000, setup='from __main__ import d,
dtol3')
...:
Out[25]: 3.2725

In [26]: def dtol4(d):
...: return list(chain(*d.iteritems()))
...: timeit('dtol4(d)', number=1000, setup='from __main__ import d,
dtol4')
...:
Out[26]: 2.2957

In [27]: def dtol5(d):
...: return list(sum(d.iteritems(),()))
...: timeit('dtol5(d)', number=1000, setup='from __main__ import d,
dtol5')
...:
Out[27]: 479.147 (OMFG!)

In [28]: def dtol5a(d):
...: return list(sum(d.items(),()))
...: timeit('dtol5a(d)', number=1000, setup='from __main__ import d,
dtol5a')
...:
Out[28]: 477.200 (OMFG!)


再次,如果只需要得到 iterator,也是这种“笨拙”写法最容易修改成 generator 版
本,
利用 lazy evaluation 得到最高的效率。

In [29]: def dtol4_it(d):
...: return chain(*d.iteritems())
...: timeit('dtol4_it(d)', number=1000, setup='from __main__ import d,
dtol4_it')
...:
Out[29]: 0.9271

In [30]: def dtol5_it(d):
...: return iter(sum(d.iteritems(),()))
...: timeit('dtol5_it(d)', number=1000, setup='from __main__ import d,
dtol5_it')
...:
Out[30]: 479.2705 (OMFG!)

In [31]: def dtol2_it(d):
...: for k, v in d.iteritems():
...: yield k
...: yield v
...: timeit('dtol2_it(d)', number=1000, setup='from __main__ import d,
dtol2_it')
...:
Out[31]: 0.002788 (Best.)
(当然这里 dtol2_it 这个 generator 所返回的 iterator 的 .next() 方法
还没有开始执行,也就是说字典 d 还没有开始被遍历。)


综上,跟 one liner 相比,[]-extend/append 这种看似笨拙的写法
心智负担最小、执行效率最高、扩展/修改起来最灵活,正所谓大巧不工,
在我看来,至少在这个场景下,是所谓最 "pythonic" 的写法。


更进一步(不是特指这个例子,只是借题发挥一下,有 over-generalization 之嫌)

我隐约觉得在不少 Python 程序员中弥漫着一种 一味追求代码短小 的风气,
认为 代码写得短就是"Pythonic"。对此我保留意见。
m**k
发帖数: 290
2
这个也算是特例吧。以一个例子来得出任何结论都太草率。
只能说写的短不一定效率好。大部分情况 list/dict compresion 效率高。

【在 j********x 的大作中提到】
: 我们来比较一下三种写法,我来阐述一下为什么 A最好,C最烂。
: A. 初始化成[]然后“笨拙地”逐个append/extend
: B. list(chain(*d.iteritems()))
: C. list(sum(d.items(),()))
:
:
: 首先,跟 B 和 C 这样的 one liner 相比,A 这种看起来最“笨拙”、
: 似乎不怎么 "idiomatic" 的写法,实际上理解起来最容易,
: 几乎没有什么沟通成本和心智负担。
:

n**s
发帖数: 2230
3
靠,这就是码农写的论文了。拿到学术界,让人笑掉大牙
1 (共1页)
进入Programming版参与讨论
相关主题
一个system design题:content feed问个java String问题
coding就是行为艺术--Try Julia (2)windows下输入流转向求助
pandas 作者:Apache Arrow and the "10 Things I Hate About pandas"[合集] What does this mean in C++
狗家又open source一个底层C++ libraryhow to assign object rather and 'reference' to a python list?
如何用python web.py web service 做 multiple parameters 的 call?StringBuffer
python 的 timeit 问题有没有好的 bootstrap 工具推荐
go 怎么 disable这个replace document body,but js does not run
Dynamic buffer management questionLinux下incrementally地读一个正在被写的file
相关话题的讨论汇总
话题: timeit话题: __话题: out话题: import话题: dtol2