Python代码优化技巧和窍门

  • 1-分析你的代码
    • 1.1. 使用timeit模块
    • 1.2. 使用高级的cProfile分析
      • 1.2.1. 关于 cProfile 的结果说明?
  • 2-使用生成器和键进行排序
  • 3-优化你的循环语句
    • 3.1. 在Python中优化for循环
  • 4-利用哈希
  • 5-避免使用全局变量
  • 6-使用外部的包或者库
  • 7-使用内置的运算符
  • 8-限制循环中的方法调用
  • 9-字符串优化
  • 10-if语句进行优化
  • 11-使用装饰器进行一些缓存操作
  • 12-将“ while 1”用于无限循环。

Python是一种功能强大的编程语言。 我们可以做很多事情来使我们的代码更轻,更快。 它不仅仅是使用多进程等功能,而且还可以轻松实现。 下面,我们列出了一些最佳的Python代码优化技巧和窍门。

1-分析你的代码

如果您不了解你的代码性能瓶颈所在,那么在进一步优化代码之前,这会显得你很幼稚。因此,首先,使用以下两种方法中的任何一种来分析您的代码

1.1. 使用timeit模块

下面是使用Python的模块进行分析的传统方式。它记录了一段代码执行所需的时间。及测量过程消耗的时间(以毫秒为单位)

import timeitsubStrings = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']def simpleString(subStrings):finalString = ''for part in subStrings:finalString += partreturn finalStringdef formatString(subStrings):finalString = "%s%s%s%s%s%s%s" % (subStrings[0], subStrings[1],subStrings[2], subStrings[3],subStrings[4], subStrings[5],subStrings[6])return finalStringdef joinString(subStrings):return ''.join(subStrings)print('joinString() Time   : ' + str(timeit.timeit('joinString(subStrings)', setup='from __main__ import joinString, subStrings')))
print('formatString() Time : ' + str(timeit.timeit('formatString(subStrings)', setup='from __main__ import formatString, subStrings')))
print('simpleString() Time : ' + str(timeit.timeit('simpleString(subStrings)', setup='from __main__ import simpleString, subStrings')))

结果如下:

joinString() Time   : 0.223614629
formatString() Time : 0.49615162100000004
simpleString() Time : 0.47305408300000007

上面的示例说明了join方法比其他方法效率更高。

1.2. 使用高级的cProfile分析

从Python 2.5开始,cProfile已成为Python软件包的一部分。 它带来了一套不错的分析功能。 您可以通过多种方式将其与代码绑定。 就像将一个函数包装在其run方法中以衡量性能。 或者,借助Python的“ -m”选项将cProfile作为参数激活,同时以命令行方式运行整个脚本。

import cProfiledef add():"""也可使用双引号,当然引号里面也可以是直接的表达式 例如 '10 + 10'这样的用法"""return 10 + 10cProfile.run('add()')

结果如下:

             3 function calls in 0.000 secondsOrdered by: standard namencalls  tottime  percall  cumtime  percall filename:lineno(function)1    0.000    0.000    0.000    0.000 <string>:1(<module>)1    0.000    0.000    0.000    0.000 {built-in method builtins.exec}1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

当然也可以在terminal 里面使用命令:python -m cProfile -s cumtime xxx.py

1.2.1. 关于 cProfile 的结果说明?

从输出中分析找到导致代码耗时罪魁祸首就显得尤为重要。因此只有知道cProfile报告的关键要素后才能做出判断;
1. ncalls:表示函数调用的次数;
2. tottime:表示指定函数的总的运行时间;
3. percall:(第一个percall)表示tottime除以ncalls;
4. cumtime:表示该函数及其所有子函数的调用运行的时间,即函数开始调用到返回的时间;
5 .percall:(第二个percall)即函数运行一次的平均时间,等于 cumtime/ncalls;
5. filename:lineno(function):每个函数调用的具体信息;
从分析报告中你可以找到具体的原因。当然首先;最重要的是tottime和cumtime。 ncalls有时也可能是有用的。对于其余项目,您需要自己练习分析;

2-使用生成器和键进行排序

生成器是内存优化的绝佳工具。 它会创建一个可以一次返回一个结果的(迭代器)的函数,而不是一次返回所有的结果。 一个很好的例子是创建大量数字并将它们相加。
同样,在对列表中的元素进行排序时,应尽可能使用键和默认的sort()方法,在下面的例子中,我们根据key参数选择部分的索引对列表进行排序。

