Python编程能力自测


以下是在实际编程中会遇到的一些代码的示例,如果你觉得下面这些内容对你来说很难理解的话,你可能需要加强编程方面的训练

Python >= 3.6

语言基础

enumerate, zip

为了批量处理数据,in, enumeratezip在机器学习中被大量的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
X = [1, 2, 3]
Y = [4, 5, 6]
for x in X:
print(x)
# 1
# 2
# 3

# enumerate提供一个迭代用的下标
for i, x in enumerate(X):
print(f"data {i+1}: {x}") # f-string在python 3.6中出现
# data 1: 1
# data 2: 2
# data 3: 3

# zip可以将两组数据捆绑在一起使用
for x, y in zip(X, Y):
print(f"{x}+{y}={x+y}")
# 1+4=5
# 2+5=7
# 3+6=9

# enumerate与zip结合可以做一些简单有趣的事情
for i, (x, y) in enumerate(zip(X, Y)):
print(f"equation {i+1}: {x}+{y}={x+y}")
# equation 1: 1+4=5
# equation 2: 2+5=7
# equation 3: 3+6=9

递归

递归是一种非常自然的表达算法逻辑的方式

Fibonacci数列:$F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N^+)$

1
2
3
4
5
6
7
8
def fibonacci(n:int):
if n<1 or n%1 != 0:
raise(ValueError(f"n should be positive integer, instead it's {n}"))

if n==1 or n==2:
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)

类的定义

Python是面向对象的语言,因此很多时候需要把代码写成类的形式

最简单的类:

1
2
3
4
5
6
class Car:
def drive(self, speed):
print(f"driving with speed {speed} km/h")

mycar = Car() # 初始化一个Car类
mycar.drive(40) # driving with speed 40

类里面可以存储一些信息:

1
2
3
4
5
6
7
8
9
10
class Car:
def __init__(self, car_owner, *args):
super(Car, self).__init__()
self.owner = car_owner

def drive(self, speed):
print(f"driving {self.owner}'s car with speed {speed} km/h")

mycar = Car("Johnny")
mycar.drive(40) # driving Johnny's car with speed 40 km/h

工程实践

分离数据处理与显示

在做实验的过程中,经常会需要将每一步的结果显示出来;而在批量测试的时候,则并不需要将其打印处理(否则的话信息量太大)

为此一般会设定一个verbose参数(一般默认为False)

1
2
3
4
5
6
7
8
def fit(data, target, verbose=False)
for i, (x, y) in enumerate(zip(data, target)):
... # 实际的算法流程
if verbose:
# 如果为True,则打印中间结果
loss = calculate_loss()
print(f"Iteration {i}: Loss {loss}")
return model

简易函数Wrapper

当你打算实现一个操作的很多种算法时,一个实际的问题就是统一函数调用的方式,以下代码将算法的实现细节_classify_*与算法的调用方式classify分离.

scikit-learnscikit-images中大量使用了该技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 数据分类
def classify(method:str, data):
if method == "logistic":
_classify_logistic(data)
elif method == "bayes":
_classify_bayes(data)
elif method == "svm":
_classify_svm(data)
else:
raise(ValueError("unsupported classification methods" + method))

# logistic regression
def _classify_logistic(data):
raise(NotImplementedError)
# naive bayes
def _classify_bayes(data):
raise(NotImplementedError)
# 支持向量机
def _classify_svm(data):
raise(NotImplementedError)

Functor class

有很多算法是带有参数/状态的,例如:

1
2
3
4
5
6
def multiply(num ,factor):
return num * factor

factor = 3
multiply(2, factor) # 每次调用都需要指定factor
multiply(3, factor)

在实际应用中,会遇到一些情况,我们并不想每次都将factor作为参数传递到该函数中,因此我们可以
构建一个以factor为参数的函数类。

pytorchtorchvision中大量使用了该技巧;本课程不会使用该方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Multiplier:
def __init__(self, factor):
super(Multiplier, self).__init__()
self.factor = factor

def __call__(self, num):
return self.factor * num

m2 = Multiplier(2) # 创建一个每次调用都乘2的函数
m2(3) # 6
m2(4) # 8

m3 = Multiplier(3) # 创建一个每次调用都乘3的函数
m3(3) # 9
m3(4) # 12