python必知必会2
什么是负索引?
序列中的每一个元素都有自己对应的索引,例如左端第一个元素的索引是 0 ,第二个元素的索引是 1,一般来讲索引都是正数,而负索引是指使用负数作为索引去访问序列中的某一个元素。此时 Python 会从序列的右端去访问元素,但是右端第一个元素即序列最后一个元素的索引是 -1 ,而不是 -0。对于一个序列而言:x[-n]就等同于x[len(x)-n]。
如何使用负索引来完成一个字符串反转?
a = "abcdefg"
print(a[::-1]) # gfedcba
Python 中的序列类型如列表,元组,字符串等都支持一些相同的通用操作。比如索引,切片,加(a + b,a,b拼接),乘(s * n,n次拼接)和检查某个元素是否属于序列,以及一些常用内建函数:计算序列长度len(seq),最大元素max(seq)和最小元素min(seq)。
我们在使用 len() 函数获取序列长度的时候语法是 len(seq) , 但是如果对于一个列表进行扩展操作使用的语法是 seq.append() 。这是因为 len() 是 Python 的内置函数(Built-in functions),而 append() 则是内置方法。内置函数对象是对于C函数的外部封装,而内置方法,实际上是内置函数的另一种形式,只不过还包含了一个传入C函数的对象作为隐式的额外参数。max()和min()同上。
对序列对象进行切片s[a:b:c],最左边的索引 a 代表截取序列的起始位置,包括该起始位置元素,中间的索引 b 代表截止位置,但不包括该截止位置位置上的元素,最右边的 c 代表步长。运算符[]里可以置空起始位置,截止位置,还有步长。
字典操作中del和pop有什么区别?
- del :使用语法 del dic["k"] ,移除字典中键为 k 的键值对,没有返回值,但是如果字典中没有 k 这个键,会抛出异常 keyError。
- pop:使用语法 dic.pop(k, [default]) ,返回键 k 所对应的值,然后移除这个键值对。如果没有这个键,返回指定的 default 值。如果 default 未给出且 key 不存在于字典中,则会引发 KeyError 。
字典的键几乎可以是任何不可变类型,通常为数字或字符串。除了移除键值对的操作,字典的其它一些常用的基本操作有:
-
len(d) 返回键-值对的长度
-
d[k] 返回键k上的值
-
d[k] = v 把键k上的值设为v
-
del d[k] 删除键为k的元素
-
k in d 检查d中是否包含键为k的项
-
d.clear() 移除所有元素
-
d.copy() 浅复制
-
d.get(k, [default]) 返回键k上的值,如果没有,返回default值。如果 default未给出则默认为None,因而此方法绝不会引发KeyError。在实际的工作中,如果你可以确定你要查询的字典中有 k 这个键的话可以使用 d[k],如果不能确定的话尽量使用 d.get[k] ,这样可以避免在运行时出现一些意想不到的错误。
-
d.popitem()随机返回一个键值并从字典里移除它
-
d.update(m)把新字典m的键值对更新到d中,返回None。做更新操作的时候千万不要再赋值一遍,比如像这样:d = d.update(m),这样你得到的是None,而非更新过的字典。
字典的遍历操作
- d.items() 返回所有的键值对
- d.keys() 返回所有的键
- d.values() 返回所有的值
在Python3中,它们返回的都是一个字典视图,视图对象提供字典条目的一个动态视图,这意味着当字典改变时,视图也会相应改变。
在使用del的时候,如果你希望避免异常,必须用一个判断键是否存在在字典中的语句去决定是否进一步进行移除,像这样:if k in d: del d[k]。当然我们也可以使用try/except去捕捉异常:
try:
del d["a"]
except KeyError:
print("key a not found")
del和pop这两种移除字典中键值对的操作都会直接改变原字典,也就是说你丢失了原来的数据,并且无法回退。但是在实际项目中我们有的时候是需要对数据某一时刻的状态进行记录,这个时候我们应该如何操作呢?
我们可以考虑创造一个新的字典,这个新字典不包括想要移除的键值对。
new_dict = { key: val for key, val in d.items() if key != k }
# 将字典 d 中所有键不为 k 的键值对添加到 new_dict 这个新字典中去。
什么是推导式?
推导式 (comprehensions),是Python的一种独有特性。推导式是可以从一个可迭代的数据结构构建出另一个新的数据结构。主要有列表推导式,字典推导式和集合推导式。 Python2 和 Python3 中都支持推导式语法。
列表推导可以帮助我们把一个序列或是其他可迭代对象中的元素过滤或是加工,然后再创建一个新的列表。它的语法是这样的: [x_expr for x in iterable if condition ]
x_expr : 为新的列表中的元素,这里可以是一个有返回值的函数,函数的返回值即为新列表的元素。
for x in iterable : iterable 可迭代对象
if condition : 根据条件过滤
"""
有一个列表 squares = [1,2,3,4,5],我们想得到这个列表中每一个元素的平方所组成的一个新的列表,那么该怎么办呢?有三种方法:for 语句,匿名函数,列表推导式,我们逐一来看下这三种方法哪一种比较简洁。
"""
squares = [1,2,3,4,5]
# 第一种方法:for 语句
new_squares = []
for x in squares:
new_squares.append(x**2)
# 第二种方法:匿名函数
new_squares = list(map(lambda x: x**2, squares))
# 第三种方法:列表推导式
new_squares = [x**2 for x in squares]
列表推导式的语法是最简洁易懂的。
seq1 = 'abc'
seq2 = (1, 2, 3)
# 这里等同于一个for循环嵌套了另一个for循环,前面的在最外层
print([(x, y) for x in seq1 for y in seq2])
"""
输出结果:[('a', 1), ('a', 2), ('a', 3),
('b', 1), ('b', 2), ('b', 3),
('c', 1), ('c', 2), ('c', 3)]
"""
什么是可迭代对象?
如果这个对象可以在for循环进行迭代操作,那么它就是可迭代对象。在程序运行时,for会调用容器对象中的iter(),而这个函数会返回一个定义了next()的迭代器,每迭代一次就调用一次,逐一访问容器中的元素。
字典推导可以从任何以键值对作为元素的可迭代对象将其元素进行过滤或是加工,然后再新建构建出一个字典。其语法基本和列表推导式类似,只不过最外层的 [] 要换成 {}。
下面演示一些常用的字典推导的例子:
- 将列表转换为字典,用数字索引作为关键字。
>>> d = { i:v for i, v in enumerate(['a', 'b', 'c'])}
- 使用zip将多个可迭代对象聚合成一个新的迭代对象。
>>> names = ['paul', 'adam', 'jane']
>>> ages = [20, 24, 29]
>>> d = { name: age for name, age in zip(names, ages)}
集合推导有点类似于列表推导,把一个序列或是其他可迭代对象中的元素过滤或是加工然后构建出一个集合。
推导式小结
集合推导是花括号,列表推导是方括号,生成器表达式是圆括号。这里再提一句,生成器表达式相对于列表推导式的优势在于,它得到的是一个生成器,只有在需要的时候,才会计算新的值,从而节省内存。比如,你如果在Python交互界面上输出一个从列表推导式得到的一个新列表对象,它会把这个对象中的所有元素打印出来,所以它的所有条目都已经在内存中。但是如果从生成器表达式得到的生成器对象,需要通过调用next(gen)方法去手动遍历。