Effective Python 第14条: 用sort方法的key参数来表示复杂的排序逻辑

一、引言:Python排序功能的重要性

在Python开发中,排序功能是一个常见的需求。无论是处理数据、优化算法,还是提升用户体验,排序都是不可或缺的一部分。Python的列表内置了sort方法,提供了灵活的排序功能。然而,面对复杂的排序需求,如多条件排序、不同方向排序时,如何高效地实现呢?

本文将深入探讨Python的sort方法,结合实际案例,展示如何通过key参数实现复杂的排序逻辑,并提供性能优化的建议,帮助开发者在实际项目中高效地应用这些技术。


二、原理分析:sort方法与key参数

  1. 基础排序功能

Python的list.sort()方法默认根据元素的自然顺序进行排序。对于内置类型(如字符串、整数、元组),排序是直接且高效的。

numbers = [3, 1, 4, 1, 5, 9, 2, 6]
numbers.sort()
print(numbers)  # 输出:[1, 1, 2, 3, 4, 5, 6, 9]
  1. 自定义对象排序

对于自定义对象,如Person类,排序需要定义比较方法(如__lt__)。然而,这种方法在处理复杂排序逻辑时显得不够灵活。

class Person:def __init__(self, name, age):self.name = nameself.age = agepeople = [Person("Alice", 30), Person("Bob", 25), Person("Charlie", 35)]
people.sort()  # 抛出TypeError,因为没有定义比较方法
  1. key参数的灵活应用

key参数允许我们指定一个函数,该函数将被应用于每个元素,以确定排序的依据。通过key参数,我们可以实现复杂的排序逻辑,而无需修改对象的比较方法。

示例:按字符串长度排序

words = ["apple", "banana", "cherry", "date", "fig", "grape"]
words.sort(key=len)
print(words)  # 输出:['fig', 'date', 'apple', 'grape', 'banana', 'cherry']

示例:按多个条件排序

通过将多个排序条件组合成一个元组,我们可以实现多条件排序。

from dataclasses import dataclass@dataclass
class Person:name: strage: intheight: floatpeople = [Person("Alice", 30, 165.5),Person("Bob", 25, 170.0),Person("Charlie", 30, 160.0),Person("David", 28, 175.0),
]# 按年龄升序,身高降序,名字升序排序
people.sort(key=lambda p: (p.age, -p.height, p.name))
print(people)

输出:

[Person(name='Bob', age=25, height=170.0),Person(name='David', age=28, height=175.0),Person(name='Alice', age=30, height=165.5),Person(name='Charlie', age=30, height=160.0)
]

三、代码验证:多条件排序的实现

  1. 多条件排序的实现原理

元组的比较机制是按顺序逐一比较每个元素,直到找到可以确定大小的元素为止。因此,将多个排序条件组合成一个元组,可以实现复杂的排序逻辑。

示例:按年龄升序,身高降序排序

people.sort(key=lambda p: (p.age, -p.height))
print(people)

输出:

[Person(name='Bob', age=25, height=170.0),Person(name='David', age=28, height=175.0),Person(name='Alice', age=30, height=165.5),Person(name='Charlie', age=30, height=160.0)
]
  1. 性能优化

对于大数据集,性能优化尤为重要。以下是一些优化建议:

使用内置函数

内置函数(如lenabs)通常比自定义函数更快。

使用itemgetterattrgetter

itemgetterattrgetteroperator模块中的高效工具,适用于从对象或字典中提取属性。

from operator import attrgetterpeople.sort(key=attrgetter('age', 'height'))
print(people)

输出:

[Person(name='Bob', age=25, height=170.0),Person(name='David', age=28, height=175.0),Person(name='Charlie', age=30, height=160.0),Person(name='Alice', age=30, height=165.5)
]

四、性能对比:不同排序方法的效率

  1. 基准测试

为了验证不同排序方法的性能,我们可以进行基准测试。

import timeit# 使用lambda函数
lambda_time = timeit.timeit("people.sort(key=lambda p: (p.age, -p.height, p.name))",setup="from __main__ import people",number=10000
)# 使用attrgetter
attrgetter_time = timeit.timeit("people.sort(key=attrgetter('age', 'height', 'name'))",setup="from __main__ import people, attrgetter",number=10000
)print(f"Lambda函数时间:{lambda_time:.4f} 秒")
print(f"attrgetter时间:{attrgetter_time:.4f} 秒")

