马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 鱼C-小师妹 于 2021-10-20 20:25 编辑
在线视频:
小讲堂更新到现在,距离几个新手总会踩的“坑”(上)|【辛 酸 血 泪】已经过去了几千行代码的时间~
哈哈哈哈哈,这么说是暗示你们都有认真完成每一讲的课后练习~
为什么迟迟没更呢?
原因很简单,让有“共性的问题”飞一会儿!
此刻时机已到,凝结成本文。
因为学到现在,很多童鞋不会再踩(上)中那样显而易见的“浅”坑。
会因为懂得还不够多,不够全面,而踩一些效率低下的坑~
这次我们就不在黑板上写代码咯·~
主要和大家分享一些心得,涉及到的代码不是重点,那些形而上的概念才重要哦!
废话不读说啦,开始吧~
1、优化原则
经常在每一讲的练习中,都会介绍给大家多种优化代码的方法。
这次来好好总结下优化代码的 3 大原则:
咱们一个一个的来说。
原则一·:过早优化
很多童鞋一开始上手写代码就奔着性能优化的目标,对于老鸟这无可厚非~
但是对于新手如果这么要求自己,就会感到步步维艰,因为你不敢先让程序“先跑去来”。
没有跑起来就不知道哪里是重点,就会陷入到某个点中。俗话说得好:
因此,优化的前提是代码能正常工作。
过早地进行优化可能会忽视对总体性能指标的把握,在得到全局结果前不要主次颠倒。
原则二:权衡代价
对于已经上手编程的童鞋,应该都已经学会“权衡代价”了,如果还不会,说明犯过的错还不够~
世间做任何事情,都会有代价的,就像你此时此刻看了本视频,当下就无法看其他的一样~
要知道想解决所有性能的问题是几乎不可能的!
通常面临的选择无非就是时间换空间或空间换时间。
开发成本一定要考虑到,不能为了优化一行代码,让其他维护他的人都不知所云。
原则三:集中火力
不要优化那些无关紧要的部分。
如果对代码的每一部分都去优化,这些修改会使代码难以阅读和理解。
如果你的代码运行速度很慢,首先要找到代码运行慢的位置,通常是内部循环,专注于运行慢的地方进行优化。
在其他地方,一点时间上的损失没有什么影响。
2、慎用全局变量
不管是使用哪门编程语言的新手,都会有一个不好的小习惯,我先不公布答案。
看看你能从下面这段代码中找到答案吗:
import math
size = 99999
for x in range(size):
for y in range(size):
z = math.sqrt(x) + math.sqrt(y)
发现了吧,没错就是:
究其原因其实很简单:
只要你看过小师妹之前分享的调试教程,真的会发现让编译器来帮你查值才最靠谱。
由于全局变量和局部变量实现方式不同,定义在全局范围内的代码运行速度会比定义在函数中的慢不少。
通过将脚本语句放入到函数中,通常可带来 15% - 30% 的速度提升哦!
所以上面代码更好的写法是将 size 写到函数中:
定义到函数中后就可以减少全部变量使用~
3、无意义的数据复制
这里的复制不是指那种把函数复制过直接用。
而是指数据层面的复制,来看下面的代码,找问题:
def main():
size = 99999
for f in range(size):
value = range(size)
value_list = [x for x in value]
square_list = [x * x for x in value_list]
main()
这里的 value_list,其实完全没有必要~
因为会创建不必要的数据结构或复制,直接这么写就好:
for f in range(size):
value = range(size)
square_list = [x * x for x in value]
main()
另外也不要滥用 copy.deepcopy() 之类的函数。
通常在这些代码中是可以去掉复制操作的。
4、拼接字符串用 join
小甲鱼老师在最新版 Python 中讲解字符串的使用,强调过:
很重要,但是有多少人还在图方便用 “+”呢:
result = ''
fori in string_list:
result += i
return result
当使用 a + b 拼接字符串时,由于 Python 中字符串是不可变对象。
其会申请一块内存空间,将a和b分别复制到该新申请的内存空间中。
因此,如果要拼接 n 个字符串,会产生 n-1 个中间结果,每产生一个中间结果都需要申请和复制一次内存!
这肯定会严重影响运行效率滴。
而使用 join() 拼接字符串时,会首先计算出需要申请的总的内存空间,然后一次性地申请所需内存,并将每个字符串元素复制到该内存中去。
所以看完今天这一讲,请用 join 来拼接字符串,就像酱紫:
return ''.join(string_list)
是不是干净又好用呢?!
5、用 if 的短路特性
if 条件的短路特性是指对 if a and b 这样的语句, 当 a 为 False 时将直接返回,不再计算 b:
对于 if a or b 这样的语句,当 a 为 True 时将直接返回,不再计算 b。
上面就是短路逻辑的核心玩法,基于此还可以将多个 and 或 or 混用在一起。
表达式从左至右运算,若 or 的左侧逻辑值为 True ,则短路 or 后所有的表达式(不管是 and 还是 or),直接输出 or 左侧表达式 。
表达式从左至右运算,若 and 的左侧逻辑值为 False ,则短路其后所有 and 表达式,直到有 or 出现,输出 and 左侧表达式到 or 的左侧,参与接下来的逻辑运算。
若 or 的左侧为 False ,或者 and 的左侧为 True 则不能使用短路逻辑。
因此, 为了节约运行时间,对于 or 语句,应该将值为 True 可能性比较高的变量写在 or 前,而 and 应该推后。
说了这么多,我们用个月考程序来举例说明~
让鱼油输入两次月考的成绩和期末考试成绩。
月考只要其中一次及格(大于 60 分),期末考必须及格,这样学期成绩才算及格,及格就输出“合格”,否则输出"失败"。
就可以写成这样:
看输出:
代码很精简是不是,短路掉的部分,就是提升效率的所在。
6、循环的优化
天底下应该没有不用循环的程序员吧。
而选择哪些循环是有效率高低之别的,这几个点不理解的话就先记住:
- 用 for 循环代替 while 循环
- 使用隐式 for 循环代替显式 for 循环
- 减少内层 for 循环的计算
我们一个一个来说~
在 Python 底层中 for 循环是比 while 循环效率高滴。
像这种最常用的 while 循环:
while i < size:
sum += 1
i++
return sum
就可以写成:
for i in range(size):
sum += 1
return sum
针对这样的写法,还有更进一步用隐式循环代替显示 for 循环:
很多老鸟都爱这这么写,自行使用就好~
最后一个循环嵌套,其实在 08 就有说过了,这里简单提一下。
像下面的平方根求和代码:
for x in range(size):
for y in range(size):
z = sqrt(x) + sqrt(y)
代码中 sqrt(x) 位于for 循环最内层。
这就意味着每次执行都会重新计算一次,增加了时间开销。
其实可以这么写:
for x in range(size):
sqrt_x = sqrt(x)
for y in range(size):
z = sqrt_x + sqrt(y)
这样就会减少内层 for 循环的计算~
还有很多很多优化的高级操作,我们以后遇到再来像这样总结一下~
最后分享给大家一个查询 Python 数据结构效率的网址:传送门
好啦,这节课讲了很多概念,好好消化一下吧,有问题或者新的操作。
欢迎留言评论,下课!拜·~~
|