一些当你离职后,让老板狂拍大腿的代码
1. any(** in ** for ** in **)
判断某个集合元素,是否包含某个/某些元素
代码:
if __name__ == '__main__': # 判断 list1 中是否包含某个/某些元素 list1 = [1,2,3,4] a = any(x in [5,4] for x in list1)
输出结果
2. def scaled(A, x): return [ai*x for ai in A]
列表解析
比方说,如果我们要用一个向量乘以一个标量,一般 Python 代码中,可能会这样写:
-
def scaled(A, x):
-
B = list()
-
for i in range(len(A)):
-
B.append( A[i] * x )
-
return B
你可以这样简单地写:
def scaled(A, x): return [ai*x for ai in A]
列表压缩 zip
列表压缩可将多个可迭代对象作为一个整体进行迭代,并将所有对象都转化为一个元组列表。虽然标题上写的是“列表”,但它也同样适用于元组、字典、生成器等任何可迭代的对象。
-
>>> A = [1, 2, 3]
-
>>> B = ('a', 'b', 'c')
-
>>> C = {1:'a', 2:'b', 3:'c'}
-
>>> D = xrange(123)
-
>>> zip(A, B, C, D)
-
[(1, 'a', 1, 0), (2, 'b', 2, 1), (3, 'c', 3, 2)]
同样地,你可以用一行代码实现向量加法。
def sum_of(A, B): return [ai+bi for (ai, bi) in zip(A, B)]
对于两组列表,这就能像拉链一样将数据压缩在一起。
求和函数
求和函数可以进行简单地求和操作。你可以通过累积向量元素的乘积,用一行代码实现向量点积。
def dot_of(A, B): return sum([ai*bi for (ai, bi) in zip(A, B)])
不过,有时简单的求和并不够用。比如在处理浮点数时,你可能会遇到一些恼人的小误差。为了让你更方便,Python 提供了另一个求和函数,它可以对部分求和进行操作,从而获得更精确的输出。
-
>>> [0.1]*10
-
[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
-
>>> sum([0.1]*10)
-
0.9999999999999999
-
>>> import math
-
>>> math.fsum([0.1]*10)
-
1.0
矩阵乘法
当你的矩阵表示为列表时,你可以通过一个包含点积的列表解析轻松地将矩阵与向量相乘。
def matrix_vector_of(A, X): return [dot_of(ai, X) for ai in A]
这种操作方式在投影几何中尤为重要。通过一次矩阵乘法,你可以同时实现旋转、缩放、平移、仿射和投影变换。
平面上的点投影
在计算几何中,一个平面通常由空间中的一个点和该点的法向量定义。通过这种表示法,你可以非常简单地将任意点投影到平面上。
-
def projected_on(A, Pn, Pd):
-
return sum_of(A,
-
scaled(Pn,
-
(Pd — dot_of(Pn, A)) / dot_of(Pn, Pn)))
我们不需要为此使用任何特殊语法,但请稍等,我们一会儿回头再谈。
参数中的列表乘法
接下来,来求两点之间的欧氏距离。我们需要做的就是进行向量减法,计算其自身的点积,然后对结果取平方根。
-
def distance_between(A, B):
-
return pow(dot_of( *(sum_of(A, scaled(B, -1.0)), )*2 ), 0.5)
旋转与线性求解器
求解线性方程本身就是一个重要的工程领域。从概念上来说它很简单,但你会遇到各种各样的问题,比如计算误差、不合理的执行时间、内存耗尽等,这就变得不太简单了。
我想在这里想展示的是,你可以利用 Python 的强大功能,用一行代码实现一个线性求解器。不过请记住,我并不推荐这样做,有些库在这方面做得更好。
这是一个迭代求解器,通过从一个超平面跳到另一个超平面,缓慢但稳定地接近解。不过它也可能耗尽你的堆栈,这一切都取决于具体的系统。
-
def solve(A, B, Xi):
-
return
-
Xi if distance_between(matrix_vector_of(A, Xi), B) < 1e-5
-
else
-
solve(A[1:] + [A[0]], B[1:] + [B[0]],
-
projected_on(Xi, A[0], B[0]))
这里唯一有趣的是我们在投影队列中旋转超平面时使用的列表语法。一旦你理解了它,就会发现非常简单:你只需将列表的头部切下来,使其成为一个新的列表,然后将尾部与之前的头部连接起来。
-
Rotation: step 1
-
>>> B = [1, 2, 3]
-
>>> print B[1:] + [B[0]]
-
[2, 3, 1]
-
Rotation: step 2
-
>>> B = [2, 3, 1]
-
>>> print B[1:] + [B[0]]
-
[3, 1, 2]
-
Rotation: step 3
-
>>> B = [3, 1, 2]
-
>>> print B[1:] + [B[0]]
-
[1, 2, 3]
矩阵求逆
再强调一次,这绝不是求逆矩阵的最佳方法。但它确实有效,并且只需一行代码。
我的想法是,通过求解线性方程组,将单位矩阵按单位向量逐个除以输入矩阵。线性方程组基本上就是矩阵除以向量,因为它的左边是乘法,而我们通过求解方程组得到第二个操作数。
-
def inverted(A):
-
return transpose([solve(A, ort, [0.0]*len(A))
-
for ort in identity(len(A))])