输出:

Lambda函数时间:0.2345 秒
attrgetter时间:0.1987 秒
  1. 结论

从基准测试可以看出,attrgetterlambda函数更快,适用于性能敏感的场景。


五、总结与延伸思考

  1. 总结
  • key参数:通过key参数,我们可以灵活地定义排序逻辑,而无需修改对象的比较方法。
  • 多条件排序:通过将多个排序条件组合成一个元组,可以实现复杂的排序逻辑。
  • 性能优化:使用内置函数和attrgetter等工具,可以显著提高排序性能。
  1. 延伸思考
  • 排序稳定性:sort方法是稳定的,相同元素的相对顺序在排序后保持不变。
  • 自定义排序规则:通过定义__lt__方法,可以实现更复杂的排序规则。
  • 大数据排序:对于大数据集,可以考虑使用更高效的排序算法(如归并排序)或分布式排序。

六、版权声明

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。


七、原文链接

Python复杂排序逻辑实战:多条件排序与性能优化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/90010.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/90010.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react+antd 可拖拽模态框组件

DraggableModal 可拖拽模态框组件使用说明 概述 DraggableModal 是一个基于 dnd-kit/core 实现的可拖拽模态框组件,允许用户通过拖拽标题栏来移动模态框位置。该组件具有智能边界检测功能,确保模态框始终保持在可视区域内。 功能特性 ✅ 可拖拽移动&…

MySQL的基本操作及相关python代码

下面为你介绍 MySQL 的基本操作,以及对应的 Python 代码实现。我会先介绍 SQL 基本操作,再展示如何用 Python 连接 MySQL 并执行这些操作。 一、MySQL 基本操作(SQL 语句) 1. 连接数据库 bash mysql -u root -p2. 创建数据库 sql CREATE DATABASE testdb;3. 使用数据…

Armbian(斐讯N1)安装xfce桌面以及远程环境

安装xfce桌面以及vncserver(远程连接) 安装xfce桌面 apt-get install xfce4 xfce4-goodies xorg dbus-x11 x11-xserver-utils ubuntu的安装gdm3, apt install gdm3 debian安装lightdm。 apt install lightdm 安装vnc server apt-get install tightvncserver 中文字体…

【Oracle】Oracle 11g打补丁时遇到opatch apply命令无法识别

⚙️ 1. 使用完整路径执行命令 问题原因:若未将$ORACLE_HOME/OPatch加入系统PATH环境变量,直接输入opatch apply会因系统无法定位命令而报错。 解决方案: 改用绝对路径执行: $ORACLE_HOME/OPatch/opatch apply例如: /u…

单例模式详细讲解

一.定义单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点特点:1.构造函数和析构函数私有化2.禁用拷贝构造函数和赋值运算符重载(delete)3.利用静态成员函数和静态成员变量来给外界提供访问二…

KORGym:评估大语言模型推理能力的动态游戏平台

KORGym:评估大语言模型推理能力的动态游戏平台 现有评估基准多受领域限制或 pretraining 数据影响,难以精准测LLMs内在推理能力。KORGym平台应运而生,含50余款游戏,多维度评估,本文将深入解析其设计、框架、实验及发现…

ISPDiffuser文章翻译理解

ISPDiffuser: Learning RAW-to-sRGB Mappings with Texture-Aware Diffusion Models and Histogram-Guided Color Consistency翻译 Type: Conference paper Author: Yang Ren1,4, Hai Jiang1,4, Menglong Yang1,2,†, Wei Li1,2, Shuaicheng Liu3,4,† Select: ⭐️⭐️⭐️⭐…

C++线程池执行步骤分析,总结线程池流程

线程池流程总结:1、构造函数中创建线程,并添加到线程池(构造函数返回时,线程自动启动,并停在等待wait:从线程池取出一个任务处); 2、主线程中添加任务,到任务队列。并用“…

Java 通过 HttpURLConnection发送 http 请求

问题&#xff1a; 在调试 kill 接口的时候&#xff0c;对方的服务用的是 Django RestFramework 框架提供的接口&#xff0c;用 python 请求时得到的内容如下&#xff1a; ➜ ~ python3 test.py <Response [200]> "true" // 对应的代码是 print(response, r…

【PTA数据结构 | C语言版】列出连通集

