python基本数据结构(浅谈Python编程中3个常用的数据结构和算法)
python基本数据结构
浅谈Python编程中3个常用的数据结构和算法本篇文章将介绍3种常见的数据结构和同数据有关的算法。此外,在collections模块中也包含了针对各种数据结构的解决方案。
python内置了许多非常有用的数据结构,比如列表(list)、集合(set)以及字典(dictionary)。就绝大部分情况而言,我们可以直接使用这些数据结构。但是,通常我们还需要考虑比如搜索、排序、排列以及筛选等这一类常见的问题。
本篇文章将介绍3种常见的数据结构和同数据有关的算法。此外,在collections模块中也包含了针对各种数据结构的解决方案。
1. 将序列分解为单独的变量
(1) 问题
我们有一个包含 n 个元素的元组或序列,现在想将它分解为n个单独的变量。
(2) 解决方案
任何序列(或可迭代的对象)都可以通过一个简单的赋值操作来分解为单独的变量。唯一的要求是变量的总数和结构要与序列相吻合。例如:
|
>>> p = ( 4 , 5 ) >>> x, y = p >>> x 4 >>> y 5 >>> >>> data = [ 'acme' , 50 , 91.1 , ( 2012 , 12 , 21 ) ] >>> name, shares, price, date = data >>> name 'acme' >>> date ( 2012 , 12 , 21 ) >>> name, shares, price, (year, mon, day) = data >>> name 'acme' >>> year 2012 >>> mon 12 >>> day 21 >>> |
如果元素的数量不匹配,将得到一个错误提示。例如:
|
>>> p = ( 4 , 5 ) >>> x, y, z = p traceback (most recent call last): file "<stdin>" , line 1 , in <module> valueerror: need more than 2 values to unpack >>> |
(3) 讨论
实际上不仅仅只是元组或列表,只要对象恰好是可迭代的,那么就可以执行分解操作。这包括字符串、文件、迭代器以及生成器。比如:
|
>>> s = 'hello' >>> a, b, c, d, e = s >>> a 'h' >>> b 'e' >>> e 'o' >>> |
当做分解操作时,有时候可能想丢弃某些特定的值。python并没有提供特殊的语法来实现这一点,但是通常可以选一个用不到的变量名,以此来作为要丢弃的值的名称。例如:
|
>>> data = [ 'acme' , 50 , 91.1 , ( 2012 , 12 , 21 ) ] >>> _, shares, price, _ = data >>> shares 50 >>> price 91.1 >>> |
但是请确保选择的变量名没有在其他地方用到过。
2. 从任意长度的可迭代对象中分解元素
(1) 问题
需要从某个可迭代对象中分解出n个元素,但是这个可迭代对象的长度可能超过n,这会导致出现“分解的值过多(too many values to unpack)”的异常。
(2) 解决方案
python的“*表达式”可以用来解决这个问题。例如,假设开设了一门课程,并决定在期末的作业成绩中去掉第一个和最后一个,只对中间剩下的成绩做平均分统计。如果只有4个成绩,也许可以简单地将4个都分解出来,但是如果有24个呢?*表达式使这一切都变得简单:
|
def drop_first_last(grades): first, * middle, last = grades return avg(middle) |
另一个用例是假设有一些用户记录,记录由姓名和电子邮件地址组成,后面跟着任意数量的电话号码。则可以像这样分解记录:
|
>>> record = ( 'dave' , 'dave@example.com' , '773-555-1212' , '847-555-1212' ) >>> name, email, * phone_numbers = user_record >>> name 'dave' >>> email 'dave@example.com' >>> phone_numbers [ '773-555-1212' , '847-555-1212' ] >>> |
不管需要分解出多少个电话号码(甚至没有电话号码),变量phone_numbers都一直是列表,而这是毫无意义的。如此一来,对于任何用到了变量phone_numbers的代码都不必对它可能不是一个列表的情况负责,或者额外做任何形式的类型检查。
由*修饰的变量也可以位于列表的第一个位置。例如,比方说用一系列的值来代表公司过去8个季度的销售额。如果想对最近一个季度的销售额同前7个季度的平均值做比较,可以这么做:
|
* trailing_qtrs, current_qtr = sales_record trailing_avg = sum (trailing_qtrs) / len (trailing_qtrs) return avg_comparison(trailing_avg, current_qtr) |
从python解释器的角度来看,这个操作是这样的:
|
>>> * trailing, current = [ 10 , 8 , 7 , 1 , 9 , 5 , 10 , 3 ] >>> trailing [ 10 , 8 , 7 , 1 , 9 , 5 , 10 ] >>> current 3 |
(3) 讨论
对于分解未知或任意长度的可迭代对象,这种扩展的分解操作可谓是量身定做的工具。通常,这类可迭代对象中会有一些已知的组件或模式(例如,元素1之后的所有内容都是电话号码),利用*表达式分解可迭代对象使得开发者能够轻松利用这些模式,而不必在可迭代对象中做复杂花哨的操作才能得到相关的元素。
*式的语法在迭代一个变长的元组序列时尤其有用。例如,假设有一个带标记的元组序列:
|
records = [ ( 'foo' , 1 , 2 ), ( 'bar' , 'hello' ), ( 'foo' , 3 , 4 ), ] def do_foo(x, y): print ( 'foo' , x, y) def do_bar(s): print ( 'bar' , s) for tag, * args in records: if tag = = 'foo' : do_foo( * args) elif tag = = 'bar' : do_bar( * args) |
当和某些特定的字符串处理操作相结合,比如做拆分(splitting)操作时,这种*式的语法所支持的分解操作也非常有用。例如:
|
>>> line = 'nobody:*:-2:-2:unprivileged user:/var/empty:/usr/bin/false' >>> uname, * fields, homedir, sh = line.split( ':' ) >>> uname 'nobody' >>> homedir '/var/empty' >>> sh '/usr/bin/false' >>> |
有时候可能想分解出某些值然后丢弃它们。在分解的时候,不能只是指定一个单独的*,但是可以使用几个常用来表示待丢弃值的变量名,比如_或者ign(ignored)。例如:
|
>>> record = ( 'acme' , 50 , 123.45 , ( 12 , 18 , 2012 )) >>> name, * _, ( * _, year) = record >>> name 'acme' >>> year 2012 >>> |
*分解操作和各种函数式语言中的列表处理功能有着一定的相似性。例如,如果有一个列表,可以像下面这样轻松将其分解为头部和尾部:
|
>>> items = [ 1 , 10 , 7 , 4 , 5 , 9 ] >>> head, * tail = items >>> head 1 >>> tail [ 10 , 7 , 4 , 5 , 9 ] >>> |
在编写执行这类拆分功能的函数时,人们可以假设这是为了实现某种精巧的递归算法。例如:
|
>>> def sum (items): ... head, * tail = items ... return head + sum (tail) if tail else head ... >>> sum (items) 36 >>> |
但是请注意,递归真的不算是python的强项,这是因为其内在的递归限制所致。因此,最后一个例子在实践中没太大的意义,只不过是一点学术上的好奇罢了。
3. 保存最后n个元素
(1) 问题
我们希望在迭代或是其他形式的处理过程中对最后几项记录做一个有限的历史记录统计。
(2) 解决方案
保存有限的历史记录可算是collections.deque的完美应用场景了。例如,下面的代码对一系列文本行做简单的文本匹配操作,当发现有匹配时就输出当前的匹配行以及最后检查过的n行文本。
|
from collections import deque def search(lines, pattern, history = 5 ): previous_lines = deque(maxlen = history) for line in lines: if pattern in line: yield line, previous_lines previous_lines.append(line) # example use on a file if __name__ = = '__main__' : with open ( 'somefile.txt' ) as f: for line, prevlines in search(f, 'python' , 5 ): for pline in prevlines: print (pline, end = '') print (line, end = '') print ( '-' * 20 ) |
(3) 讨论
如同上面的代码片段中所做的一样,当编写搜索某项记录的代码时,通常会用到含有yield关键字的生成器函数。这将处理搜索过程的代码和使用搜索结果的代码成功解耦开来。如果对生成器还不熟悉,请参见4.3节。
deque(maxlen=n)创建了一个固定长度的队列。当有新记录加入而队列已满时会自动移除最老的那条记录。例如:
|
>>> q = deque(maxlen = 3 ) >>> q.append( 1 ) >>> q.append( 2 ) >>> q.append( 3 ) >>> q deque([ 1 , 2 , 3 ], maxlen = 3 ) >>> q.append( 4 ) >>> q deque([ 2 , 3 , 4 ], maxlen = 3 ) >>> q.append( 5 ) >>> q deque([ 3 , 4 , 5 ], maxlen = 3 ) |
尽管可以在列表上手动完成这样的操作(append、del),但队列这种解决方案要优雅得多,运行速度也快得多。
更普遍的是,当需要一个简单的队列结构时,deque可祝你一臂之力。如果不指定队列的大小,也就得到了一个无界限的队列,可以在两端执行添加和弹出操作,例如:
|
>>> q = deque() >>> q.append( 1 ) >>> q.append( 2 ) >>> q.append( 3 ) >>> q deque([ 1 , 2 , 3 ]) >>> q.appendleft( 4 ) >>> q deque([ 4 , 1 , 2 , 3 ]) >>> q.pop() 3 >>> q deque([ 4 , 1 , 2 ]) >>> q.popleft() 4 |
从队列两端添加或弹出元素的复杂度都是o(1)。这和列表不同,当从列表的头部插入或移除元素时,列表的复杂度为o(n)。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持开心学习网。
原文链接:https://blog.csdn.net/w17688977481/article/details/89355856
- python群聊提示(python-itchat 统计微信群、好友数量,及原始消息数据的实例)
- python爬虫入门自学(自学python爬虫的建议和周期预算)
- python菜单栏中常用的菜单(Python3实现的简单三级菜单功能示例)
- python 写入d盘文件(python文件写入write的操作)
- python爬取微博登录数据(Python实现爬取马云的微博功能示例)
- python3.5 tkinter教程(解决python3.5 正常安装 却不能直接使用Tkinter包的问题)
- python表白代码演示(python3实现表白神器)
- python中什么是迭代器(一篇文章彻底搞懂Python中可迭代Iterable、迭代器Iterator与生成器Generator的概)
- python3简单编程(Python3.5面向对象编程图文与实例详解)
- python电脑端微信自动化(python使用wxpy实现微信消息防撤回脚本)
- python怎么测试api接口(python接口自动化测试之接口数据依赖的实现方法)
- python爬网验证码在哪里(详解python 爬取12306验证码)
- 微信昵称python(Python 微信之获取好友昵称并制作wordcloud的实例)
- python协程详解(为什么你还不懂得怎么使用Python协程)
- centos8配置python开发环境(CentOS6.9 Python环境配置python2.7、pip、virtualenv)
- python3常用内建函数(Python3中函数参数传递方式实例详解)
- 四月新番CP人气榜公布,《剃须》两度上榜,沙优不是女朋友(四月新番CP人气榜公布)
- 2019年外媒秋季新番动画角色CP排行榜,桐人和爱丽丝落榜(2019年外媒秋季新番动画角色CP排行榜)
- 新一小兰领衔 盘点动漫中的那些 远距离恋爱情侣(盘点动漫中的那些)
- 大事件 合肥四中火了(大事件合肥四中火了)
- 翼龙贷组织出借人调研 感受鄱阳 借 来的致富路(翼龙贷组织出借人调研)
- 2023新国风戏曲教育寒假集训班汇报演出《戏娃闹元宵》图文报道(2023新国风戏曲教育寒假集训班汇报演出戏娃闹元宵图文报道)
热门推荐
- C#泛型List的用法
- easyui datebox的用法
- laravel5.2模型返回数组(解决Laravel5.5下的toArray问题)
- apache漏洞怎么排查(apache urlrewrite防盗链功能配置)
- 云服务器备案吗(免备案云服务器与国内云服务器有什么不同?)
- js条件语句教学(浅谈JS如何写出漂亮的条件表达式)
- 用mysql语句写python学生管理系统(Python基于mysql实现学生管理系统)
- 云服务存储空间不足(云服务器内存资源不足解决方案)
- 微信小程序开发如何实现自动保存(微信小程序开发实用技巧之数据传递和存储)
- vue移动端页面不能上下滑动(vue移动端实现左滑编辑与删除的全过程)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9