python中一些代码提速技巧

用set而非list进行查找

列表是一个有序的可重复元素的集合,它可以包含任意类型的对象。列表的实现通常使用动态数组,这意味着可以通过索引来快速访问元素。

集合是一个无序的不重复元素的集合,它只能包含可散列的对象(例如,数字、字符串等)。集合的实现通常使用哈希表或类似的数据结构,这使得它能够在O(1)的时间复杂度内查找元素。

由于集合使用哈希表实现,它可以在常数时间内(O(1))执行查找操作,而列表需要在最坏情况下遍历整个列表才能找到目标元素,其时间复杂度为O(n)。

集合是用来存储唯一元素的,所以在查找时,它不需要考虑是否有重复的元素,这也使得它在查找时更加高效。

list_d = [x**2 + 1 for x in range(1000000)]

set_d = (x**2 + 1 for x in range(1000000))

# 慢
1098987 in list_d

# 快
1098987 in set_d

用dict而非两个list进行匹配查找

看如下例子:

list_a = [2*i - 1 for i in range(1000000)]

list_b = [i**2 for i in list_a]

# 列表查找
print(list_b[list_a.index(876567)])

# 使用字典按照key查找
dict_ab = dict(zip(list_a, list_b))
print(dict_ab.get(876567, None))

与set同理,dict也是使用哈希表实现,也可以在常数时间内(O(1))执行查找操作。

优先使用for循环而不是while循环

示例:

import time


def time_cal(func):
    def wrapper():
        t1 = time.time()
        func()
        print(f"耗时:{time.time() - t1}")
    return wrapper


@time_cal
def func1():
    s = 0
    i = 0
    while s < 10000:
        s += 1
        i += 1


@time_cal
def func2():
    s = 0
    for i in range(10000):
        s += 1


if __name__ == "__main__":
    func1()
    func2()

结果如下:

耗时:0.0007779598236083984
耗时:0.00047516822814941406

循环代替递归

示例如下:

import time


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


def func1(n):
    # 斐波那契函数
    return (1 if n in (1, 2) else (func1(n-1) + func1(n-2)))


@time_cal
def func2(n):
    if n in (1, 2):
        return 1
    a, b = 1, 1
    for i in range(2, n):
        a, b = b, a + b
    return b


if __name__ == "__main__":
    t1 = time.time()
    func1(30)
    print(f"耗时:{time.time() - t1}")

    func2(30)

结果如下:

耗时:0.1676180362701416
耗时:7.867813110351562e-06

递归虽然简单,但是可能存在以下问题:

  • 在递归中,每次函数调用都会涉及到压栈和弹栈的操作,这会导致额外的开销。每次函数调用都需要保存当前函数的状态(包括局部变量、返回地址等),而循环则避免了这种开销。
  • 另外有最大的函数调用栈深度限制。当递归的深度超过这个限制时,会引发栈溢出错误。
  • 一些编译器可以对尾递归做出优化,将其转换为类似循环的形式,从而避免了递归的开销。
  • 在一些问题中,递归可能会导致重复计算,因为递归往往会反复调用相同的子问题,而迭代可以使用循环变量来避免这种情况。

用缓存机制加速递归函数

上面说到,递归可能会导致重复计算,会反复调用相同的子问题。可以使用缓存减少重复计算。

代码如下:

import time
from functools import lru_cache

@lru_cache(100)
def func1(n):
    # 斐波那契函数
    return (1 if n in (1, 2) else (func1(n-1) + func1(n-2)))


if __name__ == "__main__":
    t1 = time.time()
    func1(30)
    print(f"耗时:{time.time() - t1}")

执行时间如下:

耗时:1.3828277587890625e-05

可以看到时间明显少了几个数量级。

用numba加速Python函数

未加速的代码:

import time


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


def my_power(x):
    return x**2


@time_cal
def my_power_sum(n):
    s = 0
    for i in range(1, n+ 1):
        s += my_power(i)
    return s


if __name__ == "__main__":
    my_power_sum(1000000)

执行时间如下:

耗时:0.324674129486084

使用numba如下:

import time
from numba import jit


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


@jit
def my_power(x):
    return x**2


@time_cal
@jit
def my_power_sum(n):
    s = 0
    for i in range(1, n+ 1):
        s += my_power(i)
    return s


if __name__ == "__main__":
    my_power_sum(1000000)

执行时间:

耗时:0.25246715545654297

使用collections.Counter加速计数

示例如下:

import time
from collections import Counter


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


@time_cal
def func1(data):
    # 普通方法
    values_count = {}
    for i in data:
        i_count = values_count.get(i, 0)
        values_count[i] = i_count + 1
    print(values_count.get(4, 0))


