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 str类型怎么转换(Python3中的bytes和str类型详解)
- python算法图解(python实现kmp算法的实例代码)
- python弹跳小球(python GUI实现小球满屏乱跑效果)
- pythonselenium隐藏浏览器窗口(Python Selenium 之关闭窗口close与quit的方法)
- python直接查询mongodb(pymongo中聚合查询的使用方法)
- python多线程超时设置(解决python线程卡死的问题)
- python本地ocr库(详解Python安装tesserocr遇到的各种问题及解决办法)
- python中if的条件语句(浅谈Python的条件判断语句if/else语句)
- zabbix sender能否发送告警数据(python3实现zabbix告警推送钉钉的示例)
- python3知识点汇总(Python3几个常见问题的处理方法)
- python 多进程读取文件(Python实现的多进程拷贝文件并显示百分比功能示例)
- pythonnumpy定义一个2*2数组(对python numpy.array插入一行或一列的方法详解)
- python 多进程的启动和停止(Python3.5多进程原理与用法实例分析)
- 协程在python中怎么使用(python协程之动态添加任务的方法)
- python对象创建流程(Python3.5面向对象与继承图文实例详解)
- python类继承和封装(Python面向对象程序设计类的封装与继承用法示例)
- 销 售 买 卖 你真的了解这四个字了吗(销售买)
- 谢娜是得罪快乐大本营造型师了吗 全场被黑化(谢娜是得罪快乐大本营造型师了吗)
- 前《iLOOK》时装总监 《快乐大本营》御用造型师上线(快乐大本营御用造型师上线)
- 释小龙晒杀青照片 多重身份惹观众期待(释小龙晒杀青照片)
- 《九牛之人降魔传》开机 演员祁高坤化身九牛之人除魔卫道(九牛之人降魔传开机)
- 王铲铲的致富之路无限金币卡法攻略教学(王铲铲的致富之路无限金币卡法攻略教学)
热门推荐
- dockerfile 添加yum文件(使用YUM 安装 docker的方法步骤)
- 云服务器租用哪个好(云服务器租用价格受什么影响?)
- nodejs实现websocket服务端(Node.js+express+socket实现在线实时多人聊天室)
- fastdfs服务器集群(fastdfs+nginx集群搭建的实现)
- 怎样查看mysql的安装路径(MySQL中查看数据库安装路径的方法)
- laravel框架网站搭建教程(Laravel框架实现文件上传的方法分析)
- 织梦dedecms优化安全设置指南(DedeCms V5.5 性能优化方法分享)
- laravel count 报错(解决laravel5.5访问public报错的问题)
- laravel定时脚本(laravel实现按时间日期进行分组统计方法示例)
- python正则表达式入门(Python正则表达式实现简易计算器功能示例)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9