流畅的python记录
记录一下书中自己容易混淆和错误的知识点~~~
一: 序列类型
python的序列类型,如果从能否被修改来分类,可以分为以下两类:
可变序列 | list,bytearray,array.array,collections.deque,memoryview |
---|---|
不可变序列 | tuple,str,bytes |
其中,加了下划线的序列类型可以存放不同类型的数据。剩下的都为扁平序列,只能容纳一种类型。从我们最常用的tuple和list出发,接下来介绍一下他们特有的知识点:
1. 常用序列
tuple元组:
-
元组拆包:用*处理多余的元素,把一个可迭代对象拆开作为函数的参数。
a,b,*rest=range(5) a,b,rest
a,*body,c,d=range(5) a,body,c,d
分别输出:(0, 1, [2, 3, 4])和(0, [1, 2], 3, 4)
*前缀只能用在一个变量名前面,但这个变量可以出现在赋值表达式的任意位置。
-
具名元组:collections.namedtuple,可以用来构建一个带字段名的元组和一个有名字的类
构建一个具名元组需要两个 参数,1.类名 2.类的各个字段的名字。其中,后者有两种定义方式:
from collections import namedtuple city1=namedtuple("city1","name country population") city2=namedtuple("city2",["name","country","population"]) city1._fields city2._fields
city1和city2的字段名相同。
list列表:
-
list.sort()和sorted
两者我想从以下列表介绍一下:
相同点 都有两个可选的关键字参数reverse和key 不同点 list.sort()就地排序,改变原列表
sorted创建一个新列表作为返回值两者的不同点相信通过以下的代码就可以区分清楚:
fruits=["grape","raspberry","apple","banana"] print(sorted(fruits)) print(fruits) fruits.sort() print(fruits)
三个输出将分别为:
['apple', 'banana', 'grape', 'raspberry'] ['grape', 'raspberry', 'apple', 'banana'] ['apple', 'banana', 'grape', 'raspberry']
-
list推导:如何只用列表推导来创建新的列表,尽量保持简短
list作为可变序列,最大的陷阱就是引用可变对象背后的陷阱,看下面这个例子:
board=[["-"]*3 for i in range(3)] board[1][2]="X" board
[['-', '-', '-'], ['-', '-', 'X'], ['-', '-', '-']]
这个结果似乎很好理解,但我们换一个写法可能会得到不同的结果:
board=[["-"]*3]*3
board[1][2]="X"
board
[['-', '-', 'X'], ['-', '-', 'X'], ['-', '-', 'X']]
为什么结果会完全不同呢?因为这个列表的3个引用都指向同一个对象,每次循环都追加同一个对象到board中。而上一个例子,是在每次循环中创新一个新对象追加到board中。
最后,对于list和tuple,我还想从下面这个表对比一下两者可操作的区别:
操作 | 列表 | 元组 |
---|---|---|
+ | ✔︎ | ✔︎ |
+= | ✔︎ | ✗ |
append | ✔︎ | ✗ |
index索引 | ✔︎ | ✔︎ |
2. 序列共有操作
切片操作:
切片操作应该是序列操作中最常用的之一,这里只讲述三个特殊的点。
-
为什么切片和区间操作总是忽略最后一个元素?
1.可以快速看出切片和区间里有几个元素
2.起止位置可见时,可以快速计算出切片和区间的长度
3.可以把序列分割成不重复的两部分
-
间隔取值
s[a: b :c]表示s在a和b之间以c为间隔取值,c为负代表反向取值。因此s[::-1]可以表示翻转。
-
切片赋值
把切片放在赋值语句的左边,或作为del操作的对象,就可以对序列进行嫁接,切除或修改。
3. 其他序列
有序序列管理:
bisect模块有两个主要函数,bisect和insort,都使用二分查找对有序序列进行查找或者插入元素的操作。
import bisect
s=[1,2,3,4,6,7]
bisect.bisect(s,5)
输出为4,代表把5这个值插入到“4”这个位置之后,序列还能保持有序。
bisect.insort(s,5)
s
输出[1, 2, 3, 4, 5, 6, 7],即插入值后的序列。
array.array:
与list的区别是,在处理只有数字的列表时,array.array将更加高效。
双向队列collections.deque:
双向队列可以快速从两端添加和删除元素。创建时,可以 指定队列大小。
二:字典等操作
1. dict.setdefault处理找不到的键
通常使用d[k]不能找到正确的键时,python会抛出异常。一个方法是如下设置默认值:
d={1:"apple",2:"banana",3:"watermelon"}
d.get(4,"None")
返回设置好的默认值“None”。但这样处理并不自然,且效率低,如果寻找字典中键值为空且进行赋值更新,dict.setdefault更简洁。
d.setdefault(key,[]).append(new_value)就等于以下的操作:
if 4 not in d:
d[4]=[]
d[4].append("grape")
d
{1: 'apple', 2: 'banana', 3: 'watermelon', 4: ['grape']}
2.collections模块中的字典变种
映射类型 | 功能 |
---|---|
collections.defaultdict | 处理找不到键的一个选择,具体见下面代码块 |
collections.OrderDict | 有序的添加键,键的迭代次数一致,因为字典默认是无序的。 |
collections.Counter | 给键准备一个整数计数器。 ct=collections.Counter(“abracadabra”) 输出:Counter({“a”:5, “b”:2, “r”:2, “c”:1, ‘d’:1}) |
import collections
index=collections.defaultdict(list)
index["apple"].append("1")
index
defaultdict(list, {'apple': ['1']})
或者:
import collections
index=collections.defaultdict(tuple)
index["apple"]=(1,2,3)
index
defaultdict(tuple, {'apple': (1, 2, 3)})
三:python函数
1. 函数参数
调用函数时可以使用*和**(传入字典)展开可迭代对象,见下例
def tag(name,*content,cls=None,**attrs):
if cls is not None:
print("cls value is:",cls)
attrs["class"]=cls
if attrs:
print("attrs is:",attrs)
else:
print("attr is empty")
if content:
print("content is:",content)
print("-"*50)
tag("p","hello")
print("-"*50)
tag("p","hello",id=33)
print("-"*50)
tag("p","hello","world",cls="sidebar")
print("-"*50)
tag(content="testing",name="img")
my_tag={"name":"img","title":"sunset","cls":"framed"}
print("-"*50)
tag(**my_tag)
--------------------------------------------------
attr is empty
content is: ('hello',)
--------------------------------------------------
attrs is: {'id': 33}
content is: ('hello',)
--------------------------------------------------
cls value is: sidebar
attrs is: {'class': 'sidebar'}
content is: ('hello', 'world')
--------------------------------------------------
attrs is: {'content': 'testing'}
--------------------------------------------------
cls value is: framed
attrs is: {'title': 'sunset', 'class': 'framed'}
考虑上面五种代入参数的形式,尤其关注最后一种,当传入整个字典的时候,同名键名会自动绑定到对应的具名参数上,剩下的被**atts捕捉。