简介

Python 的序列(sequence)通常指一个可迭代的容器,容器中可以存放任意类型的元素。列表和元组这两种数据类型是最常被用到的序列,python内建序列有六种,除了刚刚有说过的两种类型之外,还有字符串、Unicode字符串、buffer对像和最后一种xrange对像,这几种都是不常使用的。本文讲解了列表推导式、切片命名、列表元素排序、列表元素分组的使用方法。学习了 Python 基本的列表操作后,学习这些进阶的操作,让我们写出的代码更加优雅简洁和 pythonic 。

列表推导式

当我们想要根据某些规则来构造一个列表时,首先想到的应该是列表推导式。列表推导式简化了循环操作,例如我们想要从一个原始文件名列表中获取全部 .py 文件,在没有列表推导式的情况下,我们通常会这样做:

file_list = ['foo.py', 'bar.txt', 'spam.py', 'animal.png', 'test.py']

py_list = []

for file in file_list:

if file.endswith('.py'):

py_list.append(file)

print(py_list)

# output

['foo.py', 'spam.py', 'test.py']

而如果使用列表推导式则可简化为:

py_list = [f for f in file_list if f.endswith('.py')]

print(py_list)

# output

['foo.py', 'spam.py', 'test.py']

列表推导式的介绍网上资源很多,不再赘述。这里只强调,当你需要根据某个规则来构造一个列表时,首先应该想一想,能否使用简洁的列表推导式来实现该需求,否则再回到常规的方式。

为切片命名

Python 的列表切片使用起来非常方便,但有时也会影响代码可读性。例如有一个字符串:

record = '..........19.6..........100..........'

19.6 为产品价格,100 为产品数量,那么计算总价格为:

但是如果这样写,可能过一段时间我们再来读代码时已经忘记了 record[10:14]、record[24:27]切出来的究竟是什么?为了解决上述问题,可以给切片命个名来增强可读性。

record = '..........19.6..........100..........'

price = slice(10, 14)

count = slice(24, 27)

total_price = float(record[price])*int(record[count])

slice 接收的参数格式为 slice(stop) 、slice(start, stop[, step])。如果只接收了一个参数,则等价于切片语法 [:stop] ,如果接收两个参数,则等价于切片语法 [start:stop] ,如果接收三个参数,则等价于切片语法 [start:stop:step] 。

排序

排序相关的任务通常由内置函数 sorted 完成。需要排序的元素一般存放在一个列表容器中,列表可以存放任意类型的元素,而 sorted 函数的 key 关键字使得我们能够轻松地指定元素排序的关键字,让排序变得异常简单。下面将给出几个常见的排序例子以说明 key 关键字的使用方法。注意 Python3 和 Python2 的排序方法不能通用,下面的例子只适用于 Python3 ,Python2 的排序方法未包含在本文中。

情况一

列表中的元素已经是可比较元素,直接将列表传入 sorted 函数即可返回一个已排序列表。默认为升序排列,降序排列可以指定 reverse 参数,例如:

>>> l = [3,5,4,1,8]

>>> sorted(l)

[1, 3, 4, 5, 8]

>>> sorted(l, reverse=True)

[8, 5, 4, 3, 1]

>>>

情况二

需要排序的元素是一个元组或者字典,希望根据我指定的关键字来排序,例如有如下两个列表:

l_v1 = [('b',2),('a',1),('c',3),('d',4)]

l_v2 = [

{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},

{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},

{'fname': 'John', 'lname': 'Cleese', 'uid': 1001},

{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}

]

l_v1 是一个元组列表, l_v2 是一个字典列表。对 l_v1 我们希望根据元组中第二个元素来排序,对 l_v2 我们希望根据字典的关键字 uid 进行排序。

sorted 函数接收一个关键字参数 key ,该参数指定一个可调用函数,函数返回一个值(只要是可比较的),那么 sorted 函数将根据返回的关键字对列表中的元素进行排序。

例如对上面的例子:

>>> l_v1 = [('b',2),('a',1),('c',3),('d',4)]

>>> sorted(l_v1, key=lambda x: x[1])

