Python 集合比列表快得多,对吗?

原文:towardsdatascience.com/python-set-is-way-faster-than-list-true-or-false-042c6f8975cd

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4b79e9e630ef9b8e2b14c7bc20892abe.png

由作者在 Canva 中创建

几周前,我写了一篇另一篇文章来解释一些流行的“Python 小技巧”背后的机制和逻辑。其中之一是在可能的情况下使用 Python 集合而不是列表。

许多文章告诉你 Python 小技巧,但很少告诉你为什么

在这篇文章变得流行之后,许多读者向我提问或争论说 Python 集合并不总是很快。这是绝对正确的。因此,我决定写这篇文章,深入探讨 Python 列表和集合的数据结构。

在这篇文章中,我将首先使用实际代码在不同场景下比较 Python 列表和集合的性能。然后,我将介绍它们使用的几种数据结构,即动态数组和哈希表。基于这些数据结构的特性,我将解释为什么 Python 列表或集合在某些场景下具有更好的性能。

1. 性能

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/923080f13f88cf877bdf17e4b364fd9f.png

由作者在 Canva 中创建

让我们从性能实验开始。不能说 Python 集合的性能总是比 Python 列表高。我们需要考虑不同的场景,例如创建查找追加删除

使用 Jupyter Notebook 进行这项测试要方便得多。因此,我们可以使用 %timeit 魔法命令来轻松评估经过的时间。

创建 – 列表胜出(快 2 倍)

要测试创建性能,我们可以简单地使用 range(10000) 来生成 10,000 个数字。请注意,这是一个生成器,但我们可以从这个生成器创建一个列表或一个集合。

# Create list for 100 times%timeit -n 100 my_list =list(range(10000))# Create set for 100 times%timeit -n 100 my_set =set(range(10000))

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/06ee37fe73a2bd810e951a222c6a822a.png

可以看到,创建集合所需的时间大约是创建列表的两倍。这是因为集合的数据结构比列表消耗更多的时间和空间。这一点将在下一节中讨论。

查找 – 集合胜出(快 1000 倍)

在我们能够测试查找性能和后续测试用例之前,我们需要正确地创建一个列表和一个集合。除此之外,我们还需要一些数字用于测试目的。例如,我们需要一个数字用于在列表和集合中查找。让我们生成 1,000 个这样的数字,这应该足够了。

import random # Creat a list and a set my_list =list(range(10000)) my_set =set(my_list)# Random 1000 numbers for testing purpose test_numbers = random.sample(range(10000),1000)

现在,我们可以使用以下代码在 Jupyter Notebook 中测试查找性能。

%timeit -n 100for num in test_numbers: num in my_list %timeit -n 100for num in test_numbers: num in my_set 

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a09aab35f303ce777149e8fff8009264.png

由于 1ms = 1000μs,Python 集合的查找性能比 Python 列表快 1000 倍。

追加 – 列表胜出(快 0.2 倍)

现在,让我们测试追加。我们需要另一个测试数字数据集,因为我们的集合是从 1 到 10,000 的数字创建的。我们当前的测试数字是从同一范围内随机选择的,用于测试查找性能。然而,我们需要测试范围之外的数字。否则,我们对集合没有影响,因为我们不能在集合中追加重复的项。

# Random 1000 numbers from 10,000 to avoid duplicates in the set test_numbers = random.sample(range(10000,20000),1000)# Insertion into list%timeit -n 100for num in test_numbers: my_list_copy.append(num)# Insertion into set%timeit -n 100for num in test_numbers: my_set_copy.add(num)

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/14d78b86845e968b255639cc568a628b.png

这次列表赢了,但不是很多,只快了 0.2 倍。可以说性能即将相同。

删除 – 集合胜出(快 800 倍)

要测试删除性能,我们需要我们的原始测试数字,因为我们需要删除在列表和集合中存在的数字。

# Create the test numbers again test_numbers = random.sample(range(10000),1000)# Deletion from list%timeit -n 100for num in test_numbers: my_list.remove(num)if num in my_list elseNone# Deletion from set%timeit -n 100for num in test_numbers: my_set.discard(num)

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a1ac755e0b2c8befbe04d52ad52b7308.png

这次 Python 集合再次获胜,大约快 800 倍。这是因为删除操作与查找有点相似。数字需要在列表或集合中找到,然后才能删除。

然而,集合的性能并不像查找那样快,查找的速度快了 1000 倍。原因是从列表中删除一个项比从集合中删除要容易一些。

现在,我们已经清楚不同场景下的性能比较。让我们谈谈原因。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8030a8c7f4baf334b4ec1b585b4e08bb.png

由作者在 Canva 中创建

2. 列表与集合 – 数据结构比较

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/f785b76b5730aa0e810efe225a4d0d38.png

由作者在 Canva 中创建

Python 列表和集合的数据结构是动态数组哈希表。它们之间的差异导致了性能比较的结果。

对于其余的比较,尽管它们是动态数组和哈希表之间的比较,我仍然会使用 Python 列表和 Python 集合来使其简单且具有上下文。

2.1 结构

Python 列表利用连续的内存块。Python 列表中的项是相邻存储的。因此,它的结构非常紧凑和有效。

