如何提高代码可读性,再教你一招
Hello,各位小伙伴,在前面的几个章节中,我们重点讲解了Python的编程规范,其中对PEP8和Google编程规范进行了解读,其中对代码的缩进、行数、命名、注释等都有明确的规范,似乎我们按照这样的编程规范进行规范性写代码就可以了。
NO,我们还是要意识到一个关键性问题就是最早我问的那个问题,你的代码是写给谁的?很显然,肯定不仅仅是给机器去执行的,我们的代码很多的时候是为了给人看,那就需要做到让人能看懂和理解,所以才有了那些编程规范的要求,但是另一个问题是你在不同的团队或环境中写的代码是给不同的人阅读和理解的,那么此时遵守你们团队的编程规范才是王道,在符合团队或公司规范的情况下,去使用前面我们所讲解的编程规范才是正确的。
那是不是我按照团队或公司或官方指导的编程规范进行代码的编写就一定能够让人容易阅读了呢?
其实在大多数情况下已经可以了,因此编程规范非常重要,那么另外一个就是在这些基础上,让你的代码尽可能的简单、易读、逻辑清楚。那么除了遵守编程规范,还有什么办法来提高代码的可读性呢?
我的想法就是分解代码,很多情况下,我们的代码都是错中复杂,互相交织,这样即便按照一定的编程规范,也依然很难使你的代码变的具有可读性,因此本章节我们通过几个案例来看一下,如何通过合理分解代码来提高代码的可读性。
如何分解代码
首先,我们来看两个小代码段
# 第一段代码
if i_am_rich:
money = 100
send(money)
else:
money = 10
send(money)
# 第二段代码
if i_am_rich:
money = 100
else:
money = 10
send(money)
在上面的代码中,你可以看到两段代码的执行是一样的,但是第一段代码中,send调用出现了两次,因此我们把它修改变成第二段代码,我们把send合并了,而且达到了同样的效果。其实就是去除了重复代码,让代码更加易读。
作为一个程序员,那么肯定要知道编程中一个核心思想就是不写重复代码,重复代码基本都可以通过使用条件、循环、函数和类来解决。而另一个核心思想就是,减少迭代层数,尽可能让代码扁平化,让代码更加易读。我们经常在很多业务逻辑比较复杂的地方,使用大量的判断和循环。不过它可能会让你的代码失去阅读性。
再来看一个例子:
你能很好的阅读或理解这段代码吗?
def send(money):
if is_server_dead:
LOG('server dead')
return
else:
if is_server_timed_out:
LOG('server timed out')
return
else:
result = get_result_from_server()
if result == MONEY_IS_NOT_ENOUGH:
LOG('you do not have enough money')
return
else:
if result == TRANSACTION_SUCCEED:
LOG('OK')
return
else:
LOG('something wrong')
return
如果我们改造一下:
def send(money):
if is_server_dead:
LOG('server dead')
return
if is_server_timed_out:
LOG('server timed out')
return
result = get_result_from_server()
if result == MONET_IS_NOT_ENOUGH:
LOG('you do not have enough money')
return
if result == TRANSACTION_SUCCEED:
LOG('OK')
return
LOG('something wrong')
这样会不会更加的清晰呢?
你看通过对代码结构的调整,代码一下就变得更加清晰,更具有易读性。所以,我们除了遵守编程规范以外就是要有更好的程序逻辑的表达能力。具备这样的能力才能写出具备可读性的代码。
如何分解函数
接下来我们再看一个关于函数的代码:
可以自己尝试写一下哦
下面是一个简单的二分查找函数,传递一个数组/列表 arr,和一个查找目标target。要求找到数组中最小的一个数x,可以满足x*x > target。如果不存在则返回-1
def solve(arr, target):
l, r = 0, len(arr) - 1
ret = -1
while l <= r:
m = (l + r) // 2
if arr[m] * arr[m] > target:
ret = m
r = m - 1
else:
l = m + 1
if ret == -1:
return -1
else:
return arr[ret]
print(solve([1, 2, 3, 4, 5, 6], 8))
print(solve([1, 2, 3, 4, 5, 6], 9))
print(solve([1, 2, 3, 4, 5, 6], 0))
print(solve([1, 2, 3, 4, 5, 6], 40))
你看上面的代码,虽然已经实现了目标。可是在一个代码中写了判断、循环和运算,大多数人应该都会这样做,这样本身也没错。可是,我们应该让一个函数的颗粒度尽可能的细一些,不应该让一个函数处理太多的事情。所以,如果我们把这个复杂的函数进行分解,分成几个功能单一又简单的函数分别进行处理,那么应该怎么做呢?
函数分解:
我们把不同的处理代码进行了分离
- Comp作为运算的核心,只做数据的计算
- binary_search专门负责二分搜索
- solve函数负责拿到结果来判断
def comp(x, target):
return x * x > target
def binary_search(arr, target):
l, r = 0, len(arr) - 1
ret = -1
while l <= r:
m = (l + r) // 2
if comp(arr[m], target):
ret = m
r = m - 1
else:
l = m + 1
return ret
def solve(arr, target):
id = binary_search(arr, target)
if id != -1:
return arr[id]
return -1
print(solve([1, 2, 3, 4, 5, 6], 8))
print(solve([1, 2, 3, 4, 5, 6], 9))
print(solve([1, 2, 3, 4, 5, 6], 0))
print(solve([1, 2, 3, 4, 5, 6], 40))
你看,这样把一个复杂的函数分解成几个功能单一的函数,是不是就清晰了很多。
如何拆分类
最后,我们再来看一下如何拆分类。老规矩,先看代码:
class Person:
def __init__(self, name, sex, age, job_title, job_description, company_name):
self.name = name
self.sex = sex
self.age = age
self.job_title = job_title
self.job_description = description
self.company_name = company_name
你应该能看得出来,job 在其中出现了很多次,而且它们表达的是一个意义实体,这种情况下,我们可以考虑将这部分分解出来,作为单独的类。
class Person:
def __init__(self, name, sex, age, job_title, job_description, company_name):
self.name = name
self.sex = sex
self.age = age
self.job = Job(job_title, job_description, company_name)
class Job:
def __init__(self, job_title, job_description, company_name):
self.job_title = job_title
self.job_description = description
self.company_name = company_name
你看,改造后的代码,瞬间就清晰了很多。
总结
怎么样?通过上面的几个案例是不是感觉到了代码分解的重要性了呢?抓紧看看你写的代码吧,当然如果以前的可能没有很好的分解,我觉得不要因为这个原因去动,原因你知道的?
所以,希望大家通过本章的学习,能够在未来的coding中注意代码的可读性进行合理的代码分解。
如果喜欢本文或对你有帮助的话,欢迎大家关注我的公众号:后厂程序员,并分享、点赞、在看 三连哦。