前言
本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。
PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取
编写干净的,Python式的代码就是要尽可能地使其易于理解,但又要简明扼要。以下是有关Python重构的系列文章的第二部分,第一部分见Python代码重构(一)。
本系列的重点是为什么这样做是好的做法,而不仅仅是教你如何做。
1. 将for循环转为list/set/dictionary生成式/推导式(List Comprehensions)
编码的时候我们经常要创建集合。在大多数语言中,标准的做法如下:
values = []
for i in range(20):
values.append(i ** 3)
在这里我们创建一个数据集列表values,用数字迭代的填充它。在Python中,我们可以访问列表生成式。这样可以在一行上做相同的事情,消除了声明一个空列表然后赋值的麻烦:
values = [i ** 3 for i in range(20)]
我们已经将三行代码转换为一行代码,这绝对是一种胜利——这意味着在阅读方法时减少了来回滚动,并有助于保持代码的可管理性。
将代码压缩到一行可能会更难以阅读,但对于理解来说并非如此。需要的所有元素都很好地呈现出来,并且一旦习惯了这种语法,它实际上比for循环版本更具可读性。
另一点是,赋值现在更像是一个原子操作——我们在声明什么是values,而不是提供关于如何构建它的说明。这使代码读起来更像是一种叙述,因此今后我们更关注values是什么,而不是它的构造细节。
最后,列表生成式的执行通常比在循环中构建集合更快,这是另一个考虑性能的因素。
2. 用增强赋值替代赋值
增强赋值是Python的一个简便语法,比如下面的代码
count = count + other_value
可以替换成下面的代码:
count += other_value
这样代码更短更清晰——我们不需要两次考虑count变量。其他可以使用的操作符包括-=、=、/=和*=。需要注意的一点是,要赋值的类型必须定义适当的操作符。例如,numpy数组不支持/=操作。
3. 内联变量只使用一次
在代码中经常看到给结果变量赋值,然后立即返回它。
def method(self):
state = {
code: self.code_format,
change: self.changed_by,
}
return state
这里最好直接返回结果
def method(self):
return {
code: self.code_format,
change: self.changed_by,
}
这缩短了代码并删除了一个不必要的变量,减少了读取函数的心理负担(mental load)。
临时变量可能有用的地方是,如果它们被用作参数或条件,名称可以当做变量所代表的内容的注释。在从函数返回它的情况下,函数名告诉你结果是什么——在上面的例子中,它是状态属性,而state名没有提供任何额外的信息。
4. 用if表达式替换if语句
根据某些程序状态,通常需要将一个变量设置为两个不同值中的一个。
if condition:
x = 1
else:
x = 2
可以使用Python的条件表达式语法(它的三元操作符版本)将其写在一行上:
x = 1 if condition else 2
这肯定更简洁,但它是最有争议的重构之一(也包括列表推是)。一些程序员不喜欢这些表达式,并且发现解析它们比完全写出它们要稍微难一些。
我们的观点是,只要条件表达式很短,并且适合在一行中,它就是一种改进。只有一条语句定义了x,而不是必须读取两个语句加上if-else行。
5. 用生成器替换不必要的推导式
一个小技巧是像any、all和sum这样的函数允许传入生成器而不是集合。这意味着与其这样做:
hat_found = any([is_hat(item) for item in wardrobe])
你可以这样写:
hat_found = any(is_hat(item) for item in wardrobe)
上述代码删除了一对括号,使意图更加清晰。如果找到了hat,它将立即返回,而不必构建整个列表。这种延迟计算可以提高性能。
请注意,我们实际上是在向any()传递一个生成器,所以严格地说,代码应该是这样的:
hat_found = any((is_hat(item) for item in wardrobe))
但是Python允许忽略这对括号。接受生成器的标准库函数有:
'all', 'any', 'enumerate', 'frozenset', 'list', 'max', 'min', 'set', 'sum', 'tuple'
6. 将条件简化为返回语句
最后一个重构是我们希望一个方法的末尾返回True或False。一种常见的方法是这样的:
def function():
if isinstance(a, b) or issubclass(b, a):
return True
return False
然而,像这样直接返回结果会更简洁:
def function():
return isinstance(a, b) or issubclass(b, a)
只有当表达式的计算结果为布尔值时才能执行此操作。在这个例子中:
def any_hats():
hats = [item for item in wardrobe if is_hat(item)]
if hats or self.wearing_hat():
return True
return False
我们不能进行这种精确的重构,因为现在我们可以返回hats的列表,而不是True或False。为了确保返回的是一个布尔值,可以调用bool()来包装返回值:
def any_hats():
hats = [item for item in wardrobe if is_hat(item)]
return bool(hats or self.wearing_hat())