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的更多相关文章

  1. 干净win7要做几步才能运行第一个Spring MVC 写的动态web程序

    干净win7要做几步才能运行第一个Spring MVC 写的动态web程序: 1. 下载安装jdk 2. 配置Java环境变量 3. 测试一下第1,2两步是否完全成功:http://jingyan.b ...

  2. GD32电压不足时烧写程序导致程序运行异常的解决方法

    一直使用的GD32F450前段时间遇到这样一个问题,当使用J-Link供电给板子烧写程序之后,程序运行缓慢,就像运行在FLASH高速部分之外一样,但是如果使用外部供电烧写,就不会出现这个问题,而且一旦 ...

  3. [Java.File]如果写 File filesFolder = new File("/") ,在windows系统中,filesFolder 会去找哪个盘符? 答案:程序运行路径的根盘符.

    首先这段代码在Unix/Linux系统上会去找根路径,但在Windows系统上会去找C:盘还是D:盘还是其它盘呢? 其实它会去找user.dir所在盘符的根目录,user.dir即用户的当前工作目录, ...

  4. python学习笔记-python程序运行

    小白初学python,写下自己的一些想法.大神请忽略. 安装python编辑器,并配置环境(见http://www.cnblogs.com/lynn-li/p/5885001.html中 python ...

  5. linux下实现在程序运行时的函数替换(热补丁)

    声明:以下的代码成果,是参考了网上的injso技术,在本文的最后会给出地址,同时非常感谢injso技术原作者的分享. 但是injso文章中的代码存在一些问题,所以后面出现的代码是经过作者修改和检测的. ...

  6. 放在NSArray、NSDictionary等容器内的对象Item,Item中的property在程序运行过程中被无故释放

    可能是被释放的property本身是OC对象而它的属性被误写成assign,例如: @interface MyItem : Object @property (nonatomic, assign) N ...

  7. 孙鑫MFC学习笔记3:MFC程序运行过程

    1.MFC中WinMain函数的位置在APPMODUL.cpp APPMODUL.cpp中是_tWinMain,其实_tWinMain是一个宏#define _tWinMain WinMain 2.全 ...

  8. Java中内存中的Heap、Stack与程序运行的关系

    堆和栈的内存管理 栈的内存管理是顺序分配的,而且定长,不存在内存回收问题:而堆 则是随机分配内存,不定长度,存在内存分配和回收的问题:堆内存和栈内存的区别可以用如下的比喻来看出:使用堆内存就象是自己动 ...

  9. 第二章--Win32程序运行原理 (部分概念及代码讲解)

    学习<Windows程序设计>记录 概念贴士: 1. 每个进程都有赋予它自己的私有地址空间.当进程内的线程运行时,该线程仅仅能够访问属于它的进程的内存,而属于其他进程的内存被屏蔽了起来,不 ...

随机推荐

  1. Vuex form表单处理, 比官网更好的办法

    Vuex form表单处理, 比官网更好的办法 问题, 当使用vuex的state作为表单的v-model元素, 虽然简单粗暴, 但这种修改没有经过mutation方法. 在严格模式下会抛出错误 目录 ...

  2. java导出excel并且压缩成zip上传到oss,并下载,使用字节流去存储,不用文件流保存文件到本地

    最近项目上要求实现导出excel并根据条数做分割,然后将分割后的多个excel打包成压缩包上传到oss服务器上,然后提供下载方法,具体代码如下:这里只展示部分代码,获取数据的代码就不展示了 ByteA ...

  3. Java 在Excel中添加分离型饼图、环形图

    一.概述 Excel中可支持多种不同类型的图表,本文介绍如何绘制分离型饼图和环形图.其中,分离型饼图的绘制可分为整体分离型(即设置饼图分离程度)和局部分离(即设置点爆炸型值)两种情况.下面将以Java ...

  4. 汇编中的inc和dec

    原文链接:https://www.cnblogs.com/whzym111/p/6370198.htmlinc 加1指令 dec 减1指令 一.加一指令inc inc a 相当于 add a,1 // ...

  5. 【GDOI2007】JZOJ2020年8月10日提高组T1 夏娜的菠萝包

    [GDOI2007]JZOJ2020年8月10日提高组T1 夏娜的菠萝包 题目 Description 夏娜很喜欢吃菠萝包,她的经纪人RC每半个月就要为她安排接下来的菠萝包计划.今天是7月份,RC又要 ...

  6. 【佛山市选2013】JZOJ2020年8月7日提高组T3 海明距离

    [佛山市选2013]JZOJ2020年8月7日提高组T3 海明距离 题目 描述 对于二进制串a,b,他们之间的海明距离是指两个串异或之后串中1的个数.异或的规则为: 0 XOR 0 = 0 1 XOR ...

  7. SpringCloud 源码系列(3)—— 注册中心 Eureka(下)

    十一.Eureka Server 集群 在实际的生产环境中,可能有几十个或者几百个的微服务实例,Eureka Server 承担了非常高的负载,而且为了保证注册中心高可用,一般都要部署成集群的,下面就 ...

  8. 第14.2节 HTML知识简介

    一. HTML语言 HTML 指的是超文本标记语言 (Hyper Text Markup Language),它不是一种编程语言,而是一种使用一套标记标签(markup tag)来标记元素作用的标记语 ...

  9. Java数据结构(十五)—— 多路查找树

    多路查找树 二叉树和B树 二叉树的问题分析 二叉树操作效率高 二叉树需要加载到内存,若二叉树的节点多存在如下问题: 问题1:构建二叉树时,需多次进行I/O操作,对与速度有影响 问题2:节点海量造成二叉 ...

  10. 【Docker】 CentOS7 安装 Docker 及其使用方法 ( 一 )

    系列目录: [Docker] CentOS7 安装 Docker 及其使用方法 ( 一 ) [Docker] 使用Docker 在阿里云 Centos7 部署 MySQL 和 Redis (二) [D ...