一个python程序员需要掌握的知识-Python程序员鲜为人知但你应该知道的17个问题...

论坛 期权论坛     
选择匿名的用户   2021-5-22 15:30   115   0
<p>一、不要使用可变对象作为函数默认值</p>
<p>In [1]: def append_to_list(value, def_list&#61;[]):</p>
<p>...: def_list.append(value)</p>
<p>...: return def_list</p>
<p>...:</p>
<p>In [2]: my_list &#61; append_to_list(1)</p>
<p>In [3]: my_list</p>
<p>Out[3]: [1]</p>
<p>In [4]: my_other_list &#61; append_to_list(2)</p>
<p>In [5]: my_other_list</p>
<p>Out[5]: [1, 2] # 看到了吧,其实我们本来只想生成[2] 但是却把第一次运行的效果页带了进来</p>
<p>In [6]: import time</p>
<p>In [7]: def report_arg(my_default&#61;time.time()):</p>
<p>...: print(my_default)</p>
<p>...:</p>
<p>In [8]: report_arg() # 第一次执行</p>
<p>1399562371.32</p>
<p>In [9]: time.sleep(2) # 隔了2秒</p>
<p>In [10]: report_arg()</p>
<p>1399562371.32 # 时间竟然没有变</p>
<p>这2个例子说明了什么? 字典,集合,列表等等对象是不适合作为函数默认值的. 因为这个默认值实在函数建立的时候就生成了, 每次调用都是用了这个对象的”缓存”. 我在上段时间的分享python高级编程也说到了这个问题,这个是实际开发遇到的问题,好好检查你学过的代码, 也许只是问题没有暴露</p>
<p>可以这样改:</p>
<p>def append_to_list(element, to&#61;None):</p>
<p>if to is None:</p>
<p>to &#61; []</p>
<p>to.append(element)</p>
<p>return to</p>
<p>二、生成器不保留迭代过后的结果</p>
<p>In [12]: gen &#61; (i for i in range(5))</p>
<p>In [13]: 2 in gen</p>
<p>Out[13]: True</p>
<p>In [14]: 3 in gen</p>
<p>Out[14]: True</p>
<p>In [15]: 1 in gen</p>
<p>Out[15]: False # 1为什么不在gen里面了? 因为调用1-&gt;2,这个时候1已经不在迭代器里面了,被按需生成过了</p>
<p>In [20]: gen &#61; (i for i in range(5))</p>
<p>In [21]: a_list &#61; list(gen) # 可以转化成列表,当然a_tuple &#61; tuple(gen) 也可以</p>
<p>In [22]: 2 in a_list</p>
<p>Out[22]: True</p>
<p>In [23]: 3 in a_list</p>
<p>Out[23]: True</p>
<p>In [24]: 1 in a_list # 就算循环过,值还在</p>
<p>Out[24]: True</p>
<p>三、lambda在闭包中会保存局部变量</p>
<p>In [29]: my_list &#61; [lambda: i for i in range(5)]</p>
<p>In [30]: for l in my_list:</p>
<p>....: print(l())</p>
<p>....:</p>
<p>4</p>
<p>4</p>
<p>4</p>
<p>4</p>
<p>4</p>
<p>这个问题还是上面说的python高级编程中说过具体原因. 其实就是当我赋值给my_list的时候,lambda表达式就执行了i会循环,直到 i &#61;4,i会保留</p>
<p>但是可以用生成器</p>
<p>In [31]: my_gen &#61; (lambda: n for n in range(5))</p>
<p>In [32]: for l in my_gen:</p>
<p>....: print(l())</p>
<p>....:</p>
<p>0</p>
<p>1</p>
<p>2</p>
<p>3</p>
<p>4</p>
<p>也可以坚持用list:</p>
<p>In [33]: my_list &#61; [lambda x&#61;i: x for i in range(5)] # 看我给每个lambda表达式赋了默认值</p>
<p>In [34]: for l in my_list:</p>
<p>....: print(l())</p>
<p>....:</p>
<p>0</p>
<p>1</p>
<p>2</p>
<p>3</p>
<p>4</p>
<p>有点不好懂是吧,在看看python的另外一个魔法:</p>
<p>In [35]: def groupby(items, size):</p>
<p>....: return zip(*[iter(items)]*size)</p>
<p>....:</p>
<p>In [36]: groupby(range(9), 3)</p>
<p>Out[36]: [(0, 1, 2), (3, 4, 5), (6, 7, 8)]</p>
<p>一个分组的函数,看起来很不好懂,对吧? 我们来解析下这里</p>
<p>In [39]: [iter(items)]*3</p>
<p>Out[39]:</p>
<p>[,</p>
<p>,</p>
<p>] # 看到了吧, 其实就是把items变成可迭代的, 重复三回(同一个对象哦), 但是别忘了,每次都.next(), 所以起到了分组的作用</p>
<p>In [40]: [lambda x&#61;i: x for i in range(5)]</p>
<p>Out[40]:</p>
<p>[&gt;,</p>
<p>&gt;,</p>
<p>&gt;,</p>
<p>&gt;,</p>
<p>&gt;] # 看懂了吗?</p>
<p>四、在循环中修改列表项</p>
<p>In [44]: a &#61; [1, 2, 3, 4, 5]</p>
<p>In [45]: for i in a:</p>
<p>....: if not i % 2:</p>
<p>....: a.remove(i)</p>
<p>....:</p>
<p>In [46]: a</p>
<p>Out[46]: [1, 3, 5] # 没有问题</p>
<p>In [50]: b &#61; [2, 4, 5, 6]</p>
<p>In [51]: for i in b:</p>
<p>....: if not i % 2:</p>
<p>....: b.remove(i)</p>
<p>....:</p>
<p>In [52]: b</p>
<p>Out[52]: [4, 5] # 本来我想要的结果应该是去除偶数的列表</p>
<p>思考一下,为什么 �C 是因为你对列表的remove,影响了它的index</p>
<p>In [53]: b &#61; [2, 4, 5, 6]</p>
<p>In [54]: for index, item in enumerate(b):</p>
<p>....: print(index, item)</p>
<p>....: if not item % 2:</p>
<p>....: b.remove(item)</p>
<p>....:</p>
<p>(0, 2) # 这里没有问题 2被删除了</p>
<p>(1, 5) # 因为2被删除目前的列表是[4, 5, 6], 所以索引list[1]直接去找5, 忽略了4</p>
<p>(2, 6)</p>
<p>五、IndexError - 列表取值超出了他的索引数</p>
<p>In [55]: my_list &#61; [1, 2, 3, 4, 5]</p>
<p>In [56]: my_list[5] # 根本没有这个元素</p>
<p>---------------------------------------------------------------------------</p>
<p>IndexError Traceback (most recent call last)</p>
<p> in ()</p>
<p>----&gt; 1 my_list[5]</p>
<p>IndexError: list index out of range # 抛异常了</p>
<p>In [57]: my_list[5:] # 但是可以这样, 一定要注意, 用好了是trick,用错了就是坑啊</p>
<p>Out[57]: []</p>
<p>六、重用全局变量</p>
<p>In [58]: def my_func():</p>
<p>....: print(var) # 我可以先调用一个未定义的变量</p>
<p>....:</p>
<p>In [59]: var &#61; &#39;global&#39; # 后
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP