Python 是一种脚本语言,相比 C/C++ 这样的编译语言,在效率和性能方面存在一些不足,但是可以通过代码调整来提高代码的执行效率。本文整理一些代码优化技巧。

代码优化基本原则代码正常运行后优化。

很多人一开始写代码就奔着性能优化的目标,“让正确的程序更快要比让快速的程序正确容易得多”,因此,优化的前提是代码能正常工作。过早地进行优化可能会忽视对总体性能指标的把握,在得到全局结果前不要主次颠倒。

权衡优化的代价。

优化是有代价的,想解决所有性能的问题是几乎不可能的。通常面临的选择是时间换空间或空间换时间。另外,开发代价也需要考虑。

优化关键耗时部分。

如果对代码的每一部分都去优化,这些修改会使代码难以阅读和理解。如果你的代码运行速度很慢,首先要找到代码运行慢的位置,通常是内部循环,专注于运行慢的地方进行优化。在其他地方,一点时间上的损失没有什么影响。

优化技巧

避免全局变量

在函数中编写代码而不要将其写为全局变量。 由于全局变量和局部变量实现方式不同,定义在全局范围内的代码运行速度会比定义在函数中的慢不少。通过将脚本语句放入到函数中,通常可带来 15% - 30% 的速度提升。

# 不推荐写法

import math

size = 10000

for x in range(size):

for y in range(size):

z = math.sqrt(x) + math.sqrt(y)

# 推荐写法

import math

def main(): # 定义到函数中,以减少全部变量使用

size = 10000

for x in range(size):

for y in range(size):

z = math.sqrt(x) + math.sqrt(y)

main()

避免 .

避免模块和函数属性访问

每次使用.(属性访问操作符时)会触发特定的方法,如__getattribute__()和__getattr__(),这些方法会进行字典操作,因此会带来额外的时间开销。通过from import语句,可以消除属性访问。

# 不推荐写法

import math

def computeSqrt(size: int):

result = []

for i in range(size):

result.append(math.sqrt(i))

return result

def main():

size = 10000

for _ in range(size):

result = computeSqrt(size)

main()

# 推荐写法,第一次优化 . 模块属性访问

from math import sqrt

def computeSqrt(size: int):

result = []

for i in range(size):

result.append(sqrt(i)) # 避免math.sqrt的使用

return result

def main():

size = 10000

for _ in range(size):

result = computeSqrt(size)

main()

# 推荐写法,第二次优化局部变量 sqrt,局部变量访问比全局变量快。

import math

def computeSqrt(size: int):

result = []

sqrt = math.sqrt # 赋值给局部变量

for i in range(size):

result.append(sqrt(i)) # 避免math.sqrt的使用

return result

def main():

size = 10000

for _ in range(size):

result = computeSqrt(size)

main()

# 推荐写法, 第三次优化函数属性 list.append() 方法

import math

def computeSqrt(size: int):

result = []

append = result.append

sqrt = math.sqrt # 赋值给局部变量

for i in range(size):

append(sqrt(i)) # 避免 result.append 和 math.sqrt 的使用

return result

def main():

size = 10000

for _ in range(size):

result = computeSqrt(size)

main()

避免访问类内属性

避免 . 的原则也适用于类内属性,访问self._value的速度会比访问一个局部变量更慢一些。通过将需要频繁访问的类内属性赋值给一个局部变量,可以提升代码运行速度。

# 不推荐写法

import math

from typing import List

class DemoClass:

def __init__(self, value: int):

self._value = value

def computeSqrt(self, size: int) -> List[float]:

result = []

append = result.append

sqrt = math.sqrt

for _ in range(size):

append(sqrt(self._value))

return result

def main():

size = 10000

for _ in range(size):

demo_instance = DemoClass(size)

result = demo_instance.computeSqrt(size)

main()

# 推荐写法,将self._value 赋值给局部变量

import math

from typing import List

class DemoClass:

def __init__(self, value: int):

self._value = value

def computeSqrt(self, size: int) -> List[float]:

result = []

append = result.append

sqrt = math.sqrt

value = self._value

for _ in range(size):

append(sqrt(value)) # 避免 self._value 的使用

return result

def main():

size = 10000

for _ in range(size):

demo_instance = DemoClass(size)

demo_instance.computeSqrt(size)

main()

避免不必要的抽象

任何时候当你使用额外的处理层(比如装饰器、属性访问、描述器)去包装代码时,都会让代码变慢。大部分情况下,需要重新进行审视使用属性访问器的定义是否有必要,使用getter/setter函数对属性进行访问通常是 C/C++ 程序员遗留下来的代码风格。如果真的没有必要,就使用简单属性。

# 不推荐写法。

class DemoClass:

def __init__(self, value: int):

self.value = value

@property

def value(self) -> int:

return self._value

@value.setter

def value(self, x: int):

self._value = x

def main():

size = 1000000

for i in range(size):

demo_instance = DemoClass(size)

value = demo_instance.value

demo_instance.value = i

main()

避免数据复制避免无意义的数据复制

交换值时不使用中间变量

a, b = b, a

字符串拼接使用join而不是+

当使用a + b拼接字符串时,由于 Python 中字符串是不可变对象,其会申请一块内存空间,将a和b分别复制到该新申请的内存空间中。因此,如果要拼接 n 个字符串,会产生 n-1 个中间结果,每产生一个中间结果都需要申请和复制一次内存,严重影响运行效率。而使用join()拼接字符串时,会首先计算出需要申请的总的内存空间,然后一次性地申请所需内存,并将每个字符串元素复制到该内存中去。

# 不推荐写法

import string

from typing import List

def concatString(string_list: List[str]) -> str:

result = ''

