鱼C论坛

 找回密码
 立即注册
查看: 3940|回复: 12

[技术交流] 番外:几个新手总会踩的“坑”(下)

[复制链接]
发表于 2021-9-30 08:45:56 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 鱼C-小师妹 于 2021-10-20 20:25 编辑

在线视频:



小讲堂更新到现在,距离几个新手总会踩的“坑”(上)|【辛 酸 血 泪】已经过去了几千行代码的时间~

哈哈哈哈哈,这么说是暗示你们都有认真完成每一讲的课后练习~

为什么迟迟没更呢?

原因很简单,让有“共性的问题”飞一会儿!

此刻时机已到,凝结成本文。

因为学到现在,很多童鞋不会再踩(上)中那样显而易见的“浅”坑。

会因为懂得还不够多,不够全面,而踩一些效率低下的坑~

这次我们就不在黑板上写代码咯·~

主要和大家分享一些心得,涉及到的代码不是重点,那些形而上的概念才重要哦!

废话不读说啦,开始吧~


1、优化原则

经常在每一讲的练习中,都会介绍给大家多种优化代码的方法。

这次来好好总结下优化代码的 3 大原则:

  • 过早优化
  • 权衡代价
  • 集中火力

咱们一个一个的来说。

原则一·:过早优化

很多童鞋一开始上手写代码就奔着性能优化的目标,对于老鸟这无可厚非~

但是对于新手如果这么要求自己,就会感到步步维艰,因为你不敢先让程序“先跑去来”。

没有跑起来就不知道哪里是重点,就会陷入到某个点中。俗话说得好:

让正确的程序更快要比让快速的程序正确容易得多

因此,优化的前提是代码能正常工作。

过早地进行优化可能会忽视对总体性能指标的把握,在得到全局结果前不要主次颠倒。

原则二:权衡代价

对于已经上手编程的童鞋,应该都已经学会“权衡代价”了,如果还不会,说明犯过的错还不够~

世间做任何事情,都会有代价的,就像你此时此刻看了本视频,当下就无法看其他的一样~

要知道想解决所有性能的问题是几乎不可能的!

通常面临的选择无非就是时间换空间或空间换时间。

开发成本一定要考虑到,不能为了优化一行代码,让其他维护他的人都不知所云。

原则三:集中火力

不要优化那些无关紧要的部分。

如果对代码的每一部分都去优化,这些修改会使代码难以阅读和理解。

如果你的代码运行速度很慢,首先要找到代码运行慢的位置,通常是内部循环,专注于运行慢的地方进行优化。

在其他地方,一点时间上的损失没有什么影响。


2、慎用全局变量

不管是使用哪门编程语言的新手,都会有一个不好的小习惯,我先不公布答案。

看看你能从下面这段代码中找到答案吗:

  1. import math

  2. size = 99999
  3. for x in range(size):
  4.     for y in range(size):
  5.         z = math.sqrt(x) + math.sqrt(y)
复制代码

发现了吧,没错就是:

使用全局变量

究其原因其实很简单:

因为不会调试,怕出错,一个值走天下,最安全

只要你看过小师妹之前分享的调试教程,真的会发现让编译器来帮你查值才最靠谱。



由于全局变量和局部变量实现方式不同,定义在全局范围内的代码运行速度会比定义在函数中的慢不少。

通过将脚本语句放入到函数中,通常可带来 15% - 30% 的速度提升哦!

所以上面代码更好的写法是将 size 写到函数中:

  1. def main():  
  2.     size = 10000
复制代码

定义到函数中后就可以减少全部变量使用~


3、无意义的数据复制

这里的复制不是指那种把函数复制过直接用。

而是指数据层面的复制,来看下面的代码,找问题:

  1. def main():
  2.     size = 99999
  3.     for f in range(size):
  4.         value = range(size)
  5.         value_list = [x for x in value]
  6.         square_list = [x * x for x in value_list]

  7. main()
复制代码

这里的 value_list,其实完全没有必要~

因为会创建不必要的数据结构或复制,直接这么写就好:

  1.   for f in range(size):
  2.         value = range(size)
  3.         square_list = [x * x for x in value]  

  4. main()
复制代码

另外也不要滥用 copy.deepcopy() 之类的函数。

通常在这些代码中是可以去掉复制操作的。


4、拼接字符串用 join

