第三章-内建数据结构、函数及文件
内建数据结构、函数及文件
数据结构和序列
元组
是一种固定长度、不可变的python对象序列。最简单的方法就是用逗号分隔序列值
a = (4,5,6), (7,8)
a
((4, 5, 6), (7, 8))
也可以使用tuple函数将任意序列或迭代器转换为元组
tuple([4,0,2])
(4, 0, 2)
如果元组中的一个对象是可变的,例如列表,你可以在它内部进行修改
元组拆包
如果想要将元组型的表达式赋值给变量,python会对等号右边的值进行拆包
tup = 4,5,6
a, b, c = tup
a
4
拆包常用于遍历元组或列表组成的序列
In [1]: seq = ([1,2,3],[4,5,6],[7,8,9])
In [2]: for a,b,c in seq:
...: print('a={0},b={1},c={2}'.format(a,b,c))
...:
a=1,b=2,c=3
a=4,b=5,c=6
a=7,b=8,c=9
*rest /有人用 *_ 来表示不想要的变量名
列表
与元组不同,列表的长度是可以改变的,它所包含的内容也是可以修改的。可以使用中括号或者list定义列表
增加和移除元素
append加到尾部
insert插入到指定的列表位置
a_list.append('black')
a_list.insert(1,'red')
insert 的反操作是pop 。 元素也可以通过remove方法移除,该方法会定位第一个符合要求的值并移除
In [3]: a = ['1','2','3','1','4']
In [4]: a.remove('1')
In [5]: a
Out[5]: ['2', '3', '1', '4']
连接和联合列表
两个列表可以用+号连接
如果已有列表,可以使用extend 方法添加多个元素
extend比 for循环中的 +=添加要快
排序
sort方法是针对列表内部进行排序,无须新建一个对象
sort 其中一项可以传递一个二级排序key——一个用于生成排序值的函数
而sorted方法可以针对通用序列产生一个排序后的拷贝
二分搜索和已排序列表的维护
内建的bisect模块实现了二分搜索和已排序列表的插值
bisect.bisect 方法会找到元素应当被插入的位置,bisect.insort 将元素插入到相应位置
In [7]: import bisect
In [10]: a
Out[10]: ['1', '2', '3', '4']
In [12]: bisect.bisect(a,'3')
Out[12]: 3
In [13]: bisect.insort(a,'6')
In [14]: a
Out[14]: ['1', '2', '3', '4', '6']
切片
切片的start和stop是可以省略的,如果省略的话会默认传入序列的起始位置或结束位置
[::2] 隔一个数取一个值 [::-1]翻转列表和元组
内建序列函数
enumerate
for i, value in enumerate(list):
该函数返回(i,value)元组的序列,其中value是元素的值,i是元素的索引
当你需要对数据进行索引时,可以通过enumerate构造一个字典,将序列值映射到索引位置上
In [15]: some_list = ['foo', 'bar', 'baz']
In [16]: mapping = {}
In [17]: for i, v in enumerate(some_list):
...: mapping[v] = i
In [18]: mapping
Out[18]: {'foo': 0, 'bar': 1, 'baz': 2}
sorted
函数返回一个根据任意序列中的元素新建的已排序列表
zip
zip将列表、元组或其他序列的元素配对,新建一个元组构成的列表
In [19]: seq1 = ['foo','bar','baz']
In [21]: seq2 = ['one','two','three']
In [22]: zipped = zip(seq1,seq2)
In [23]: zipped
Out[23]: <zip at 0x16d6c013d00>
In [24]: print(zipped)
<zip object at 0x0000016D6C013D00>
In [25]: list(zipped)
Out[25]: [('foo', 'one'), ('bar', 'two'), ('baz', 'three')]
reversed
将序列元素倒序排列
reversed是一个生成器,因此如果没有实例化(例如使用list函数或进行for循环)的时候,并不会产生一个倒序的列表
字典
更常用的名字是哈希表或者是关联数组
使用update将两个字典合并
dict1.update({a:'1',b:'2'})
update 方法改变了字典中元素位置,因此对于任何原字典中已经存在的键,如果传给update方法的数据也含有相同的键,则它的值将会被覆盖
从序列生成字典
字典可以接收一个2-元组的列表作为参数的
In [26]: mapping = dict(zip(range(5),reversed(range(5))))
In [27]: mapping
Out[27]: {0: 4, 1: 3, 2: 2, 3: 1, 4: 0}
默认值
字典的get 方法和pop方法可以返回一个默认值
value = some_dict.get(key, default_value)
集合
集合是一种无需且元素唯一的容器。可以认为集合也想字典,但是只有键没有值。
集合有两种创建方式:通过set函数或者用字面值集与大括号的语法
In [39]: set([2,2,1,1,4,5,3,3])
Out[39]: {1, 2, 3, 4, 5}
In [40]: {2,3,3,4,1,1,2,5}
Out[40]: {1, 2, 3, 4, 5}
常用集合方法列表
列表、集合和字典的推导式
列表推导式是python语言特性之一。它允许你过滤一个容器的元素,用一种简明的表达式转换传递给过滤器的元素,从而生成一个新的列表。
列表推导式基本形式为 :
list_comp = [expr for val in collection if condition]
过滤条件是可以忽略的,只保留表达式。例如,给定字符串列表,过滤出长度大于2的,并改写成大写
In [41]: strings = ['a', 'as', 'second', 'first', 'python', 'java', 'js']
In [42]: [x.upper() for x in strings if len(x) > 2 ]
Out[42]: ['SECOND', 'FIRST', 'PYTHON', 'JAVA']
集合与字典的推导式是列表推导式的自然拓展,用相似的方式生成集合与字典。字典推导式如下:
dict_comp = {key-expr : value-expr for value in collection if condition}
集合推导式看起来像列表推导式,只是中括号变成了大括号
set_comp = {expr for val in collection if condition}
如果想要一个集合包含上述列表中字符串的长度,可以通过推导式很快实现
In [43]: unique_lenths = [len(x) for x in strings]
In [44]: unique_lenths
Out[44]: [1, 2, 6, 5, 6, 4, 2]
使用map函数同样可以表达
In [45]: set(map(len, strings))
Out[45]: {1, 2, 4, 5, 6}
# set集合去掉重复值
字典推导式
In [50]: loc_mapping = {val : index for index, val in enumerate(strings)}
In [51]: loc_mapping
Out[51]: {'a': 0, 'as': 1, 'second': 2, 'first': 3, 'python': 4, 'java': 5, 'js': 6}
嵌套列表推导式
列表推导式的for循环部分是根据嵌套的顺序排列的,所有的过滤条件像之前一样被放在尾部
for表达式的顺序应该和你写嵌套for循环来代替列表推导式的顺序一致
函数
函数声明使用def 关键字,返回时使用return 关键字
如果python达到函数的尾部时仍然没有遇到return 语句,就会自动返回None
命名空间、作用域和本地函数
函数有两种连接变量的方式:全局、本地。在函数内部,任意变量都是默认分配到本地命名空间的。
返回多个值
a, b, c = f()
return_value = f()
return_value 是一个包含三个元素的元组
函数是对象
假设正在做数据清洗,需要将一些变形应用到下列字符串列表中,结合re库
In [52]: states = [' Alabama ', 'Georgia!', 'GEORGIA', 'georgia', 'FlOrIda', 'south carolina##', 'West virginia?']
In [53]: import re
In [54]: def clean_strings(strings):
...: result = []
...: for value in strings:
...: value = value.strip()
...: value = re.sub('[!#?]', '',value)
...: value = value.title()
...: result.append(value)
...: return result
...:
In [55]: clean_strings(states)
Out[55]:
['Alabama',
'Georgia',
'Georgia',
'Georgia',
'Florida',
'South Carolina',
'West Virginia']
另一种实现就是将特定的列表操作应用到某个字符串的集合上
In [56]: def remove_punctuation(value):
...: return re.sub('[!#?]', '',value)
In [58]: clean_ops = [str.strip, remove_punctuation, str.title]
In [59]: def clean_strings(strings, ops):
...: result = []
...: for value in strings:
...: for function in ops:
...: value = function(value)
...: result.append(value)
...: return result
In [60]: clean_strings(states, clean_ops)
Out[60]:
['Alabama',
'Georgia',
'Georgia',
'Georgia',
'Florida',
'South Carolina',
'West Virginia']
这种更为函数化的模式可以在更高层次上方便地修改字符串变换方法
匿名 Lambda函数
匿名函数使一种通过单个语句生成函数的方式,其结果使返回值
柯里化:部分参数应用
表示通过部分参数应用的方式从已有的函数中衍生出新的函数
def add_numbers(x, y):
return x + y
add_five = lambda y : add_numbers(5, y)
第二个函数对于add_numbers就是柯里化了
内建的functools 模块可以使用 partial 函数简化这种处理:
from functools import partial
add_five = partial(add_numbers, 5)
生成器
通过一致的方式遍历序列,使python重要特性之一。这个特性使通过迭代器协议来实现的,迭代器协议是一种令对象可遍历的通用方式。
写下for key in some_dict 循环语句时,python解释器首先尝试根据 some_dict生成一个迭代器
迭代器就是一种用于在上下文中(比如for循环)向python解释器生成对象的对象
生成器是构造新的可遍历对象的一种非常简洁的方式。普通函数执行并一次返回单个结果,而生成器则返回一个多结果序列,在每一个元素产生之后暂停,直到下一个请求。如果需要创建一个生成器,则只需要在函数中返回关键字 return 替换为 yield
生成器表达式
只需要将列表推导式中的中括号替换为小括号即可
很多情况下,生成器表达式可以作为函数参数用于替代列表推导式
itertools模块
该模块是适用于大多数数据算法的生成器集合