for str_i in string_list:

result += str_i

return result

def main():

string_list = list(string.ascii_letters * 100)

for _ in range(10000):

result = concatString(string_list)

main()

# 推荐写法

import string

from typing import List

def concatString(string_list: List[str]) -> str:

return ''.join(string_list) # 使用 join 而不是 +

def main():

string_list = list(string.ascii_letters * 100)

for _ in range(10000):

result = concatString(string_list)

main()

利用 if 条件的短路特性

if 条件的短路特性是指对if a and b这样的语句, 当a为False时将直接返回,不再计算b;对于if a or b这样的语句,当a为True时将直接返回,不再计算b。因此, 为了节约运行时间,对于or语句,应该将值为True可能性比较高的变量写在or前,而and应该推后。

循环优化利用for代替while;这是由于Python中for循环比while循环更快;

利用隐式for循环代替显式for循环;例如隐式sum(range(10000));

减少内层循环计算;

使用numba.jit优化

使用合适的数据结构

Python 内置的数据结构如str, tuple, list, set, dict底层都是 C 实现的,速度非常快,自己实现新的数据结构想在性能上达到内置的速度几乎是不可能的。

联系作者

python基础代码技巧_Python 代码优化技巧(二)相关推荐

  1. python基础代码大全博客园,python基础代码大全解释

    python必背入门代码是什么? python必背代码是:defnot_empty(s):returnsandlen(s.strip())>0#returnsands.strip()#如果直接单 ...

  2. Python基础数据之列表知识(二)

    Python基础数据之列表知识(二) 一.列表的特点 二.列表的排序 三.列表的嵌套 1.嵌套的基本使用 2.嵌套的示例 四.列表的循环删除 五.列表相关知识链接 一.列表的特点 1.有序 2.独立 ...

  3. python基础代码库-python爬虫基础教程:requests库(二)代码实例

    get请求 简单使用 import requests ''' 想要学习Python?Python学习交流群:973783996满足你的需求,资料都已经上传群文件,可以自行下载! ''' respons ...

  4. python基础代码的含义_Python基础学习篇

    原标题:Python基础学习篇 1.编码 默认情况下,Python 3 源码文件以 UTF-8 编码,所有字符串都是unicode 字符串. 当然你也可以为源码文件指定不同的编码:# -*- codi ...

  5. python基础代码大全-python基础语法,python 代码命令大全

    python: 1.语法强制缩进 2.区分大小写:iLoop与iloop是两个变量 3.变量无需申明,但是变量赋值前无法使用:a=3合法,b=a+3合法,b=a+c不合法,因为c未赋值前不能使用 4. ...

  6. python 的代码格式_python代码格式

    笨办法学 Python · 续 中文版 笨办法学 Python · 续 中文版 原书:Learn More Python 3 The Hard Way 译者:飞龙 自豪地采用谷歌翻译 在线阅读 PDF ...

  7. python基础知识测试题_Python中的单元测试—基础知识

    python基础知识测试题 Unit testing is the number one skill which separates people who just finished their de ...

  8. python工程代码语法_python编码环境安装与基本语法

    一.pycharm的基本使用 1.python以及pycharm的安装 python的版本选择:3.x版本就行 pycharm的版本选择:社区版就够用 pycharm只是一个编写工具,python才是 ...

  9. python基础代码大全-python零基础入门命令方式汇总大全,快速恶补你的Python基础...

    原标题:python零基础入门命令方式汇总大全,快速恶补你的Python基础 无意中浏览到这篇来自大牛的分享,总结的很全面,我重新排版下放在这里,希望能帮助到大家.在此十分感谢原作者! 在开始之前还是 ...

最新文章

  1. java 虚拟打印机_Java 通过物理、虚拟打印机打印Word文档
  2. LeetCode Maximum Product of Word Lengths(位操作)
  3. 聚焦云原生,阿里云与 CNCF 共话「云未来,新可能」
  4. server sql 将出生日期转为年龄_在sql server表中有一个出生日期字段我怎么才能在当前年份改变时自动更新年龄字段...
  5. 边缘计算容器化是否有必要?
  6. 不能调试的问题的解决
  7. SAP License:瞎搞!你真的懂什么是ERP、中台和低代码吗?
  8. log4j配置时的位置问题
  9. JAMStack-SSR/SSG 框架
  10. Navicat在输入da..时自动关闭解决方法(手心输入法)
  11. TXT文本 本地词典
  12. oracle 正版识别,正版Oracle产品价格
  13. ever since用法
  14. 成都盛迈坤电商:提高店铺商品评分的方法
  15. CPU是如何制造出来的(附高清全程图解)
  16. 域名系统(DNS)说明
  17. 解析ip到对应城市:ipdatabase
  18. java.sql.SQLException: Access denied for user ‘xxx‘@‘localhost‘ (using password: YES)
  19. leetcode算法(2)
  20. WEB渗透之SQL 注入

热门文章

  1. python中的替换函数_python:替换模块类中的函数
  2. micropython 蜂鸣器_基于MicroPython的TPYBoard微信远程可燃气体报警器的设计与实现...
  3. 计算机故障检修课过时,第三场公开课|电脑故障维修以及笔记本知识科普
  4. java 方法 示例_Java语言环境getVariant()方法与示例
  5. 单位矩阵属性(I ^ k = I)| 使用Python的线性代数
  6. dumpstack_Java Thread类的静态void dumpStack()方法(带示例)
  7. 聊聊并发编程的10个坑
  8. Redis 过期策略与源码分析
  9. Android Call requires API level 11 (current min is 8)的解决方案
  10. 【K8S】Docker向私有仓库拉取/推送镜像报错(http: server gave HTTP response to HTTPS client)