小甲鱼老师在最新版 Python 中讲解字符串的使用,强调过:

字符串拼接请用 join ,忘掉 +

很重要,但是有多少人还在图方便用 “+”呢:

  1. result = ''
  2. fori in string_list:
  3.         result += i
  4.     return result
复制代码

当使用 a + b 拼接字符串时,由于 Python 中字符串是不可变对象。

其会申请一块内存空间,将a和b分别复制到该新申请的内存空间中。

因此,如果要拼接 n 个字符串,会产生 n-1 个中间结果,每产生一个中间结果都需要申请和复制一次内存!

这肯定会严重影响运行效率滴。

而使用 join() 拼接字符串时,会首先计算出需要申请的总的内存空间,然后一次性地申请所需内存,并将每个字符串元素复制到该内存中去。

所以看完今天这一讲,请用 join 来拼接字符串,就像酱紫:

  1. return ''.join(string_list)
复制代码

是不是干净又好用呢?!


5、用 if 的短路特性

if 条件的短路特性是指对 if a and b 这样的语句, 当 a 为 False 时将直接返回,不再计算 b:

  1. if (1>2) and (3>2)
复制代码


对于 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 分),期末考必须及格,这样学期成绩才算及格,及格就输出“合格”,否则输出"失败"。

就可以写成这样:

游客,如果您要查看本帖隐藏内容请回复

看输出:

2021-10-03_19-43-07.jpg

代码很精简是不是,短路掉的部分,就是提升效率的所在。


6、循环的优化

天底下应该没有不用循环的程序员吧。

而选择哪些循环是有效率高低之别的,这几个点不理解的话就先记住:

  • 用 for 循环代替 while 循环
  • 使用隐式 for 循环代替显式 for 循环
  • 减少内层 for 循环的计算

我们一个一个来说~

在 Python 底层中 for 循环是比 while 循环效率高滴。

像这种最常用的 while 循环:

  1. while i < size:
  2.         sum += 1
  3.         i++
  4. return sum
复制代码

就可以写成:

  1. for i in range(size):
  2.         sum += 1
  3. return sum
复制代码

针对这样的写法,还有更进一步用隐式循环代替显示 for 循环:

  1. return sum(range(size))
复制代码

很多老鸟都爱这这么写,自行使用就好~

最后一个循环嵌套,其实在 08 就有说过了,这里简单提一下。



像下面的平方根求和代码:

  1. for x in range(size):
  2.         for y in range(size):
  3.             z = sqrt(x) + sqrt(y)
复制代码

代码中 sqrt(x) 位于for 循环最内层。

这就意味着每次执行都会重新计算一次,增加了时间开销。

其实可以这么写:

  1. for x in range(size):
  2.         sqrt_x = sqrt(x)  
  3.         for y in range(size):
  4.             z = sqrt_x + sqrt(y)
复制代码

这样就会减少内层 for 循环的计算~

还有很多很多优化的高级操作,我们以后遇到再来像这样总结一下~

最后分享给大家一个查询 Python 数据结构效率的网址:传送门

2021-10-04_08-46-22.jpg

好啦,这节课讲了很多概念,好好消化一下吧,有问题或者新的操作。

欢迎留言评论,下课!拜·~~

评分

参与人数 1荣誉 +5 贡献 +3 收起 理由
bool想学C + 5 + 3 催更

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-9-30 09:48:26 | 显示全部楼层
学习一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-10-3 22:12:37 From FishC Mobile | 显示全部楼层
我中了两个。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-10-4 09:59:39 | 显示全部楼层
快更新视频
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-10-9 10:57:07 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-10-14 22:06:04 | 显示全部楼层
靠靠靠靠靠扩一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-12 10:45:08 | 显示全部楼层
  1. a = int(input('请输入第一次月考的成绩:'))
  2. b = int(input('请输入第二次月考的成绩:'))
  3. c = int(input("请输入期末考试成绩:"))
  4. if  c >60 and (a > 60 or b > 60):
  5. print('及格')
  6. else:
  7. print('失败')
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-16 10:30:05 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-11-16 10:43:47 | 显示全部楼层
冲冲冲
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-21 11:23:34 | 显示全部楼层
谢了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-1-23 11:57:31 | 显示全部楼层
学习学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-1-23 23:41:27 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-8-26 08:57:40 | 显示全部楼层
666666
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-27 00:06

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表