程序运行慢?你怕是写的假 Python
Python程序运行太慢的一个可能的原因是没有尽可能的调用内置方法,下面通过5个例子来演示如何用内置方法提升Python程序的性能。
1. 数组求平方和
输入一个列表,要求计算出该列表中数字的的平方和。最终性能提升了1.4倍。首先创建一个长度为10000的列表。
arr = list(range(10000))
1.1 最常规的写法
while循环遍历列表求平方和。平均运行时间2.97毫秒。
def sum_sqr_0(arr):
res = 0
n = len(arr)
i = 0
while i < n:
res += arr[i] ** 2
i += 1
return res
%timeit sum_sqr_0(arr)
2.97 ms ± 36.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1.2 for range代替while循环
避免i += 1的变量类型检查带来的额外开销。平均运行时间2.9毫秒。
def sum_sqr_1(arr):
res = 0
for i in range(len(arr)):
res += arr[i] ** 2
return res
%timeit sum_sqr_1(arr)
2.9 ms ± 137 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1.3 for x in arr代替for range
避免arr[i]的变量类型检查带来的额外开销。平均运行时间2.59毫秒。
def sum_sqr_2(arr):
res = 0
for x in arr:
res += x ** 2
return res
%timeit sum_sqr_2(arr)
2.59 ms ± 89 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1.4 sum函数套用map函数
平均运行时间2.36毫秒
def sum_sqr_3(arr):
return sum(map(lambda x: x**2, arr))
%timeit sum_sqr_3(arr)
2.36 ms ± 15.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1.5 sum函数套用生成器表达式
生成器表达式如果作为某个函数的参数,则可以省略掉()。平均运行时间2.35毫秒。
def sum_sqr_4(arr):
return sum(x ** 2 for x in arr)
%timeit sum_sqr_4(arr)
2.35 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1. 6 sum函数套用列表推导式
平均运行时间2.06毫秒。
def sum_sqr_5(arr):
return sum([x ** 2 for x in arr])
%timeit sum_sqr_5(arr)
2.06 ms ± 27.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2. 字符串拼接
输入一个列表,要求将列表中的字符串的前3个字符都拼接为一个字符串。最终性能提升了2.1倍。
首先创建一个列表,生成10000个随机长度和内容的字符串。
from random import randint
def random_letter():
return chr(ord('a') + randint(0, 25))
def random_letters(n):
return "".join([random_letter() for _ in range(n)])
strings = [random_letters(randint(1, 10)) for _ in range(10000)]
2.1 最常规的写法
while循环遍历列表,对字符串进行拼接。平均运行时间1.86毫秒。
def concat_strings_0(strings):
res = ""
n = len(strings)
i = 0
while i < n:
res += strings[i][:3]
i += 1
return res
%timeit concat_strings_0(strings)
1.86 ms ± 74.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
2.2 for range代替while循环
避免i += 1的变量类型检查带来的额外开销。平均运行时间1.55毫秒。
def concat_strings_1(strings):
res = ""
for i in range(len(strings)):
res += strings[i][:3]
return res
%timeit concat_strings_1(strings)
1.55 ms ± 32.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
2.3 for x in strings代替for range
避免strings[i]的变量类型检查带来的额外开销。平均运行时间1.32毫秒。
def concat_strings_2(strings):
res = ""
for x in strings:
res += x[:3]
return res
%timeit concat_strings_2(strings)
1.32 ms ± 19.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
2.4 .join方法套用生成器表达式
平均运行时间1.06毫秒。
def concat_strings_3(strings):
return "".join(x[:3] for x in strings)
%timeit concat_strings_3(strings)
1.06 ms ± 15.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
2.5 .join方法套用列表解析式
平均运行时间0.85毫秒。
def concat_strings_4(strings):
return "".join([x[:3] for x in strings])
%timeit concat_strings_4(strings)
858 µs ± 14.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
3. 筛选奇数
输入一个列表,要求筛选出该列表中的所有奇数。最终性能提升了3.6倍。
首先创建一个长度为10000的列表。
arr = list(range(10000))
3.1 最常规的写法
创建一个空列表res,while循环遍历列表,将奇数append到res中。平均运行时间1.03毫秒。
def filter_odd_0(arr):
res = []
i = 0
n = len(arr)
while i < n:
if arr[i] % 2:
res.append(arr[i])
i += 1
return res
%timeit filter_odd_0(arr)
1.03 ms ± 34.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
3.2 for range代替while循环
避免i += 1的变量类型检查带来的额外开销。平均运行时间0.965毫秒。
def filter_odd_1(arr):
res = []
for i in range(len(arr)):
if arr[i] % 2:
res.append(arr[i])
i += 1
return res
%timeit filter_odd_1(arr)
965 µs ± 4.02 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
3.3 for x in arr代替for range
避免arr[i]的变量类型检查带来的额外开销。平均运行时间0.430毫秒。
def filter_odd_2(arr):
res = []
for x in arr:
if x % 2:
res.append(x)
return res
%timeit filter_odd_2(arr)
430 µs ± 9.25 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
3.4 list套用filter函数
平均运行时间0.763毫秒。注意filter函数很慢,在Python 3.6里非常鸡肋。
def filter_odd_3(arr):
return list(filter(lambda x: x % 2, arr))
%timeit filter_odd_3(arr)
763 µs ± 15.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
3.5 list套用生成器表达式
平均运行时间0.398毫秒。
def filter_odd_4(arr):
return list((x for x in arr if x % 2))
%timeit filter_odd_4(arr)
398 µs ± 16.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
3.6 带条件的列表推导式
平均运行时间0.290毫秒。
def filter_odd_5(arr):
return [x for x in arr if x % 2]
%timeit filter_odd_5(arr)
290 µs ± 5.54 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
4. 两个数组相加
输入两个长度相同的列表,要求计算出两个列表对应位置的数字之和,返回一个与输入长度相同的列表。最终性能提升了2.7倍。
首先生成两个长度为10000的列表。
arr1 = list(range(10000))
arr2 = list(range(10000))
4.1 最常规的写法
创建一个空列表res,while循环遍历列表,将两个列表对应的元素之和append到res中。平均运行时间1.23毫秒。
def arr_sum_0(arr1, arr2):
i = 0
n = len(arr1)
res = []
while i < n:
res.append(arr1[i] + arr2[i])
i += 1
return res
%timeit arr_sum_0(arr1, arr2)
1.23 ms ± 3.77 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
4.2 for range代替while循环
避免i += 1的变量类型检查带来的额外开销。平均运行时间0.997毫秒。
def arr_sum_1(arr1, arr2):
res = []
for i in range(len(arr1)):
res.append(arr1[i] + arr2[i])
return res
%timeit arr_sum_1(arr1, arr2)
997 µs ± 7.42 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
4.3 for i, x in enumerate代替for range
部分避免arr[i]的变量类型检查带来的额外开销。平均运行时间0.799毫秒。
def arr_sum_2(arr1, arr2):
res = arr1.copy()
for i, x in enumerate(arr2):
res[i] += x
return res
%timeit arr_sum_2(arr1, arr2)
799 µs ± 16.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
4.4 for x, y in zip代替for range
避免arr[i]的变量类型检查带来的额外开销。平均运行时间0.769毫秒。
def arr_sum_3(arr1, arr2):
res = []
for x, y in zip(arr1, arr2):
res.append(x + y)
return res
%timeit arr_sum_3(arr1, arr2)
769 µs ± 12.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
4.5 列表推导式套用zip
平均运行时间0.462毫秒。
def arr_sum_4(arr1, arr2):
return [x + y for x, y in zip(arr1, arr2)]
%timeit arr_sum_4(arr1, arr2)
462 µs ± 3.43 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
5. 两个列表相同元素的数量
输入两个列表,要求统计两个列表相同元素的数量。其中每个列表内的元素都是不重复的。最终性能提升了5000倍。
首先创建两个列表,并将元素的顺序打乱。
from random import shuffle
arr1 = list(range(2000))
shuffle(arr1)
arr2 = list(range(1000, 3000))
shuffle(arr2)
5.1 最常规的写法
while循环嵌套,判断元素arr1[i]是否等于arr2[j],平均运行时间338毫秒。
def n_common_0(arr1, arr2):
res = 0
i = 0
m = len(arr1)
n = len(arr2)
while i < m:
j = 0
while j < n:
if arr1[i] == arr2[j]:
res += 1
j += 1
i += 1
return res
%timeit n_common_0(arr1, arr2)
338 ms ± 7.81 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
5.2 for range代替while循环
避免i += 1的变量类型检查带来的额外开销。平均运行时间233毫秒。
def n_common_1(arr1, arr2):
res = 0
for i in range(len(arr1)):
for j in range(len(arr2)):
if arr1[i] == arr2[j]:
res += 1
return res
%timeit n_common_1(arr1, arr2)
233 ms ± 10.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
5.3 for x in arr代替for range
避免arr[i]的变量类型检查带来的额外开销。平均运行时间84.8毫秒。
def n_common_2(arr1, arr2):
res = 0
for x in arr1:
for y in arr2:
if x == y:
res += 1
return res
%timeit n_common_2(arr1, arr2)
84.8 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
5.4 使用if x in arr2代替内层循环
平均运行时间24.9毫秒。
def n_common_3(arr1, arr2):
res = 0
for x in arr1:
if x in arr2:
res += 1
return res
%timeit n_common_3(arr1, arr2)
24.9 ms ± 1.39 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
5.4 使用更快的算法
将数组用.sort方法排序,再进行单层循环遍历。把时间复杂度从O(n2)降低到O(nlogn),平均运行时间0.239毫秒。
def n_common_4(arr1, arr2):
arr1.sort()
arr2.sort()
res = i = j = 0
m, n = len(arr1), len(arr2)
while i < m and j < n:
if arr1[i] == arr2[j]:
res += 1
i += 1
j += 1
elif arr1[i] > arr2[j]:
j += 1
else:
i += 1
return res
%timeit n_common_4(arr1, arr2)
329 µs ± 12.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
5.5 使用更好的数据结构
将数组转为集合,求交集的长度。平均运行时间0.067毫秒。
def n_common_5(arr1, arr2):
return len(set(arr1) & set(arr2))
%timeit n_common_5(arr1, arr2)
67.2 µs ± 755 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理
想要获取更多Python学习资料可以加QQ:2955637827私聊或加Q群630390733大家一起来学习讨论吧!
程序运行慢?你怕是写的假 Python的更多相关文章
- 干净win7要做几步才能运行第一个Spring MVC 写的动态web程序
干净win7要做几步才能运行第一个Spring MVC 写的动态web程序: 1. 下载安装jdk 2. 配置Java环境变量 3. 测试一下第1,2两步是否完全成功:http://jingyan.b ...
- GD32电压不足时烧写程序导致程序运行异常的解决方法
一直使用的GD32F450前段时间遇到这样一个问题,当使用J-Link供电给板子烧写程序之后,程序运行缓慢,就像运行在FLASH高速部分之外一样,但是如果使用外部供电烧写,就不会出现这个问题,而且一旦 ...
- [Java.File]如果写 File filesFolder = new File("/") ,在windows系统中,filesFolder 会去找哪个盘符? 答案:程序运行路径的根盘符.
首先这段代码在Unix/Linux系统上会去找根路径,但在Windows系统上会去找C:盘还是D:盘还是其它盘呢? 其实它会去找user.dir所在盘符的根目录,user.dir即用户的当前工作目录, ...
- python学习笔记-python程序运行
小白初学python,写下自己的一些想法.大神请忽略. 安装python编辑器,并配置环境(见http://www.cnblogs.com/lynn-li/p/5885001.html中 python ...
- linux下实现在程序运行时的函数替换(热补丁)
声明:以下的代码成果,是参考了网上的injso技术,在本文的最后会给出地址,同时非常感谢injso技术原作者的分享. 但是injso文章中的代码存在一些问题,所以后面出现的代码是经过作者修改和检测的. ...
- 放在NSArray、NSDictionary等容器内的对象Item,Item中的property在程序运行过程中被无故释放
可能是被释放的property本身是OC对象而它的属性被误写成assign,例如: @interface MyItem : Object @property (nonatomic, assign) N ...
- 孙鑫MFC学习笔记3:MFC程序运行过程
1.MFC中WinMain函数的位置在APPMODUL.cpp APPMODUL.cpp中是_tWinMain,其实_tWinMain是一个宏#define _tWinMain WinMain 2.全 ...
- Java中内存中的Heap、Stack与程序运行的关系
堆和栈的内存管理 栈的内存管理是顺序分配的,而且定长,不存在内存回收问题:而堆 则是随机分配内存,不定长度,存在内存分配和回收的问题:堆内存和栈内存的区别可以用如下的比喻来看出:使用堆内存就象是自己动 ...
- 第二章--Win32程序运行原理 (部分概念及代码讲解)
学习<Windows程序设计>记录 概念贴士: 1. 每个进程都有赋予它自己的私有地址空间.当进程内的线程运行时,该线程仅仅能够访问属于它的进程的内存,而属于其他进程的内存被屏蔽了起来,不 ...
随机推荐
- Vuex form表单处理, 比官网更好的办法
Vuex form表单处理, 比官网更好的办法 问题, 当使用vuex的state作为表单的v-model元素, 虽然简单粗暴, 但这种修改没有经过mutation方法. 在严格模式下会抛出错误 目录 ...
- java导出excel并且压缩成zip上传到oss,并下载,使用字节流去存储,不用文件流保存文件到本地
最近项目上要求实现导出excel并根据条数做分割,然后将分割后的多个excel打包成压缩包上传到oss服务器上,然后提供下载方法,具体代码如下:这里只展示部分代码,获取数据的代码就不展示了 ByteA ...
- Java 在Excel中添加分离型饼图、环形图
一.概述 Excel中可支持多种不同类型的图表,本文介绍如何绘制分离型饼图和环形图.其中,分离型饼图的绘制可分为整体分离型(即设置饼图分离程度)和局部分离(即设置点爆炸型值)两种情况.下面将以Java ...
- 汇编中的inc和dec
原文链接:https://www.cnblogs.com/whzym111/p/6370198.htmlinc 加1指令 dec 减1指令 一.加一指令inc inc a 相当于 add a,1 // ...
- 【GDOI2007】JZOJ2020年8月10日提高组T1 夏娜的菠萝包
[GDOI2007]JZOJ2020年8月10日提高组T1 夏娜的菠萝包 题目 Description 夏娜很喜欢吃菠萝包,她的经纪人RC每半个月就要为她安排接下来的菠萝包计划.今天是7月份,RC又要 ...
- 【佛山市选2013】JZOJ2020年8月7日提高组T3 海明距离
[佛山市选2013]JZOJ2020年8月7日提高组T3 海明距离 题目 描述 对于二进制串a,b,他们之间的海明距离是指两个串异或之后串中1的个数.异或的规则为: 0 XOR 0 = 0 1 XOR ...
- SpringCloud 源码系列(3)—— 注册中心 Eureka(下)
十一.Eureka Server 集群 在实际的生产环境中,可能有几十个或者几百个的微服务实例,Eureka Server 承担了非常高的负载,而且为了保证注册中心高可用,一般都要部署成集群的,下面就 ...
- 第14.2节 HTML知识简介
一. HTML语言 HTML 指的是超文本标记语言 (Hyper Text Markup Language),它不是一种编程语言,而是一种使用一套标记标签(markup tag)来标记元素作用的标记语 ...
- Java数据结构(十五)—— 多路查找树
多路查找树 二叉树和B树 二叉树的问题分析 二叉树操作效率高 二叉树需要加载到内存,若二叉树的节点多存在如下问题: 问题1:构建二叉树时,需多次进行I/O操作,对与速度有影响 问题2:节点海量造成二叉 ...
- 【Docker】 CentOS7 安装 Docker 及其使用方法 ( 一 )
系列目录: [Docker] CentOS7 安装 Docker 及其使用方法 ( 一 ) [Docker] 使用Docker 在阿里云 Centos7 部署 MySQL 和 Redis (二) [D ...