提高代码可读性和颜值的几点建议(初学者必读)
学习过程中,我们经常会阅读他人写的代码,如果注意观察就会发现,好的代码本身就是一份文档,解决同样的问题,不同的人编写的代码,其可读性千差万别。
有些人的设计风格和代码风格犹如热刀切黄油,从顶层到底层的代码看下来酣畅淋漓,注释详尽又精简;深入到细节代码,无需注释也能理解清清楚楚。而有些人,代码勉勉强强能跑起来,遇到稍微复杂的情况就会出崩溃,且代码中处处都是堆积在一起的变量、函数和类,很难理清代码的实现思路。
Python 创始人 Guido van Rossum(吉多·范罗苏姆)说过,代码的阅读频率远高于编写代码的频率。毕竟是在编写代码的时候,我们自己也需要对代码进行反复阅读和调试,来确认代码能够按照期望运行。
本节,在读者学会如何使用 Puython 函数的基础上,教大家怎么才能合理分解代码,提高代码的可读性。
首先,大家在编程过程中,一定要围绕一个中心思想:不写重复性的代码。因为,重复代码往往是可以通过使用条件、循环、构造函数和类(后续章节会做详细介绍)来解决的。
例如,仔细观察下面的代码:
与此同时,还要学会刻意地减少代码的迭代层数,尽可能让 Python 代码扁平化。例如:
另外,在使用函数时,函数的粒度应该尽可能细,不要让一个函数做太多的事情。往往一个复杂的函数,我们要尽可能地把它拆分成几个功能简单的函数,然后合并起来。
如何拆分函数呢?这里,举一个二分搜索的例子。给定一个非递减整数数组,和一个 target 值,要求你找到数组中最小的一个数 x,满足 x*x > target,如果不存在,则返回 -1。
大家不妨先独立完成,写完后再对照着来看下面的代码,找出自己的问题:
对于上面这样的写法,应付算法比赛和面试已经绰绰有余。但如果从工程的角度考虑,还需要进行深度优化:
有些人的设计风格和代码风格犹如热刀切黄油,从顶层到底层的代码看下来酣畅淋漓,注释详尽又精简;深入到细节代码,无需注释也能理解清清楚楚。而有些人,代码勉勉强强能跑起来,遇到稍微复杂的情况就会出崩溃,且代码中处处都是堆积在一起的变量、函数和类,很难理清代码的实现思路。
Python 创始人 Guido van Rossum(吉多·范罗苏姆)说过,代码的阅读频率远高于编写代码的频率。毕竟是在编写代码的时候,我们自己也需要对代码进行反复阅读和调试,来确认代码能够按照期望运行。
本节,在读者学会如何使用 Puython 函数的基础上,教大家怎么才能合理分解代码,提高代码的可读性。
首先,大家在编程过程中,一定要围绕一个中心思想:不写重复性的代码。因为,重复代码往往是可以通过使用条件、循环、构造函数和类(后续章节会做详细介绍)来解决的。
例如,仔细观察下面的代码:
if i_am_rich: money = 100 send(money) else: money = 10 send(money)这段代码中,同样的 send 语句出现了两次,其实它完全可以进行合并,把代码改造成下面这样:
if i_am_rich: money = 100 else: money = 10 send(money)
与此同时,还要学会刻意地减少代码的迭代层数,尽可能让 Python 代码扁平化。例如:
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')可以看到,所有的判断语句都位于同一层级,同之前的代码格式相比,代码层次清晰了很多。
另外,在使用函数时,函数的粒度应该尽可能细,不要让一个函数做太多的事情。往往一个复杂的函数,我们要尽可能地把它拆分成几个功能简单的函数,然后合并起来。
如何拆分函数呢?这里,举一个二分搜索的例子。给定一个非递减整数数组,和一个 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))
对于上面这样的写法,应付算法比赛和面试已经绰绰有余。但如果从工程的角度考虑,还需要进行深度优化:
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))在这段代码中,我们把不同功能的代码单独提取出来作为独立的函数。其中,comp() 函数作为核心判断,提取出来之后,可以让整个程序更清晰;同时,还把二分搜索的主程序提取了出来,只负责二分搜索;最后的 solve() 函数拿到结果,决定返回不存在,还是返回值。这样一来,每个函数各司其职,阅读性也能得到一定提高。
所有教程
- C语言入门
- C语言编译器
- C语言项目案例
- 数据结构
- C++
- STL
- C++11
- socket
- GCC
- GDB
- Makefile
- OpenCV
- Qt教程
- Unity 3D
- UE4
- 游戏引擎
- Python
- Python并发编程
- TensorFlow
- Django
- NumPy
- Linux
- Shell
- Java教程
- 设计模式
- Java Swing
- Servlet
- JSP教程
- Struts2
- Maven
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Hibernate
- Mybatis
- MySQL教程
- MySQL函数
- NoSQL
- Redis
- MongoDB
- HBase
- Go语言
- C#
- MATLAB
- JavaScript
- Bootstrap
- HTML
- CSS教程
- PHP
- 汇编语言
- TCP/IP
- vi命令
- Android教程
- 区块链
- Docker
- 大数据
- 云计算