值得注意的是,列表的索引不需要显式存储。相反,当我们使用索引访问列表中的项时,索引将用作输入来计算内存位置。一个简单的例子是,如果我们需要访问第 5 个项,内存位置将是 _5 * item_length_inbytes

Python 集合将为所有其项创建一个哈希表。所有项都将有哈希键,这些键将使用特定的哈希函数计算得出。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/5f8f49fb7ab50438d59ed2918d6ec39a.png

作者创建的图片

因此,当我们从集合中查找特定项时,哈希函数可以帮助使用哈希函数将项转换为键,然后使用键直接在 O(1)时间内找到该项。

查找和删除性能

这就是为什么在集合中查找一个项目比在列表中查找要快得多。同样,要删除一个项目,主要动作是定位该项目。因此,在集合中删除一个项目的性能也比列表要快得多。

创建性能

也因为结构的原因,构建哈希表比分配一块连续内存要昂贵。因此,创建列表的性能略快。

2.2 调整大小

当一个Python 列表增长时,需要分配一个新的内存块,并且一些内部指针需要更新,但通常这不是一个昂贵的操作。

当一个Python 集合增长时,所有现有的项目都需要重新哈希。这意味着“字典”需要被重建。

追加性能

这就是为什么在列表中追加或插入项目比在集合中要快一点。因为重新哈希通常需要更多时间,尤其是在有大量项目的情况下。

摘要

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/0cccd8b086cb77bf3d922d53cedcaabf.png

由作者在 Canva 中创建

在这篇文章中,我们比较了 Python 列表和集合在不同场景下的性能。我们已经看到,在某些场景中,Python 列表甚至可以比 Python 集合更快。然而,需要强调的是,当 Python 集合的性能更好时,它通常要快数千倍,而反过来,Python 列表在其他场景中只能稍微快一点。

希望这篇文章能够满足您的一些好奇心,并帮助您在编码时做出决定!

Read more

将现有 REST API 转换为 MCP Server工具 -higress

将现有 REST API 转换为 MCP Server工具 -higress

Higress 是一款云原生 API 网关,集成了流量网关、微服务网关、安全网关和 AI 网关的功能。 它基于 Istio 和 Envoy 开发,支持使用 Go/Rust/JS 等语言编写 Wasm 插件。 提供了数十个通用插件和开箱即用的控制台。 Higress AI 网关支持多种 AI 服务提供商,如 OpenAI、DeepSeek、通义千问等,并具备令牌限流、消费者鉴权、WAF 防护、语义缓存等功能。 MCP Server 插件配置 higress 功能说明 * mcp-server 插件基于 Model Context Protocol (MCP),专为 AI 助手设计,

By Ne0inhk
MCP 工具速成:npx vs. uvx 全流程安装指南

MCP 工具速成:npx vs. uvx 全流程安装指南

在现代 AI 开发中,Model Context Protocol(MCP)允许通过外部进程扩展模型能力,而 npx(Node.js 生态)和 uvx(Python 生态)则是两种即装即用的客户端工具,帮助你快速下载并运行 MCP 服务器或工具包,无需全局安装。本文将从原理和对比入手,提供面向 Windows、macOS、Linux 的详细安装、验证及使用示例,确保你能在本地或 CI/CD 流程中无缝集成 MCP 服务器。 1. 工具简介 1.1 npx(Node.js/npm) npx 是 npm CLI(≥v5.2.0)

By Ne0inhk
解锁Dify与MySQL的深度融合:MCP魔法开启数据新旅程

解锁Dify与MySQL的深度融合:MCP魔法开启数据新旅程

文章目录 * 解锁Dify与MySQL的深度融合:MCP魔法开启数据新旅程 * 引言:技术融合的奇妙开篇 * 认识主角:Dify、MCP 与 MySQL * (一)Dify:大语言模型应用开发利器 * (二)MCP:连接的桥梁 * (三)MySQL:经典数据库 * 准备工作:搭建融合舞台 * (一)环境搭建 * (二)安装与配置 Dify * (三)安装与配置 MySQL * 关键步骤:Dify 与 MySQL 的牵手过程 * (一)安装必要插件 * (二)配置 MCP SSE * (三)创建 Dify 工作流 * (四)配置 Agent 策略 * (五)搭建MCP

By Ne0inhk
如何在Cursor中使用MCP服务

如何在Cursor中使用MCP服务

前言 随着AI编程助手的普及,越来越多开发者选择在Cursor等智能IDE中进行高效开发。Cursor不仅支持代码补全、智能搜索,还能通过MCP(Multi-Cloud Platform)服务,轻松调用如高德地图API、数据库等多种外部服务,实现数据采集、处理和自动化办公。 本文以“北京一日游自动化攻略”为例,详细讲解如何在 Cursor 中使用 MCP 服务,完成数据采集、数据库操作、文件生成和前端页面展示的全流程。 学习视频:cursor中使用MCP服务 一、什么是MCP服务? MCP(Multi-Cloud Platform)是Cursor内置的多云服务接口,支持调用地图、数据库、文件系统等多种API。通过MCP,开发者无需手动写HTTP请求或繁琐配置,只需在对话中描述需求,AI助手即可自动调用相关服务,极大提升开发效率。 二、环境准备 2.1 cursor Cursor重置机器码-解决Too many free trials. 2.

By Ne0inhk