[('a', 1), ('b', 2), ('c', 3), ('d', 4)]

>>> l_v2 = [

{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},

{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},

{'fname': 'John', 'lname': 'Cleese', 'uid': 1001},

{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}

]

>>> sorted(l_v2, key=lambda x: x['uid'])

[{'lname': 'Cleese', 'uid': 1001, 'fname': 'John'}, {'lname': 'Beazley', 'uid': 1002, 'fname': 'David'}, {'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'}, {'lname': 'Jones', 'uid': 1004, 'fname': 'Big'}]

这里 lambda 函数是一个常用的技巧。lambda 关键字后边的 x 是该函数接收的参数,冒号后边的表达式是该函数的返回值。对 l_v1 来说,传递给参数 x 的就是每一个元组,其返回元组的第二个元素用于排序;对 l_v2 来说,传递给参数 x 的就是列表中的每一个字典元素,其返回字典中 uid 对应的值用于排序。

除了使用匿名函数 lambda 这种通用的方法外,Python 标准库 operator 为我们提供了一个 itemgetter 函数替代我们写的 lambda 函数,且其性能会比使用 lambda 函数略有提升。

>>> from operator import itemgetter

>>> l_v1 = [('b',2),('a',1),('c',3),('d',4)]

>>> sorted(l_v1, key=itemgetter(1))

[('a', 1), ('b', 2), ('c', 3), ('d', 4)]

>>> l_v2 = [

{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},

{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},

{'fname': 'John', 'lname': 'Cleese', 'uid': 1001},

{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}

]

>>> sorted(l_v2, key=itemgetter('uid'))

[

{'lname': 'Cleese', 'uid': 1001, 'fname': 'John'},

{'lname': 'Beazley', 'uid': 1002, 'fname': 'David'},

{'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'},

{'lname': 'Jones', 'uid': 1004, 'fname': 'Big'}

]

以上例子均是返回一个单一的值用于排序关键字,前面说过,关键字 key 接收的函数可以返回任意的可比较对象。例如在 python 中,元组是可以比较的。对元组的比较规则为首先比较元组中第一个位置上的元素,如果相等,在比较第二个位置上的元素,依次类推。回到 l_v2 的例子,假设现在需求变了,我们首先对 lname 对应的值排序,如果 lname 对应的值相等,那么再根据 fname 确定其顺序。

>>> l_v2 = [

{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},

{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},

{'fname': 'John', 'lname': 'Cleese', 'uid': 1001},

{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}

]

>>> sorted(l_v2, key=lambda x: (x['lname'], x['fname']))

[

{'lname': 'Beazley', 'uid': 1002, 'fname': 'David'},

{'lname': 'Cleese', 'uid': 1001, 'fname': 'John'},

{'lname': 'Jones', 'uid': 1004, 'fname': 'Big'},

{'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'}

]

这个例子中,lambda 函数返回的不再是一个标量值,而是一个元组 (x['lname'], x['fname']) ,根据元组的比较规则,首先根据元组的第一个位置上的元素x['lname'] 的大小排序,由于列表中有两个字典其 lname 对应的值都为 Jones,因此再根据元组第二个位置的元素 x['fname']的值排序,由于 Big 比 Brian 要小(按字母顺序依次比较),所以 Big 排在了前面。

同样使用 itemgetter 函数也是可以的,且性能会略有提升。此外我觉得 itemgetter 比 lambda 更加简洁和可读一点。

>>> l_v2 = [

{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},

{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},

{'fname': 'John', 'lname': 'Cleese', 'uid': 1001},

{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}

]

>>> sorted(l_v2, key=itemgetter('lname', 'fname'))

[

{'lname': 'Beazley', 'uid': 1002, 'fname': 'David'},

{'lname': 'Cleese', 'uid': 1001, 'fname': 'John'},

{'lname': 'Jones', 'uid': 1004, 'fname': 'Big'},

{'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'}

]

情况三

需要排序的元素是一个 Python 对象,我们希望根据其某个属性值来排序。例如一个存放 User 对象的列表如下,根据其 name 属性排序:

class User:

def __init__(self, name):

self.name = name

def __str__(self):

