分享

Python重构(二)

 F2967527 2022-07-02 发布于北京

编写干净的,Python式的代码就是要尽可能地使其易于理解,但又要简明扼要。以下是有关Python重构的系列文章的第二部分,第一部分见Python代码重构(一)

本系列的重点是为什么这样做是好的做法,而不仅仅是教你如何做。

编码的时候我们经常要创建集合。在大多数语言中,标准的做法如下:

values = []
for i in range(20):
values.append(i ** 3)

在这里我们创建一个数据集列表values,用数字迭代的填充它。在Python中,我们可以访问列表生成式。这样可以在一行上做相同的事情,消除了声明一个空列表然后赋值的麻烦:

values = [i ** 3 for i in range(20)]

我们已经将三行代码转换为一行代码,这绝对是一种胜利——这意味着在阅读方法时减少了来回滚动,并有助于保持代码的可管理性。

将代码压缩到一行可能会更难以阅读,但对于理解来说并非如此。需要的所有元素都很好地呈现出来,并且一旦习惯了这种语法,它实际上比for循环版本更具可读性。

另一点是,赋值现在更像是一个原子操作——我们在声明什么是values,而不是提供关于如何构建它的说明。这使代码读起来更像是一种叙述,因此今后我们更关注values是什么,而不是它的构造细节。

最后,列表生成式的执行通常比在循环中构建集合更快,这是另一个考虑性能的因素。

增强赋值是Python的一个简便语法,比如下面的代码

count = count + other_value

可以替换成下面的代码:

count += other_value

这样代码更短更清晰——我们不需要两次考虑count变量。其他可以使用的操作符包括-=、*=、/=和**=。需要注意的一点是,要赋值的类型必须定义适当的操作符。例如,numpy数组不支持/=操作。

在代码中经常看到给结果变量赋值,然后立即返回它。

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名没有提供任何额外的信息。

根据某些程序状态,通常需要将一个变量设置为两个不同值中的一个。

if condition:
x = 1
else:
x = 2

可以使用Python的条件表达式语法(它的三元操作符版本)将其写在一行上:

x = 1 if condition else 2

这肯定更简洁,但它是最有争议的重构之一(也包括列表推是)。一些程序员不喜欢这些表达式,并且发现解析它们比完全写出它们要稍微难一些。

我们的观点是,只要条件表达式很短,并且适合在一行中,它就是一种改进。只有一条语句定义了x,而不是必须读取两个语句加上if-else行。

一个小技巧是像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'

最后一个重构是我们希望一个方法的末尾返回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())

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多