import operatortest = [(11, 52, 83), (61, 20, 40), (93, 72, 51)]
print("Before sorting:", test)test.sort(key=operator.itemgetter(0))
print("After sorting[1]: ", test)test.sort(key=operator.itemgetter(1))
print("After sorting[2]: ", test)test.sort(key=operator.itemgetter(2))
print("After sorting[3]: ", test)

结果如下:

Before sorting: [(11, 52, 83), (61, 20, 40), (93, 72, 51)]
After sorting[1]:  [(11, 52, 83), (61, 20, 40), (93, 72, 51)]
After sorting[2]:  [(61, 20, 40), (11, 52, 83), (93, 72, 51)]
After sorting[3]:  [(61, 20, 40), (93, 72, 51), (11, 52, 83)]

3-优化你的循环语句

大多数编程语言都强调需要优化循环。在Python中,我们确实有一种方法可以使循环执行得更快。

虽然您可能喜欢使用循环,但是循环是有代价的。 Python引擎在解释for循环结构上花费了大量精力。因此,最好将它们替换为Python的内置函数(例如Map)

接下来,代码优化的级别还取决于您对Python内置功能的了解。在以下示例中,我们将尝试解释不同的方法以帮助优化循环。

3.1. 在Python中优化for循环

import timeit
import itertoolsZipcodes = ['121212','232323','434334']
newZipcodes = ['  131313 ',' 242424   ',' 212121 ','  323232','342312  ',' 565656 ']def updateZips(newZipcodes, Zipcodes):"""Example-1 :最原始的,利用for循环去除 newZipcodes 里面的空格:param newZipcodes::param Zipcodes::return:"""for zipcode in newZipcodes:Zipcodes.append(zipcode.strip())def updateZipsWithMap(newZipcodes, Zipcodes):"""Example-2 :现在,看看如何使用map对象将以上内容转换为一行。在查看具体收益有多大:param newZipcodes::param Zipcodes::return:"""Zipcodes += map(str.strip, newZipcodes)def updateZipsWithListCom(newZipcodes, Zipcodes):"""Example-3 :利用列表推导式:param newZipcodes::param Zipcodes::return:"""Zipcodes += [iter.strip() for iter in newZipcodes]def updateZipsWithGenExp(newZipcodes, Zipcodes):"""Example-3 :最后,最快的方法是将for循环转换为生成器表达式:param newZipcodes::param Zipcodes::return:"""return itertools.chain(Zipcodes, (iter.strip() for iter in newZipcodes))print('updateZips() Time            : ' + str(timeit.timeit('updateZips(newZipcodes, Zipcodes)', setup='from __main__ import updateZips, newZipcodes, Zipcodes')))Zipcodes = ['121212','232323','434334']
print('updateZipsWithMap() Time     : ' + str(timeit.timeit('updateZipsWithMap(newZipcodes, Zipcodes)', setup='from __main__ import updateZipsWithMap, newZipcodes, Zipcodes')))Zipcodes = ['121212','232323','434334']
print('updateZipsWithListCom() Time : ' + str(timeit.timeit('updateZipsWithListCom(newZipcodes, Zipcodes)', setup='from __main__ import updateZipsWithListCom, newZipcodes, Zipcodes')))Zipcodes = ['121212','232323','434334']
print('updateZipsWithGenExp() Time  : ' + str(timeit.timeit('updateZipsWithGenExp(newZipcodes, Zipcodes)', setup='from __main__ import updateZipsWithGenExp, newZipcodes, Zipcodes')))
updateZips() Time            : 1.043096744
updateZipsWithMap() Time     : 0.7813633710000001
updateZipsWithListCom() Time : 0.9924229019999999
updateZipsWithGenExp() Time  : 0.5045337760000002

如上所述,在上述用例中(通常),使用生成器表达式是优化for循环的最快方法。我们汇总了四个示例的代码,以便您还可以看到每种方法所获得的性能提升.

4-利用哈希

Python使用哈希表来管理集合。每当我们将元素添加到集合中时,Python解释器都会使用目标元素的哈希值确定其在分配给该集合的内存中的位置。

由于Python自动调整哈希表的大小,因此无论集合的大小如何,速度都可以恒定(O(1))这就是使设置操作执行得更快的原因。

在Python中,集合操作包括并集,交集和差集。因此,您可以尝试在适合它们的代码中使用它们。这些通常比遍历列表更快。具体用法百度

Syntax       Operation    Description------       ---------    -----------
set(l1)|set(l2) Union        Set with all l1 and l2 items.
set(l1)&set(l2) Intersection Set with commmon l1 and l2 items.
set(l1)-set(l2) Difference   Set with l1 items not in l2.

5-避免使用全局变量