return 'User: %s' % self.name

__repr__ = __str__ # 为了能够让 User 在解释器中显示为 'User: name' 的格式

user_list = [User('John'), User('David'), User('Big'), User('Alen')]

方法与前面的一样,定义一个函数返回 User 的 name 属性的值,把该函数传给 sorted 的 key 参数。

>>> user_list = [User('John'), User('David'), User('Big'), User('Alen')]

>>> sorted(user_list, key=lambda x: x.name)

>>> sorted(user_list, key=lambda x: x.name)

[User: Alen, User: Big, User: David, User: John]

但是,itemgetter 方法不再起作用,取而代之的是 attrgetter 方法。

>>> sorted(user_list, key=attrgetter('name'))

[User: Alen, User: Big, User: David, User: John]

attrgetter 与 itemgetter 用法完全一致,只是 itemgetter 用于获取某个位置索引或者字典关键字的取值,而 attrgetter 用于获取对象的属性值。

PS:sorted 返回的是原始列表的一个已排序的副本,而原始列表的顺序并没有任何变化。如果你只想就地排序(即排序原始列表本身),则直接调用 list 的 sort 方法即可:list.sort() 。其用法与 sorted 函数一样,只是该函数没有返回值,调用后原始列表已变为一个已排序列表。

对序列中的元素进行分组

和排序类似,现想根据列表中元素的某个关键字分组,使关键字相同的元素分到同一组,并可以对分好的组进行进一步处理。例如有如下的一个列表:

rows = [

{'address': '5412 N CLARK', 'date': '07/01/2012'},

{'address': '5148 N CLARK', 'date': '07/04/2012'},

{'address': '5800 E 58TH', 'date': '07/02/2012'},

{'address': '2122 N CLARK', 'date': '07/03/2012'},

{'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'},

{'address': '1060 W ADDISON', 'date': '07/02/2012'},

{'address': '4801 N BROADWAY', 'date': '07/01/2012'},

{'address': '1039 W GRANVILLE', 'date': '07/04/2012'},

]

列表的元素为字典,现想根据字典的 date 分组,使日期( date )相同的元素分到一个组。Python 的 itertools 模块中的 groupby 函数可以很好地解决该问题。为了使用 groupby 函数,首先需要对列表排序:

>>> from operator import itemgetter

>>> sorted_rows = sorted(rows, key=itemgetter('date'))

groupby 也和 sorted 一样有一个 key 关键字参数,其接收一个可调用函数,该函数返回的值被用做分组的关键字,其用法和 sorted 的 key 关键字参数一样 。

>>> for date, items in groupby(sorted_rows, key=itemgetter('date')):

print(date)

for i in items:

print(' ', i)

07/01/2012

{'address': '5412 N CLARK', 'date': '07/01/2012'}

{'address': '4801 N BROADWAY', 'date': '07/01/2012'}

07/02/2012

{'address': '5800 E 58TH', 'date': '07/02/2012'}

{'address': '5645 N RAVENSWOOD', 'date': '07/02/2012'}

{'address': '1060 W ADDISON', 'date': '07/02/2012'}

07/03/2012

{'address': '2122 N CLARK', 'date': '07/03/2012'}

07/04/2012

{'address': '5148 N CLARK', 'date': '07/04/2012'}

{'address': '1039 W GRANVILLE', 'date': '07/04/2012'}

可以看到 groupby 返回的值分别是用于分组的关键字对应的值和该组的全部成员。groupby 实际返回一个生成器,通过迭代即可分别对各组进行处理。值得注意的一点是,分组前对列表排序这一步必不可少,否则对于非紧邻的元素即使其值相同也会被分在不同组。

总结

以上就是关于python序列进阶篇的全部内容,希望本文的内容对大家学习或者使用python能有所帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

