前言
本文记录了我在python编程中遇到的各种小问题,持续更新。
1. x = x + 1 VS x += 1
辨析下面这两段代码:
>>> x = y = [1, 2, 3, 4]
>>> x += [4]
>>> x
[1, 2, 3, 4, 4]
>>> y
[1, 2, 3, 4, 4]
>>> x = y = [1, 2, 3, 4]
>>> x = x + [4]
>>> x
[1, 2, 3, 4, 4]
>>> y
[1, 2, 3, 4]
1)‘+=’ 调用 in-place 的加法,即 iadd 方法。 此方法采用两个参数,但是原地进行更改,修改了第一个参数的内容(即x被修改)。 由于x和y都指向相同的Pyobject,因此它们都是相同的。
2)x = x + [4] 调用 add 方法,相当于 x.add([4]),并没有原地进行更改或添加值,它会创建一个新列表[1, 2, 3, 4, 4],该列表指向了x,而y仍指向旧列表[1, 2, 3, 4],因此它们不相同。
2. np.matmul(@) VS np.dot VS np.multiply(*)
np.matmul(a, b)是矩阵乘法,运算符重载为@;np.dot(a, b)是点积;np.multiply(a, b)是逐元素乘法,运算符重载为*
关于三者的辨析,直接上结论:
1)如果a或者b有一个是标量,用np.multiply()或者*,np.dot()可以但不推荐,np.matmul()不可以;
2)如果a、b是向量,则使用np.dot()向量内积;
3)如果a、b是二维array(矩阵),则使用np.matmul()矩阵乘法;
4)a、b是二维及以下array的情况下,np.matmul()与np.dot()效果相同;
5)a、b是大于二维array的情况下,如下例:
a = np.array([i for i in range(120)]).reshape([2,3,4,5])
b = np.array([i for i in range(120)]).reshape([2,3,5,4])
>>> np.matmul(a,b).shape
(2, 3, 4, 4)>>> np.dot(a,b).shape
(2, 3, 4, 2, 3, 4)>>> np.matmul(b,a).shape
(2, 3, 5, 5)>>> np.dot(a,b).shape
(2, 3, 5, 2, 3, 5)
重点是观察结果的维度不同,np.matmul(a,b)的维度为(2, 3, 4, 4),np.dot(a,b)的维度为(2, 3, 4, 2, 3, 4),这是因为np.matmul()遵循了矩阵乘法的维度规则(n,k),(k,m)->(n,m),a的最后一个维度5和b的倒数第二个维度5消掉。
具体的运算,用一个简单点的例子说明:
a = np.array([i for i in range(12)]).reshape([2,2,3])
b = np.array([i for i in range(12)]).reshape([2,3,2])
"""
a
[[[ 0 1 2][ 3 4 5]][[ 6 7 8][ 9 10 11]]]
b
[[[ 0 1][ 2 3][ 4 5]][[ 6 7][ 8 9][10 11]]]
""">>> np.matmul(a,b)
array([[[ 10, 13],[ 28, 40]],[[172, 193],[244, 274]]])>>> np.dot(a,b)
array([[[[ 10, 13],[ 28, 31]],[[ 28, 40],[100, 112]]],[[[ 46, 67],[172, 193]],[[ 64, 94],[244, 274]]]])
3. “==” VS “is”
在python中,双等号 ==
和 is
好像都是用于判断两个东西是否相等,但实际上两者是不一样的。
==
是用于判断值(value)相等,即判断两个对象是否具有相同的值。
is
是用于判断参考(reference)相等,即判断两个引用是否引用同一个对象。
实际上,以下两条语句是等价的:
a is b
id(a) == id(b)
id() 函数可以理解为一种哈希函数,用来唯一标识python中的不可变类型。