不仅限于Python,几乎所有语言都不赞成过度或无节制地使用全局变量。 其背后的原因是它们可能具有导致代码一些非显而易见的副作用。 而且,Python在访问外部变量方面确实很慢。
使用很少的全局变量是一种有效的设计模式,因为它可以帮助您跟踪范围和不必要的内存使用情况。而且,Python检索局部变量要比全局变量更快。

6-使用外部的包或者库

一些python库具有与原始库相同的功能。比如用“ C”编写的代码执行速度更快。例如,尝试使用cPickle而不是使用pickle。也可以尝试使用cpython。
您也可以考虑使用PyPy软件包。它包括一个JIT(即时)编译器,使Python代码运行得非常快。您甚至可以对其进行调整以提供额外的处理能力。

7-使用内置的运算符

Python是一种解释性语言,基于高级抽象。 因此,您应尽可能使用内置功能。 由于内置程序是预先编译的,并且速度很快,因此可以提高您的代码效率。 而包括解释步骤在内的冗长迭代变得非常缓慢。
同样,多使用map等内置功能,这些功能可以显着提高速度。

8-限制循环中的方法调用

当在循环中执行操作时,应该缓存方法调用,而不是在对象上调用它。否则,方法查找会显得很昂贵。
如下示例:

>>> for it in xrange(10000):
>>>    myLib.findMe(it)
>>> findMe = myLib.findMe
>>> for it in xrange(10000):
>>>    findMe(it)

9-字符串优化

字符串拼接速度很慢,永远不要在循环内进行。相反,请使用Python的join方法。或者,使用格式设置功能来形成统一的字符串

随着Python中的RegEx,虽然它们的运行速度很快。但是,在某些情况下,像isalpha()/isdigit()/ startswith()/ endswith()这样的基本字符串使用方法会更好

10-if语句进行优化

就像大多数编程语言都允许进行惰性假设评估一样,Python也是如此。这意味着,像“ AND”条件,如果其中任何一个条件为假,则不会对后续条件进行测试;
多使用if x:,而不是if x == True:来进行比较
if done is not None比使用 if done != None 更快

11-使用装饰器进行一些缓存操作

当我使用该算法找到第36个斐波那契数,即fibonacci(36)时,计算过程花了12s,48315636 function calls.

import cProfile
import timeitdef fibonacci(n):if n == 0: # There is no 0'th numberreturn 0elif n == 1: # We define the first number as 1return 1return fibonacci(n - 1) + fibonacci(n-2)
#
# print('fibonacci() Time   : ' + str(
#     timeit.timeit('fibonacci(36)', setup='from __main__ import fibonacci, n')))
cProfile.run('fibonacci(36)')
                 48315636 function calls (4 primitive calls) in 12.584 secondsOrdered by: standard namencalls  tottime  percall  cumtime  percall filename:lineno(function)1    0.000    0.000   12.584   12.584 <string>:1(<module>)
48315633/1   12.584    0.000   12.584   12.584 vv.py:4(fibonacci)1    0.000    0.000   12.584   12.584 {built-in method builtins.exec}1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

但是,当从标准库引入缓存时,情况会发生变化。只需要几行代码

import cProfile
import functools@functools.lru_cache(maxsize=128)
def fibonacci(n):if n == 0:return 0elif n == 1:return 1return fibonacci(n - 1) + fibonacci(n-2)cProfile.run('fibonacci(100)')
         104 function calls (4 primitive calls) in 0.000 secondsOrdered by: standard namencalls  tottime  percall  cumtime  percall filename:lineno(function)1    0.000    0.000    0.000    0.000 <string>:1(<module>)101/1    0.000    0.000    0.000    0.000 vv.py:6(fibonacci)1    0.000    0.000    0.000    0.000 {built-in method builtins.exec}1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

计算第100个数的时间0s,104 function calls

12-将“ while 1”用于无限循环。

如果您正在侦听套接字,则可能需要使用无限循环。实现此目的的正常方法是在True时使用。这是可行的,但是通过使用while 1可以更快地达到相同的效果,因为它是一个数值比较,仅适用Python2。

因为,在Python 2.x中,True它不是关键字,而只是在类型中定义为1 的内置全局常量bool。因此,解释器仍然必须加载True的内容。换句话说,True是可重新分配的:

Python 2.7 (r27:82508, Jul  3 2010, 21:12:11)
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> True = 4
>>> True
4

在Python 3.x中,

Python 3.1.2 (r312:79147, Jul 19 2010, 21:03:37)
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> True = 4File "<stdin>", line 1
SyntaxError: assignment to keyword

