深入理解两个常用的Python技巧

本文探讨了Python中字符串连接的两种方法(循环+加法与join())的性能差异,以及为何集合在某些场景下优于列表。作者揭示了内存分配和数据结构对性能的影响,帮助读者理解何时选择哪种技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 引言

只需简单搜索一下,就很容易获得许多试图告诉我们关于 Python 技巧的文章。这些技巧要么更 “Pythonic”,要么能让我们的程序更快。这些文章并没有错,因为大多数技巧都非常有用。事实上,我自己也写过很多这类文章。

然而,这类文章经常受到批判,因为没有适用于所有情况的技巧。这也是事实。在我看来,更重要的是了解这些技巧存在的背后的原因,这样我们才能明白什么时候该用,什么时候不该用。

在这篇文章中,我将选取其中常见的两种技巧,并对其背后的机制进行详细解释。

2. 更快地连接字符串

通常如何将字符串连接在一起?我们来看一个字符串列表,如下:

strs = ['Life', 'is', 'short,', 'I', 'use', 'Python']

当然,最直观的方法是循环列表,并使用 + 运算符连接所有带空格的子串。
在这里插入图片描述

在上述代码中,我们只需定义一个空字符串,然后在该字符串上不断添加空格和列表中的子字符串。最后,我们返回从第 2 个字符开始的结果字符串,这样前导的空格就会被忽略。
不过,在这种情况下,我们有一个更好的方法来实现它。那就是使用 join() 函数,如下所示。
在这里插入图片描述

它不仅可读性更强,而且速度更快。请看下面的性能对比。
在这里插入图片描述

3. 原因分析

接下来我们来分析二者的具体执行步骤,首先来分析第一种方案:

● 每个for循环都会在列表中查找字符串
● Python 执行器遇到表达式 result += ' ' + s时,会并为空格 ' ' 申请一个内存地址。
● 然后,执行器意识到需要将空格与字符串连接起来,因此它将申请字符串 s 的内存地址,即第一个循环的 "Life"
● 对于每次循环,执行器都需要申请两次内存地址,一次是空格,另一次是字符串
● 共有 12 次内存分配

接下来,让我们看看使用 join() 函数的步骤。

● 执行器将计算列表中有多少个字符串。共有 6 个。
● 这意味着用于字符串列表中的连接字符串需要重复 6-1=5 次。
● 它知道总共需要 11 个内存空间,因此所有这些空间都将一次性预先分配。
● 按顺序排列字符串,并返回结果。

因此,显而易见,内存分配次数是上述技巧性能提升的主要原因。

4. 使用集合而非列表

ListPython 中非常常用。但是,你有没有想过,我们是否应该使用其他东西呢?我们知道 Python 中的 列表List 的元素是有顺序的,但如果顺序并不重要呢?例如,有时我们只需要知道一个元素是否存在,此时Python中的集合 Set 就能满足我们的要求。在这种情况下,集合set的性能会比列表list 好得多。

让我们定义一个具有完全相同元素的列表和集合。

my_list = list(range(100))
my_set = set(range(100))

如上,二者都有从 099100 个整数。唯一不同的是数据结构类型。现在,假设我们要检查数字 "99 "是否在容器中,并比较其性能。
在这里插入图片描述

可见,列表的性能会因需要扫描的范围不同而变化。在上面的示例中,如果我们要测试列表中是否有 "0",那么其性能将与集合相同。如果我们测试的是位于中间的 "50",性能就会变差。如果我们测试的是最后一个元素,则会比其他情况慢得多。另一方面,集合的性能往往相当稳定。无论我们测试哪个数字,其性能都不会有太大的变化。

5. 原因分析

简而言之,列表和集合的数据结构完全不同。PythonSet 使用哈希表实现,而 Python List 是典型的数组。
在这里插入图片描述

                                      图1: 建立哈希表

哈希表是什么样的?一般来说,数值会被送入一个哈希函数,这个哈希函数会将原始数值转换成另一个数值,而这个新的数值会被用作哈希表的索引。
在这里插入图片描述

                                             图2:   验证 "值 3 "是否存在

现在,让我们来看看 Python中的 List,它是一种数组类型的数据结构。列表中的元素以固定的顺序链接在一起。
在这里插入图片描述

                                             图3:   Python 列表中的值

因此,当我们寻找某个值时,它必须从列表的开头开始,逐个元素检查,直到找到目标时(如果不匹配,则到达结尾)。

在这里插入图片描述

                                             图4:   Python 列表查找过程

因此,最幸运的情况是第一个列表中第一个元素就是我们要找的,结果会立即返回。最糟糕的情况是,我们要找的元素是列表中的最后一项。这也解释了为什么当我们试图在列表中查找 0、50 和 99 时,性能会有所不同。

6. 总结

在本文中,我挑选了两种常见的 Python 技巧,并尽力解释了其背后的原因。它为什么有效,为什么性能更好。这也将帮助我们决定何时使用这些技巧,您学废了嘛?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

赵卓不凡

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

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

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

打赏作者

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

抵扣说明:

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

余额充值