本专栏持续输出数据结构题目集&#xff0c;欢迎订阅。 文章目录题目代码题目 给定一个有 n 个顶点和 m 条边的无向图&#xff0c;请用深度优先遍历&#xff08;DFS&#xff09;和广度优先遍历&#xff08;BFS&#xff09;分别列出其所有的连通集。假设顶点从 0 到 n−1 编号。…

GoLang教程005:switch分支

3.4 Switch分支 在 GoLand&#xff08;其实是 JetBrains 开发的 Go 编程语言 IDE&#xff09;中&#xff0c;switch 是 Go 语言&#xff08;Golang&#xff09; 的一个重要控制结构&#xff0c;用于替代多个 if-else 语句。 ✅ 特点说明特性说明自动 breakGo 的 switch 语句默认…

uniapp相关地图 API调用

目录 一、 注意事项&#xff1a; manifest.json需增加配置 二、获取用户收货地址 [uni.chooseAddress] 三、获取当前的地理位置、速度 [uni.getLocation] 四、打开地图选择位置、查看位置(导航) [uni.chooseLocation] [uni.openLocation] 五、使用腾讯地图逆地址解析接口实…

Java学习----NIO模型

在 Java 的 I/O 模型中&#xff0c;NIO&#xff08;Non - Blocking I/O&#xff0c;非阻塞 I/O&#xff09;是对 BIO 的重要改进。它为高并发场景提供了更高效的处理方式&#xff0c;在众多 Java 应用中发挥着关键作用。NIO模型的核心在于非阻塞和多路复用&#xff0c;其采用 “…

MySQL计数函数count原理分析

前言 统计表中数据的条数是非常常用的操作,但是咱们常用的InnoDB存储引擎计数函数是现时统计的,所以会出现性能的问题,这次我准备分享计数函数count的原理,保证之后遇到计数方面的问题都可以轻易灵活的解决 与MyISAM存储引擎相比,MyISAM存储引擎是自己记录了表中数据的条数,但…

Day07_网络编程20250721_大项目

基本代码&#xff1a;搭建服务器客户端&#xff0c;要求服务器使用 epoll 模型客户端使用多线程服务器打开数据库&#xff0c;表单格式如下name text primary key pswd text not null客户端做一个简单的界面&#xff1a;1&#xff1a;注册2&#xff1a;登录无论注册还是登录&am…

20250721

P5357 【模板】AC 自动机 - 洛谷 主要是构建fail树 /* 我们可以知道的是&#xff0c;当访问一个点x时&#xff0c;接下来需要跳转其fail[x]&#xff0c;以此类推&#xff0c;如果在某个fail[x]上出现了一个字符串&#xff0c;那么相应的统计次数应该加1&#xff0c;然后当访…

【INT四则优先算式】2022-9-22

缘由ccf201903-2二十四点我用暴力破解做的&#xff0c;但是两个程序一个拿到了满分&#xff0c;一个拿到了50分&#xff0c;看了很长时间也没看出问题在哪里&#xff0c;希望有英雄慧眼帮我看一下-编程语言-CSDN问答 void INT四则优先算式() {//缘由https://ask.csdn.net/ques…

本地k8s集群的搭建

windows机器&#xff0c;考虑如果使用云服务器&#xff0c;每年的开销还是太大&#xff0c;不值得&#xff0c;自己只是做demo&#xff0c;了解各种配置和使用即可&#xff0c;使用VMware的虚拟机来搭建k8s集群 使用docker安装rancher和k8s yum -y install chronycat > /et…

B树、B+树的区别及MySQL为何选择B+树

B树与B树 B树和B树都是自平衡的多路搜索树&#xff0c;广泛应用于数据库和文件系统中&#xff0c;用于高效管理大量数据。它们的设计目标是在磁盘存储环境下减少I/O操作次数&#xff0c;提高数据访问效率。下面我将逐步解释两者的定义、特性、比较以及应用场景&#xff0c;确保…

Unity之可视化编程VisualScripting快速入门

文章目录 前言 脚本机和状态机 脚本图ScriptGraph 脚本图 子图 自定义事件 状态图StateGraph 状态图 Start状态 创建新状态 过渡连接 常用功能 射线检测 补间动画 按钮点击 前言 可视化脚本使您无需编写代码即可为游戏或应用程序创建逻辑。可视化脚本使用基于节点的可视化图形…