赞
踩
列表List、元组Tuple和字典Dictionary——很重要的三个类型,还有一个类似于dict的集合set
一、list列表
list是ython内置的一种数据类型,list是一种有序的集合,可以随时添加和删除其中的元素。就是说,list是可以修改的。
定义:classmates = ['zhangsan', 'lisi', 'Bob','wangwu']
用中括号[],其中以逗号分隔各个元素。classmates就是一个list变量了。
对list可以进行增删改查操作。
查list中元素的个数,用len()函数,print(len(classmates)),结果为4。
1、取元素:取列表list中的一个元素,可以直接使用中括号中加索引的方法,即classmates[2] ,取的是第三个元素,即Bob,用索引来访问list中每一个位置的元素,索引是从0
开始的。索引超出了范围时,Python会报一个IndexError
错误,所以,要确保索引不要越界。最后一个元素的索引是len(classmates) - 1
。
按索引取列表中元素,是从左到右的顺序,最左边元素,即索引为0开始,依次加1,直到len()-1,还有一种方法是从右到左的取元素的方法,最右边的元素用-1表示,即列表list的最后一个元素用-1表示,向左依次为-2,-3,一直到-len()。
2、查询列表list中的一个元素
查询一个元素是否在list中,可以有两种思路:一种是查看这个元素在list中的索引是否在范围内,如果在,证明元素在list中存在,使用listvar.index()方法;另一种是查询元素在list中的个数,如果是1或超过1,说明存在,超过1,说明list中有重复的元素出现,使用listvar.count()。是通过内容查询。listvar代表list变量。
3、list中增加一个元素:有追加和插入两种
追加,就是在list最后增加一个元素,使用listvar.append(),插入,就是在 指定索引处插入一个元素,原来的这个索引位置及以后的所有元素也自动后移一位,使用listvar.insert()。
append()只有一个参数,即插入的内容,insert()有两个参数,第一个是索引号,即插入的位置信息,第二个是插入的内容。
测试两个方法的返回值,结果都为None,说明没有返回值,对于insert(),如果第一个参数,即索引值在0~len()-1范围,按前面的规则插入,如果第一个参数大于等于len,全部是在最后增加元素,相当于append()。
insert的第一个参数也可用负整数表示:注意的是用负数无法在最后插入元素,当第一个参数的绝对值大于列表长度,都是是第一个位置,即列表头插入。
注意,list是一个有序表,就是各个元素在list中的位置是固定的,象上面的例子,lisi的前面就是zhangsan,后面就是Bob,不管查询几遍都是这个结果,插入的元素只要不涉及这三个元素,他们的位置都是固定的,这就是一种有序。相对应的还有一种是无序表。
还有一种增加是listvar.extend(),叫扩展,扩展一个列表,将一个列表追加到另一个列表后。
扩展是在一个list后面进行,相当于将a2的元素按顺序一个一个append()到a1中。a1扩展后其值改变了。而a1 + a2,其返回结果与a1扩展后相同,但是a1和a2值不变,是形成了新的量。
为什么第一个判断是False呢???
4、list删除一个元素
可以使用.remove(x)、.pop(i)、.clear()、del listvar[i]等方法
remove()删除list中匹配参数内容的元素,没有返回值。并且,如果list中有重复的元素。remove()只删除索引最小的那一个。如果删除的内容不在list中,报错。
pop()参数是索引值,删除指定索引位置的元素,并且,他有返回值,就是刚删除的元素。pop的参数索引值必须在list长度范围内,越界则报错,pop可以不带参数,删除最后一个元素。
所以,使用append()和pop()可以模拟栈操作,入栈和出栈。
clear()不带参数,清空所有元素。没有返回值。
del是一条命令,他可以删除一个变量,即将变量从内存中删除,相当于变量没有定义了,也可以删除list中的一个元素:
5、修改list元素值
直接listvar[i] = "xxx",就将索引第i个元素修改了。
不能修改不存在的元素,即索引(或叫做下标)不能越界
同样索引可以使用负数形式:
6、排序
sort()和reverse()方法list.
sort
(key=None, reverse=False) :对列表中的元素进行排序
sort()不带参数,就是按照ascii表的编码来进行比较数字小于字母,大写字母小于小写字母。reverse参数,指定排好序的列表是否翻转,默认就是False,不翻转,按照ascii表顺序,如果为True,表示翻转,也就是按照ascii表的反序排序。key参数很复杂,可以指定一个函数,用来处理每个元素,list按照函数处理后的结果排序。如上例中使用了str.upper,就是将字符串变为大写再进行比较排序。
reverse()方法,翻转列表中的元素。
单纯的对list进行翻转,跟sort()的reverse参数意义一样,如果要对排序后的list进行翻转,完全可以用
listvar.sort()
listvar.reverse()
这两步代替。
7、高级特性
1)切片
对列表list进行操作时,通常不会是单个元素的操作,一般会涉及多个,就是对list的一个子集进行操作。如取list中的几个元素。如aa = [10,20,30,40],取前三个元素
需要一个一个取,如果list很大,取得元素很多,这种办法基本就不能使用了。
这里注意,使用中括号将三个元素括起来,又形成一个list,如果只是用逗号分隔,形成了一个tuple,即元组,单个元素,是元素的类型。
当然可以使用循环,来一个一个取list中的元素。
对这种经常取指定索引范围的操作,Python提供了切片(Slice)操作符,能大大简化这种操作。切片,很贴切的词语,把一个list切成任意的一片一片的,片有大有小,都是list的子集。切片操作符,使用冒号:
对应上面的问题,取前3个元素,用一行代码就可以完成切片:
aa[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。如果第一个索引是0,还可以省略:写成aa[:3]。也可以从索引1开始,取出2个元素出来;还可以从某个索引位置开始,直到list的最后。类似的,既然Python支持L[-1]取倒数第一个元素,那么它同样支持倒数切片。记住倒数第一个元素的索引是-1。能否将索引的顺序颠倒一下呢?
通过一系列的测试,得出如下一些结论:其一,连续取数时,中括号是左闭右开,即包括左面,不包括右面,如[1:3],就是从1开始,包括1,到3,不包括3,实际就是到2,即aa[1]、aa[2],也就是取的个数是3-1=2个元素;其二,切片的写法,即冒号前后必须索引值,不管是用正数表示,还是用负数表示,必须是左小右大,如-2小于-1,否则取出的是空值;其三,按照二的规则,那么取数也就是从左到右取数,不会乱序;其四,从头开始,即从0开始,以及取到最后一个元素,这两个都可以省略不写,如aa[:],代表所有元素。
切片还可以有一个步长参数,上面的是默认的步长,即步长1。写法是list[起始索引:终止索引:步长]
如果加上步长参数,则上面总结的结论就不适用了,索引可以左大右小,但是这时步长必须是负的。这时就是反序取数了。
字符串'xxx'也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串:
>>> 'ABCDEFG'[:3]
'ABC'
>>> 'ABCDEFG'[::2]
'ACEG'
在很多编程语言中,针对字符串提供了很多各种截取函数(例如,substring),其实目的就是对字符串切片。Python没有针对字符串的截取函数,只需要切片一个操作就可以完成,非常简单。
可以使用切片取数,就可以使用切片改数据:
2)list元素
list中的元素可以是任何数据,即可以是list,这就是list中有list
第一步aa的长度是3,因为[1,2]是作为aa的一个元素。对list中list,可以与list一样进行操作。
Python中,一切皆是对象,上面中变量后面跟一个点然后跟函数,就是对象函数的使用方法,对象有函数(也叫方法)和属性,使用的方式都是变量名加点形式使用。
还有一些,如len(),是python的内建函数,都在buildins.py模块中,启动python时自动加载。
python中所有的变量存储都是对象的地址,list中的元素,在list中存储的也是元素的地址。如下图
地址的大小一般是固定的,所以,当我们修改listvar中元素的内容时,理论上listvar的大小应该不变,变的只是其中的地址值(也叫指针值)
测试:sys模块中有一个getsizeof()函数,可以得到变量的内存大小:
通过上面的测试,可以看到,只要是修改元素,不管修改(不能增删)的内容变化多么大,listvar的内存大小都不变。
二、元组tuple
元组的定义,与list列表类似,也是一种有序列表,tuple一旦初始化就不能修改。元组tuple相当于只读列表list,即只能读取,不能修改。
tuplevar = (10,20,‘asd’)
定义元组tuple使用小括号,列表是中括号。定义元组tuple时只有一个元素时,最好后面加一个逗号,如:tuplevar = (12,)
可以看到,如果一个元素的tuple,元素后没有加逗号,他不会解释成元组。
初始化时,也可以不用加小括号,直接用逗号分隔就行。
一个特殊的问题是构造包含0个或1个元素的元组:为了适应这种情况,语法有一些额外的改变。空元组可以直接被一对空圆括号创建,含有一个元素的元组可以通过在这个元素后添加一个逗号来构建(圆括号里只有一个值的话不够明确)。
语句 t = 12345, 54321, 'hello!' 是 元组打包 :值 12345, 54321 和 'hello!' 被打包进元组。其逆操作也是允许的
>>> x, y, z = t
这被称为 序列解包 ,因为解包操作的等号右侧可以是任何序列。序列解包要求等号左侧的变量数与右侧序列里所含的元素数相同。注意多重赋值其实也只是元组打包和序列解包的组合。
tuple的取值操作与切片操作,与list相同:
“可变的”tuple:
- >>> t = ('a', 'b', ['A', 'B'])
- >>> t[2][0] = 'X'
- >>> t[2][1] = 'Y'
- >>> t
- ('a', 'b', ['X', 'Y'])
这个tuple定义的时候有3个元素,分别是'a'
,'b'
和一个list。不是说tuple一旦定义后就不可变了吗?怎么后来又变了?
别急,我们先看看定义的时候tuple包含的3个元素:
当我们把list的元素'A'
和'B'
修改为'X'
和'Y'
后,tuple变为:
表面上看,tuple的元素确实变了,但其实变的不是tuple的元素,而是list的元素。tuple一开始指向的list并没有改成别的list,所以,tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。即指向'a'
,就不能改成指向'b'
,指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的!
理解了“指向不变”后,要创建一个内容也不变的tuple怎么做?那就必须保证tuple的每一个元素本身也不能变。
这里要知道,tuple中存储的也是地址(指针)。
根据内容查索引。
虽然元组可能看起来与列表很像,但它们通常是在不同的场景被使用,并且有着不同的用途。元组是 immutable ,其序列通常包含不同种类的元素,并且通过解包(这一节下面会解释)或者索引来访问(如果是 namedtuples
的话甚至还可以通过属性访问)。列表是 mutable ,并且列表中的元素一般是同种类型的,并且通过迭代访问。
immutable -- 不可变:具有固定值的对象。不可变对象包括数字、字符串和元组。这样的对象不能被改变。如果必须存储一个不同的值,则必须创建新的对象。它们在需要常量哈希值的地方起着重要作用,例如作为字典中的键。
mutable -- 可变:可变对象可以在其 id()
保持固定的情况下改变其取值。
named tuple -- 具名元组:术语“具名元组”可用于任何继承自元组,并且其中的可索引元素还能使用名称属性来访问的类型或类。 这样的类型或类还可能拥有其他特性。
一个例子是 sys.float_info
:
>>> sys.float_info[1] # indexed access 1024 >>> sys.float_info.max_exp # named field access 1024 >>> isinstance(sys.float_info, tuple) # kind of tuple True
三、字典dictionary
Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。字典是映射类型,采用键值对(key-value)形式存储。字典是无序存储的,对key进行哈希运算,根据结果决定value的存储地址。Key必须是可哈希的,key必须是不可变类型,即为immutable。
字典的定义,使用大括号(或叫花括号):
字典在其他语言里可能会被叫做 联合内存 或 联合数组。与以连续整数为索引的序列(list和tuple)不同,字典是以 关键字 为索引的,关键字可以是任意不可变类型,通常是字符串或数字。如果一个元组只包含字符串、数字或元组,那么这个元组也可以用作关键字。但如果元组直接或间接地包含了可变对象,那么它就不能用作关键字。列表不能用作关键字,因为列表可以通过索引、切片或 append()
和 extend()
之类的方法来改变。
通过上面的测试,不可变类型主要有整型、浮点型、字符串、元组,布尔型,可变类型有列表和字典。作为字典的key,可以是不可变型数据,但是元组比较特殊,在元组的元素中不能有可变类型,否则 不能做key。
理解字典的最好方式,就是将它看做是一个 键: 值 对的集合,键必须是唯一的(在一个字典中)。一对花括号可以创建一个空字典:{}
。另一种初始化字典的方式是在一对花括号里放置一些以逗号分隔的键值对,而这也是字典输出的方式。
字典的操作:
通过关键字取值:
字典的查找速度是非常快的,原因是因为dict的实现原理和查字典是一样的。假设字典包含了1万个汉字,我们要查某一个字,一个办法是把字典从第一页往后翻,直到找到我们想要的字为止,这种方法就是在list中查找元素的方法,list越大,查找越慢。
第二种方法是先在字典的索引表里(比如部首表)查这个字对应的页码,然后直接翻到该页,找到这个字。无论找哪个字,这种查找速度都非常快,不会随着字典大小的增加而变慢。
dict就是第二种实现方式,给定一个名字,比如'abcd'字符串
,dict在内部就可以直接计算出'abcd'
对应的存放其值的“页码”,也就是string
这个字符串存放的内存地址,直接取出来,所以速度非常快。
你可以猜到,这种key-value存储方式,在放进去的时候,必须根据key算出value的存放位置,这样,取的时候才能根据key直接拿到value。这就是为什么字典的key必须是不可变类型,因为不可变类型才能进行哈希计算。
修改值:
增加数据:除了初始化时指定外,还可以通过key放入
通过与上面修改值进行对比,可以看出:如果key在字典中存在,那就是修改,如果key在字典中不存在,那就是增加。所以,字典中的key是唯一的,不会存在重复的现象,而list与tuple中是可以存在重复值的。
还有一种方法:字典自身的setdefault()方法:
可见。setdefault()方法是:如果不能存在key,就 在字典中增加相应的键值对,返回新增加的键值对的值,如果字典中已经存在key了,则不作改变,返回已有键值对的值。
可以使用字典自身的update()方法,使用来自 other 的键/值对更新字典,覆盖原有的键。 返回 None
列出key:使用list()函数,对一个字典执行 list(d)
将返回包含该字典中所有键的列表,按插入次序排列
list()的结果是一个list
使用字典自身的keys()和values()方法,返回字典的key和value的列表
排序:按照key进行排序
可以看到,sorted要求可以的类型一致。
删除数据:使用del,这个命令也可以删除list中的元素
如果删除时指定的key不存在,就会报错。通过对象本身的pop()方法删除一个键值对,返回了值,为刚删除的键值对的值数据。当key类型一致时,进行排序,sorted()成功。
因为如果key不存在,删除或查找就会出错,所以可以先判断key是否存在,这可以使用in,或者字典自身的get()方法。
通过第二步测试,in操作是在key中进行的,不会查找value,即值域中的内容,相当于‘xxx’ in list(dic2),在key的列表中查找。
get()方法,如果存在对应的key,返回key对应的value,如果不存在key,默认返回None,可以自己加第二个参数,指定不存在key时返回的值。
上面是一个很有意思的测试,当要修改字典中的某个键的值时,改成None是不成功的,存在的key,值为None,相当于不做修改,但是,可以增加一个值为None的键值对。这时判断key是否存在时肯定要出现混乱,不存在,返回None,存在,也有可能是None。对于get()的第二个参数,实际编程中一定要仔细考虑其取值,就是一定不能在键值对中的值域中出现。
返回None的时候Python的交互环境不显示结果。
使用字典自身的clear()方法,清空字典:
dict内部存放的顺序和key放入的顺序是没有关系的。
和list比较,dict有以下几个特点:
而list相反:
所以,dict是用空间来换取时间的一种方法。
dict可以用在需要高速查找的很多地方,在Python代码中几乎无处不在,正确使用dict非常重要,需要牢记的第一条就是dict的key必须是不可变对象。
这是因为dict根据key来计算value的存储位置,如果每次计算相同的key得出的结果不同,那dict内部就完全混乱了。这个通过key计算位置的算法称为哈希算法(Hash)。
要保证hash的正确性,作为key的对象就不能变。在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。而list是可变的,就不能作为key。
字典dict好像只能通过key进行操作,没有切片操作
四、集合set
set和dict类似,是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。要创建一个set,需要提供一个list作为输入集合。
集合是由不重复元素组成的无序的集。它的基本用法包括成员检测和消除重复元素。集合对象也支持像 联合,交集,差集,对称差分等数学运算。
花括号或 set()
函数可以用来创建集合。注意:要创建一个空集合你只能用 set()
而不能用 {}
,因为后者是创建一个空字典
key中有重复的,直接消除了。同时,输入的顺序与显示的顺序是不同的。
通过add(key)方法可以添加元素到set中,可以重复添加,但不会有效果,通过remove(key)方法可以删除元素,set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的交集、并集等操作:
set和dict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象,因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素”。试试把list放入set,看看是否会报错。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。