python3与迭代对象

今天写了个简单的脚本,调了好久才发现这个坑点。。。


python3与迭代对象

关于for的循环

使用zip与不使用zip的区别

今天写了一个脚本,发现结果总是不对,然后发现问题出在如下的位置:

1
2
3
4
5
6
7
8
class Test(object):
def __init__(self, input_num):
self.weight = [0.0 for _ in range(input_num)]

def test(self, input_num):
weight_num = 0
for i,j in input_num, self.weight:
print("i is {} and j is {}".format(i,j))

(有一点改动)
然后发现一个奇怪的事情,当我调用test的函数的时候,输出如下:

1
2
3
>>> test.test([1,2])
i is 1 and j is 2
i is 0.0 and j is 0.0

嗯嗯???

我就是懒了一下没写zip,怎么就遍历错了呢??

我原先的目的

这个原先的想法是让i遍历input_num,j遍历weight,正常的写法大概就是如下:

1
for i, j in zip(input_num, weight)

进一步理解

后来再大佬的点拨下,发现这个表达式完全可以如此理解:

1
for (i,j) in (tuple_of_input_num, tuple_of_weight)

这个写法可能不妥,大概表达的意思是i,j作为一个整体,然后依次 unpack in关键字后面的数据
然后我们再修改一下代码:

1
2
3
>>> input_num.append(5)
>>> for i,j in input_num, weight:
print("i is {} and j is {}".format(i,j))

然后发出了如下的报错:

1
ValueError: too many values to unpack (expected 2)

果然,这里是把i,j作为了一个整体来考虑数据。

ZIP的原理

zip是怎么实现同时迭代多个对象的呢?我们来看一下接下来的代码:

1
2
3
4
5
6
>>> t = zip([1,2],[3,4])
>>> i,j = t
>>> i
(1, 3)
>>> j
(2, 4)

可以看到,zip会将当前的两个可迭代对象放在两个tuple里面,也就是说,其实我们如下的代码:

1
for i,j in zip([1,2], [3,4])

等价于

1
for i,j in (1,3),(2,4)

总结

  • 记得另一位大佬好像讲过,python里面万物皆tuple,这里完全都体会到了
  • 写代码的时候记得写测试。。。

关于迭代的方式

过几天又遇到了一个奇怪的现象:

1
2
3
4
>>> tmp = [(i,j)
for i in [1,2,3]
for j in [4,5,6]
]

我理想中的输出是:

1
[(1,4),(2,5),(3,6)]

但是实际上却是:

1
[(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]

仔细思考之后,大概明白了上述的写法其实应该等价于

1
2
3
for i in [1,2,3]:
for j in [4,5,6]:
tmp.append((i,j))

emmm…感觉我对python还是了解不够啊