Pythont tip相关推荐

  1. html5页面中鼠标悬停效果,CSS实例:非常不错的鼠标悬停TIP效果!_div+css布局教程...

    在实际开发中,我们会给图片加上alt.给链接加上title,为了出故障预备,也可以提醒用户的内容是什么,或仅仅是tip提示.今天我们介绍一款不错的鼠标悬停TIP效果,图片如下: 这样的效果在实际开发中 ...

  2. Linux下静态编译的一个TIP

    Linux下静态编译的一个TIP | 素包子 Linux下静态编译的一个TIP 2010年3月28日 baoz 阅读评论 linux下静态编译好处很多,一来是可以跨发行版(debian redhat ...

  3. affectnet数据集_处理表情识别中的坏数据:一篇CVPR 2020及两篇TIP的解读

    机器之心分析师网络 作者:周宇 编辑:Joni Zhong 本篇提前看重点关注 CVPR 2020 中的这篇「Suppressing Uncertainties for Large-Scale Fac ...

  4. PHP 小tip .(@)符号和 php if 赋值

    tip 1: 下面介绍一下它的用法. 例如: 复制代码代码如下: function db_connect()//连接数据库  {  @$db =mysql_connect('localhost','r ...

  5. github上的版本和本地版本冲突的解决方法(Updates were rejected because the tip of your current branch is behind)

    github上的版本和本地版本冲突的解决方法(Updates were rejected because the tip of your current branch is behind) 参考文章: ...

  6. (转)[翻译] ASP.NET MVC Tip #1 - 使用扩展方法创建新的HTML Helper

    原文地址:http://weblogs.asp.net/stephenwalther/archive/2008/06/13/asp-net-mvc-tip-1-creating-new-html-he ...

  7. tip use view.isineditmode() in your custom views to skip code when shown in eclipse

    tip use view.isineditmode() in your custom views to skip code when shown in eclipse 转载于:https://www. ...

  8. 基于1.3.3版本tooltip的datagrid单元格tip实现

    基于1.3.3版本tooltip的datagrid单元格tip实现 2013年05月25日 ⁄ datagrid ⁄ 共 6122字 ⁄ 评论数 26 ⁄ 被围观 7,033 views+ 文章目录 ...

  9. ASP.NET MVC Tip #31: 给 Master Pages 和 User Controls 传递数据

    原文地址:ASP.NET MVC Tip #31 – Passing Data to Master Pages and User Controls 原文作者:swalther 本文译者:QLeelul ...

最新文章

  1. 温水里的程序员,技术将淘汰一切。
  2. 在线作图|在线做生态位宽度计算
  3. [svc]arp协议的细枝末节
  4. 天马行空脚踏实地,阿里巴巴有群百里挑一的天才应届生
  5. eventEmitter3源码分析与学习
  6. opencv 裁剪 java_如何在opencv java中裁剪检测到的面部图像
  7. 解决Python memory error的问题--扩充虚拟内存
  8. python界面长什么样子-这可能是最好玩的python GUI入门实例(推荐)
  9. java-自定义数据排序
  10. 图像识别中的深度学习【香港中文大学王晓刚】
  11. python运维开发常用模块(四)文件对比模块difflib
  12. matlab中的分类器使用小结(SVM、KNN、RF、AdaBoost、Naive Bayes、DAC)
  13. Redis如何淘汰过期的keys
  14. linux计划任务执行日志,linux中centos制定计划任务执行命令并且输出日志
  15. 2.9 go mod 之本地仓库搭建
  16. react navtagion api
  17. 2019 outlook 数据迁移_清华开源迁移学习算法库
  18. 一起学Hive——总结复制Hive表结构和数据的方法
  19. java获取.py文件值_Java File文件处理 读文件
  20. 微信开发:微信公众号给粉丝推送通知消息(模板消息)

热门文章

  1. 2019年即时通讯局势为Magento用户带来的启示
  2. 自己做的Google地图下载工具(一)
  3. linux dwg查看软件下载,CAD迷你看图 - DWG文件浏览小工具
  4. android手机做个人网盘,[干货Get!]Android搭建Cloudreve私人云盘 来自 kindyear
  5. 什么是php 的精华,PHP之精髓
  6. woff格式字体怎么打开和编辑?
  7. scratch加法出题机 电子学会图形化编程scratch等级考试三级真题和答案解析2021-3
  8. 短视频副业做什么比较靠谱,副业赚钱的路子有哪些
  9. Win10下Anaconda3上安装tensorflow教程
  10. ElasticSearch-常用搜索