python如何进阶提升_Python序列操作之进阶篇相关推荐

  1. python自动化常用模块_Python自动化 【第五篇】:Python基础-常用模块

    目录 模块介绍 time和datetime模块 random os sys shutil json和pickle shelve xml处理 yaml处理 configparser hashlib re ...

  2. python如何进阶提升_python快速进阶3-提高pip install速度

    pip install命令默认是用的是python官方源,由于一些客观原因,连接速度很慢,甚至超时中断,到时很多模块安装不上,甚是苦恼! 怎么办? 使用国内镜像源,将以下命令完成拷贝出来,粘贴至记事本 ...

  3. python延时us函数_Python延时操作实现方法示例

    本文实例讲述了Python延时操作实现方法.分享给大家供大家参考,具体如下: 在日常的开发中,往往会遇到这样的需求,需要某一个函数在一段时间之后才执行以达到某种特定的效果.此时,我们就需要某种机制,使 ...

  4. python元祖用法_Python序列(列表list和元组tuple)用法完全攻略

    所谓序列,指的是一种包含多项数据的数据结构,序列包含的多个数据项(也叫成员)按顺序排列,可通过索引来访问成员. Python 的常见序列类型包括字符串.列表和元组.前一章介绍过的字符串,其实就是一种常 ...

  5. python 循环实现延时_Python延时操作实现方法示例

    本文实例讲述了Python延时操作实现方法.分享给大家供大家参考,具体如下: 在日常的开发中,往往会遇到这样的需求,需要某一个函数在一段时间之后才执行以达到某种特定的效果.此时,我们就需要某种机制,使 ...

  6. python的sqlite3示例_Python简单操作sqlite3的方法示例

    让Python更加充分的使用Sqlite3 我最近在涉及大量数据处理的项目中频繁使用 sqlite3.我最初的尝试根本不涉及任何数据库,所有的数据都将保存在内存中,包括字典查找.迭代和条件等查询.这很 ...

  7. python如何查询数据库_Python数据库操作手册-数据库专栏,SQL Server

    数据库的操作在现在的python里面已经变得十分的好用,有了一套api标准.下面的就是讲讲如何的去使用这套框架定义.此框架包含以下部分模块接口 连接对象 游标对象 dbi辅助对象 数据类型与定义 如何 ...

  8. python画切片图_python切片操作

    序列类型是其元素被顺序放置的一种数据结构类型,这种方式允许通过下标的方式来获得某一个数据元素,或者通过指定下标范围来获得一组序列的元素.这种访问序列的方式叫做切片.字符串也可以使用切片操作.切片操作符 ...

  9. python文本文档_python 文本文件操作

    文件操作三步走:打开.读写.关闭. open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, close ...

最新文章

  1. 学习,是前进的必由之路
  2. Linux 高性能服务器编程——socket选项
  3. getpeername函数与getsockname函数的介绍
  4. 从C10K到C10M高性能网络的探索与实践
  5. intellij导入文件夹后各种红色cannot resolve symbol
  6. LeetCode 1430. 判断给定的序列是否是二叉树从根到叶的路径(递归)
  7. java对象的浅克隆和深克隆
  8. 从Qt的图片文件传输来看Qt 中UDP的收发消息writeDatagram和readDatagram
  9. [原创]消灭eclipse中运行启动的错误:“找不到或无法加载主类”问题
  10. V模型、W模型、测试工具的介绍
  11. Git下载连接远程仓库
  12. Python模拟登陆古诗文网手动输入验证码显示验证码错误
  13. 浏览器窗口通信的多种方式
  14. 这个季节有离别——观《Sad Movie》有感
  15. Win11筛选键怎么关闭?Win11关闭筛选键的两种方法
  16. Error:Apostrophe not preceded by \ (
  17. win11提示找不到gpedit.msc命令
  18. 快捷指令通知运行html,快捷指令怎样运行这段,一个书签
  19. ffmpeg h264指南
  20. win10如何设置锁屏时间

热门文章

  1. [微信小程序直播平台开发]___(一)介绍与流程
  2. javase基础第三天
  3. VMware Data Recovery备份恢复vmware虚拟机
  4. 《使用Nessus进行渗透测试》- 简介
  5. DataGridView常见用法和FAQ汇总
  6. 知识图谱资源-NLP
  7. Go 导入当前项目下的包
  8. WebConfig 加密解密的原理是什么?
  9. 数字签名时间戳服务器的原理 !
  10. 23种基本设计模式简介