数据结构
通过某种方式(例如对元素进行编号)组织在一起的数据元素的集合,这些数据元素可以是数字或者字符,甚至可以是其他数据结构
容器(container)
包含其他对象的任意对象。序列(例如列表和元组)和映射(字典)是两类主要容器
序列(sequence)
索引: 每个元素被分配的号,即元素的位置。每个元素都有自己的编号
>>>edward=['Edward Gumby', 42
>>>john=['John Smith', 50]
>>>database=[edward, john]
>>>database
[['Edward Gumby', 42],['John Smith', 50]]
-
索引(indexing)
正数从0开始, 倒数-1开始,字符串可以直接索引
>>>greeting='Hello'
>>>greeting[0]
'H'
>>>greeting[-1]
'o'
>>>'Hello'[1]
'e'
取用户输入的年份第4位
>>>fourth=raw_input('Year: ')[3]
Year: 2005
>>>fourth
'5'
练习: 要求输入年,月,日,打印相应日期连续格式,月份按单词。
#-*- coding:utf-8 –*-
# 根据给定的年月日打印相应的日期的月份名称
months=['January', 'February', 'March','April', 'June', 'July','August', 'September', 'October', 'November', 'December']
# 以1-31的数字作为结尾的列表
endings=['st','nd','rd']+ 17*['th']+['st','nd','rd']+7*['th']+['st']
year=raw_input('Year: ')
month=raw_input('Month (1-12): ')
day=raw_input('day(1-31) ')
month_number=int(month)
day_number=int(day)
#月份,日期减1,获得正确索引
month_name=months[month_number-1]
original=day+endings[day_number-1]
print month_name+' '+ original+' '+year
分片(sliceing)[起:终:步长]
分片操作需要提供两个索引作为便捷,第一个元素包含在分片内,第二个不包含。
10个数,1,2,3,4,5,6,7,8,9,10
取全部:[:] 1,2,3,4,5,6,7,8,9,10
取索引至5(不包括5):[:5] 1,2,3,4,5
取索引6起(包括6)后所有:[5:] 6,7,8,9,10
取索引6起(包括6)后所有(已知索引最后位才可用,索引为10的数不存在,不过也不用取,所以不影响):[5:10] 6,7,8,9,10
取索引1起至索引3(不包括3):[1:3] 1,2,3
取倒数第3个至第一个[-3, -1]:
步长不能为0,可以为负数。负数时表示从右往左提取,索引也反过来写
索引为8的至索引为3的[8:3:-1] : 9,7,6,5加(adding)
- 相同类型的序列,直接用
+
相加,变成一个序列 - 不相同类型的序列,不能相加
- 乘(multiplying)
用数字x乘一个序列,序列会生成一个将原来序列重复N次的新序列
常用初始化列表:
>>>sequence=[None]*10
练习: 其中书是box_width-2,我跑了发现不对,改成4.
#-*- coding:utf8 -*-
#以正确的宽度在居中的盒子内打印一句话
#注意,正数除法运算符//只能用在python 2.2以后版本,之前版本,只能用普通除法
sentence=raw_input("Sentence: ")
screen_width=80
text_width=len(sentence)
box_width=text_width+6
left_margin=(screen_width-box_width)//2
print
print ' '* left_margin+'+' +'-'* (box_width-4)+ '+'
print ' '* left_margin+'| '+' '* text_width + ' |'
print ' '* left_margin+'| '+ sentence + ' |'
print ' '* left_margin+'| '+' '* text_width + ' |'
print ' '* left_margin+'+' +'-'* (box_width-4)+ '+'
print
- 检查某个元素是否属于序列成员(查看权限,提供的用户名是否存在等安全策略, 垃圾邮箱过滤)
'信息' in 序列名
得到的结果是布尔值
>>>raw_input('Enter your user name: ') in users
Enter your user name:m1h
True
练习: 检查用户名和密码是否匹配
#-*- coding:utf8 -*-
#检查用户名和密码
database=[['albert', '1234'], ['dilbert','4242'],['smith','7524'],['jones','9843']]
username=raw_input('User name: ')
pin=raw_input('Pin code: ')
if[username, pin] in database: print 'Access granted'
- 计算序列长度
len(序列x) - 找到最大元素
max(序列x) - 最小元素
min(序列x) - 迭代
1. 列表list
可修改(mutable).
创建: x=[列表内容] 创建字符串列表可以直接 list('字符串') 会生成一个一个字符单个作为一个元素的列表。
' '.join(somelist)
修改: x[要修改的元素索引位置]=修改目标值
删除: del x[要删除的索引位置],会将列表变小。
分片赋值: 通过分片赋值可以达到批量修改(不局限列表长度),批量插入新元素(x[1:1]=[插入内容]), 删除元素(x[2:4]=[])
--------列表的方法:----
对象.方法(参数)
- append(元素) 在列表最末尾加上新元素,改变原list
- count(元素) 统计某个元素出现次数,返回次数
- extend(元素) 在列表末尾追加另一个序列的多个值,改变原list
- index(元素), 找到该元素的索引, 返回索引
- insert(要插入位置的索引, 要插入的元素):插入元素到目标索引,改变原list
- pop(为空是移除最后一个,或者填要移除的索引):移除list中最后一个或者索引对应元素,返回该被移除的元素,改变原list
数据结构:栈 (入栈,出栈)
用append()+pop()实现LIFO后进先出的队列
用insert(0,...)+pop()或者pop(0)+append()或者collection.deque实现FIFO先进先出队列 - remove(元素):移除第一个匹配项,无返回值,改变原list
8.reverse(空): 将列表中的元素反过来存放,改变原list,返回的是一个迭代器对应
9.sort(cmp, key, reverse):将列表排序。改变原list,返回值为None。key是依照排序的对象,比如按照元素长度排序,就key=len,reverse为布尔值,是否反响排序,填True 或者False.cmp同compare
sorted(x):将列表排序,不改变原list,输出排序后的list,故而如需保存需要赋值。该函数可用于任何可迭代对象
10.compare(x,y):高级排序,当x<y时,返回负数,x>y时,返回正数,x=y则返回0
x.sort().reverse() 不可行,因为sort()返回值为None
sorted(x).reverse() 可行
2. 元组tuple
不可修改
创建:(x,); x,; tuple()
映射
映射可以使用任何不可变对象标识元素,常见类型是字符串和元组,python唯一的内建映射就是字典。
键: 每个元素都有自己的名字,唯一
1.字典
适用于: 象征游戏棋盘的状态,每个键都是由坐标值组成的元组;存储文件修改次数,用文件名作为键;数字电话/地址簿
创建:{}
; dict([(键),(值)])
; dict(键名=键, 值名=值)
查看键-值数量:len(字典)
查值: 字典名[键]
关联(赋值): 字典[键]=值
删除某键及对应值: del 字典[键]
检查是否存在: 键 in 字典
练习 书里少了一行关于request定义。
#-*- coding=utf8 -*-
#简单数据库
#使用人名作为键的字典,每个人用另一个字典来表示,其键'phone'和'addr'分别表示他们的电话号码和地址
people={'Alice':{'phone':'2341','addr':'Foo drive 23'}, 'Beth':{'phone':'9102','addr':'Bar street 42'},
'Ceil':{'phone':'3158','addr':'Baz avenue 90'}}
#针对电话号码和地址是用的描述性标签,会在打印输出的时候用到
label={'phone':'phone number','addr':"address"}
name=raw_input('Name: ')
request=raw_input('Phone number(p) or address (a)?')
#查找电话号码还是地址? 使用正确的键
#使用正确的键
if request == 'p':key='phone'
if request == 'a':key="addr"
#如果姓名是字典中的有效键才打印
if name in people: print "%s's %s is %s" % (name,label[key],people[name][key])
方法:
- clear(为空): 清空字典,和sort一样,改变原字典,不返回值(或者说返回值为None)
- copy(为空):返回一个相同键-值的新字典,属于浅复制,大概就是在副本中替换值(比如用赋值),原始字典不受影响,但是如果在副本当中进行了修改(比如删除了某个值),原始字典里的也会进行同样的操作。
深复制: copy.deepcopy
>>>from copy import deepcopy
>>>d={}
>>>d['names']=['Alfred','Bertrand']
>>>c=d.copy()
>>>dc=deepcopy(d)
>>>d['names].append('Clive')
>>>c
{'names':['Alfred','Bertrand','Clive;]}
>>>d
{'names':['Alfred','Bertrand'}
- fromkeys(键列表,自定义默认值): 建立以提供的键列表为基础自定义默认值(不填就是None)的字典,返回创建字典。
{}.fromkeys(['names'.'age'])
;dict.fromkeys(['names'.'age'],'(unknown)')
- get(键,自定义键不存在时返回啥):访问字典项, 键不存在返回自定义的值(不填返回None),存在返回值。
练习 基于上面简单数据库加入get的应用,和格式化一起用,真的很方便,少打一万行字,深切感受到格式化的强大。这人怎么就这么聪明呢。
#-*- coding=utf8 -*-
#使用get()的简单数据库
#使用人名作为键的字典,每个人用另一个字典来表示,其键'phone'和'addr'分别表示他们的电话号码和地址
people={'Alice':{'phone':'2341','addr':'Foo drive 23'}, 'Beth':{'phone':'9102','addr':'Bar street 42'},
'Ceil':{'phone':'3158','addr':'Baz avenue 90'}}
#针对电话号码和地址是用的描述性标签,会在打印输出的时候用到
labels={'phone':'phone number','addr':"address"}
name=raw_input('Name: ')
#查找电话号码还是地址?
request=raw_input('Phone number(p) or address (a)?')
#使用正确的键
key=request #如果请求既不是p也不是a
if request == 'p':key='phone'
if request == 'a':key="addr"
#使用get()提供默认值
label=labels.get(key,key)
person=people.get(name,{})
result=person.get(key,'not available')
#如果姓名是字典中的有效键才打印
print "%s's %s is %s" % (name,label,result)
- has_key(键):检查是否有这个键,返回布尔值。3.0版没有这个函数!!!和 k in d一样的功能。
- items(为空)和iteritmes(为空):前者将字典以[(键,值),(键,值),(键,值)]的列表形式返回,无特殊顺序。后者作用一样,不过返回的是迭代器对象。
- keys和iterkeys:和上面一样,前后者区别也一样,不过是只显示键。
8.vales()和itervalues():和上面一样,前后者区别也一样,不过是只显示值。 - pop(键): 删除对应键-值,并且返回该键-值。
10.popitem(为空): 随机删除字典中的一项,在想实现不用获取键列表的前提下,一个个地移除并处理项时很实用。
11.setdefault(键盘,自定义默认值):在键存在时,返回键对应的目前值,键不存在时,增加键,并设定为默认值,默认值不填时默认None。 - update(更新内容字典): 用更新内容字典更新对象字典,新建会添加,相同建会覆盖对象字典原有值。