@time_cal
def func2(data):
    # 加速方法
    values_count = Counter(data)
    print(values_count.get(4, 0))


if __name__ == "__main__":
    data = [x**2 % 1989 for x in range(2000000)]
    func1(data)
    func2(data)

运行结果如下:

8044
耗时:0.27747488021850586
8044
耗时:0.14070415496826172

使用collections.ChainMap加速字典合并

示例如下:

import time
from collections import ChainMap


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


@time_cal
def func1(dic_a, dic_b, dic_c, dic_d):
    # 普通方法
    res = dic_a.copy()
    res.update(dic_b)
    res.update(dic_c)
    res.update(dic_d)
    print(res.get(9999, 0))


@time_cal
def func2(dic_a, dic_b, dic_c, dic_d):
    # 加速方法
    chain = ChainMap(dic_a, dic_b, dic_c, dic_d)
    print(chain.get(9999, 0))


if __name__ == "__main__":
    dic_a = {i: i + 1 for i in range(1, 1000000, 2)}
    dic_b = {i: 2*i + 1 for i in range(1, 1000000, 3)}
    dic_c = {i: 3*i + 1 for i in range(1, 1000000, 5)}
    dic_d = {i: 4*i + 1 for i in range(1, 1000000, 7)}

    func1(dic_a, dic_b, dic_c, dic_d)
    func2(dic_a, dic_b, dic_c, dic_d)

运行结果如下:

10000
耗时:0.05382490158081055
10000
耗时:4.57763671875e-05

使用map代替推导式进行加速

示例如下:

import time


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


@time_cal
def func1():
    # 普通方法
    res = [x**2 for x in range(1, 1000000, 3)]


@time_cal
def func2():
    # 加速方法
    res = map(lambda x: x**2, range(1, 1000000, 3))


if __name__ == "__main__":
    func1()
    func2()

运行结果如下:

耗时:0.0947120189666748
耗时:1.0013580322265625e-05

使用filter代替推导式进行加速

示例如下:

import time


def time_cal(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        func(*args, **kwargs)
        print(f"耗时:{time.time() - t1}")
    return wrapper


@time_cal
def func1():
    # 普通方法
    res = [x**2 for x in range(1, 1000000, 3) if x % 7 == 0]


@time_cal
def func2():
    # 加速方法
    res = filter(lambda x: x%7 == 0, range(1, 1000000, 3))


if __name__ == "__main__":
    func1()
    func2()

运行如下:

耗时:0.03171205520629883
耗时:1.0013580322265625e-05

多线程加速IO密集型任务

低速方法
在这里插入图片描述高速方法
在这里插入图片描述

应用多进程加速CPU密集型任务

低速方法
在这里插入图片描述
高速方法
在这里插入图片描述

参考:
https://mp.weixin.qq.com/s/oF35_g4gdPeprHSvw4Mnyg

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python是一种简洁优雅且高效的编程语言,具有丰富的库和模块,同时也有一些技巧可以提高代码的效率。以下是一些Python高效写代码技巧: 1. 利用列表推导式:列表推导式是一种简洁且高效的创建列表的方法。它可以将多行代码简化为一行,并且能够同时对元素进行过滤、运算等操作。 2. 使用生成器表达式:生成器表达式是一种类似于列表推导式的方法,但它是一次生成一个元素,而不是一次生成一个完整的列表。这样可以节省内存空间。 3. 使用字典推导式:类似于列表推导式,字典推导式可以用于快速创建字典。可以通过遍历一个可迭代对象来生成键-值对。 4. 使用装饰器:装饰器是一种高级的Python功能,用于将函数或类进行装饰,以实现额外的功能或修改原有功能。装饰器可以提高代码的可读性和可维护性。 5. 使用生成器:生成器是一种特殊的迭代器,可以实现在循环逐个生成元素,而不是一次性生成所有元素。这样可以节省内存空间,并且提高代码的效率。 6. 使用内置函数和方法:Python提供了很多内置函数和方法,可以帮助我们快速且高效地处理数据。比如使用map()、filter()、sort()等函数,可以简化代码,提高效率。 7. 使用异常处理:合理使用异常处理可以帮助我们处理程序的错误和异常情况。通过捕获异常和提供适当的处理,可以避免程序崩溃或产生错误结果。 8. 使用模块和库:Python拥有丰富的模块和库,可以节省大量开发时间。通过引入并利用这些模块和库,可以实现复杂的功能,同时也加速了代码的开发过程。 以上是一些Python高效写代码技巧,不仅可以提高代码的效率,还能使代码更加清晰、易读和易维护。 随着不断的学习和实践,我们会发现更多的技巧来提升代码的质量和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ethan-running

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值