Python【Feature】高级特性
文章目录
- 切片 Slice
- 索引
- 迭代 Iteration
- 判断是否迭代对象
- 迭代 List 列表类型数据
- 迭代 Dict 键-值对类型数据
- 列表生成式 List Comprehensions
- 列表生成式
- 其他生成式
- 错误示范
- 总结
- 生成器 Generator
- 普通形式
- 函数形式
- 实例
- 核心算法
- 做成生成器
- 遍历输出
- 完整代码
- 总结
- 迭代器 Iterator
- 迭代器的本质
- 自定义可迭代类
- 总结
切片 Slice
[startWith : end : step]
切片适用于 list、tuple、string
startWith是包含,end则不包含注意:
切片是从左往右切的
如果用正索引开始,就要用 正索引 或 逆索引 结束,例如s[1:5] 或 s[1:-3]
!如果用逆索引开始,就要用 逆索引 结束(
s[-1:1]
这样只会返回空字符串,正确应该是s[-5:-1]
)
!逆索引记得不要弄颠倒了。(s[-1:-3]
这样只会返回空字符串,正确应该是s[-3:-1]
)
索引
| P | y | t | h | o | n |0 1 2 3 4 5 # 从左往右,下标从0开始-6 -5 -4 -3 -2 -1 # 从右往左,下标从-1开始
>>> s = 'Python'
>>> s[0]
'P'
>>> s[0:-1] # 结束索引不被截取
'Pytho'
>>> s[:5] # 起始索引可以省略不写,代表从第一位开始截取
'Pytho'
>>> s[0:] # 结束索引可以省略不写,代表截取至最后一位
'Python'
>>> s[:] # 等于复制了一整个
'Python'>>> s[1:4]
'yth'
>>> s[1:-2]
'yth'
>>> s[-2:1] # 逆索引开始,不能以正索引结束
''
>>> s[-5:-2]
'yth'
>>> s[-2:-5] # 只能从左往右切
''
>>> l = list(range(100))>>> l[10:20]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]>>> l[10:20:3]
[10, 13, 16, 19]>>> l[80::3]
[80, 83, 86, 89, 92, 95, 98]>>> l[:10:3]
[0, 3, 6, 9]>>> l[::10]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]>>> l[::-10]
[99, 89, 79, 69, 59, 49, 39, 29, 19, 9]
迭代 Iteration
判断是否迭代对象
可以用过 collections 的 Iterable 类型,用
isinstance()
判断一个对象是否是可迭代对象
from collections import Iterablestr = 'abc'
l = [1, 2, 3]
t = (1, 2, 3)
d = {1: 1, 2: 2, 3: 3}
s = ({1, 2, 3})print(isinstance(str, Iterable)) # True
print(isinstance(l, Iterable)) # True
print(isinstance(t, Iterable)) # True
print(isinstance(d, Iterable)) # True
print(isinstance(s, Iterable)) # True
print(isinstance(123, Iterable)) # False 整数字面量不是可迭代对象
迭代 List 列表类型数据
s = 'abcdefg'
for value in s:print(value, end=' ')# Output:
a b c d e f g
# 可以通过 enumerate() 给string,list,tuple 等生成下标s = 'abcdefg'
for i, value in enumerate(s):print(i, value)# Output:
0 a
1 b
2 c
3 d
4 e
5 f
6 g
l = ['a', True, (1, 2), 43]
for i, value in enumerate(l):print(i, value)# Output:
0 a
1 True
2 (1, 2)
3 43
# 同时引用两个变量
for x, y in [(11, 12), (21, 22), (31, 32)]:print(x, y)# Output:
11 12
21 22
31 32######################################################for x, y, z in [(11, 12, 13), (21, 22, 23), (31, 32, 33)]:print(x, y, z)# Output:
11 12 13
21 22 23
31 32 33
迭代 Dict 键-值对类型数据
默认情况下,Dict迭代的是key,如果要迭代value,可以用
for value in d.values()
如果要同时迭代key 和 value, 可以用for k, v in d.items()
d = {'a': 'Alice', 'b': 'Boii', 'c': 'Cai'}
for i in d:print(i)# Output:
a
b
c#############################################d = {'a': 'Alice', 'b': 'Boii', 'c': 'Cai'}
for i in d.values():print(i)# Output:
Alice
Boii
Cai#############################################d = {'a': 'Alice', 'b': 'Boii', 'c': 'Cai'}
for k, v in d.items():print(k, '-', v)# Output:
a - Alice
b - Boii
c - Cai
列表生成式 List Comprehensions
列表生成式
[ i-expression for i in Iterations ]
[ i-expression for i in Iterations if expression ]
[ i-expression if expression else expression for i in Iterations ]
[ ··· for ··· in ··· ]
[ ··· for ··· in ··· if ··· ]
[ ··· if ··· else ··· for ··· in ··· ]
列表生成式是一种非常简洁的语法,可以大幅度的压缩代码
阅读方式:
[i-expression for i in Iterations]
遍历迭代对象 Iterations,将每个元素 e 放到 i-expression中运算后,作为这个列表 list 的元素[i-expression for i in Iterations if expression]
遍历迭代对象 Iterations,将每个元素 e 放到 if 中的 expression中运算后,放到 i-expression 中运算,然后作为这个列表 list 的元素[i-expression if expression else expression for i in Iterations]
遍历迭代对象 Iterations,将每个元素 e 放到 if else 中的 expression中运算后,放到 i-expression 中运算,然后作为这个列表 list 的元素
for 前的 if else 可以看成三目运算符,这样比较好理解
- 三目运算符:True时执行 if expression else Flase时执行
- 对比一下:[ i-expression if expression else expression for i in Iterations ]
- 代入一下:[ True时执行 if expression else Flase时执行 for i in Iterations ]
一句话:原本有10个,for…if 后不一定有 10 个, if…else…for 以后有10个,不过可能不尽相同。
两句话:for 前必 else,for 后不else。
注意:i-expression 的
计算变量
和 for 里的临时变量
要相同
普通列表生成式
# range(1, 11) 生成1~10 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# for in 遍历这10个数
# 每次遍历都把当前元素拿到 i-expression 即 x * x 做相乘计算
# 然后作为列表的元素
# 注意 for 的临时变量是 x,i-expression 的变量也是 x,这两个要相同# 这里是计算出1~10每个数的平方
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]# 把一个 List 中所有字符串变小写
>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']
for 里带 if 筛选的列表生成式
# range(1, 11) 生成1~10 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# for in 遍历这10个数
# 每次遍历都把当前元素拿到 if 里计算, 得到 [2, 4, 6, 8, 10]
# 然后放到 i-expression 即 x * x 做相乘计算得到 [4, 16, 36, 64, 100]
# 最后作为列表的元素# 这里是筛选出偶数,然后计算平方>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]
双循环的列表生成式
# 还可以使用双循环,生成全排列>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
多变量的列表生成式
# 一个循环多个变量也是可以的
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '-' + v for k, v in d.items()]
['y-B', 'x-A', 'z-C']
for 前带 if 的列表生成式
# # range(1, 11) 生成1~10 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# for in 遍历这10个数
# 每次遍历都把当前元素拿到 for 前的 if else三目运算符里计算
# x if x % 2 == 0 else -x ,偶数正常输出, 奇数变负数,得到 [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]
# 最后作为列表的元素
>>> [x if x % 2 == 0 else -x for x in range(1, 11)]
[-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]# 再稍微改动下
# 把 x if x % 2 == 0 else x + 10 看作三目运算符就很好理解
>>> [x if x % 2 == 0 else x + 10 for x in range(1, 11)]
[11, 2, 13, 4, 15, 6, 17, 8, 19, 10]
其他生成式
除了列表生成式,还有字典生成式
、元组生成式
,其实现都是一样的
{k: v for k, v in d.items()}
{k: v for k, v in d.items() if condition}
{k: v if condition else k: -v for k, v in d.items() }
元组生成式 生成一个生成器对象,下面将会讲到。
错误示范
# for 后 if 加 else
>>> [x for x in range(1, 11) if x % 2 == 0 else 0]File "<stdin>", line 1[x for x in range(1, 11) if x % 2 == 0 else 0]^
SyntaxError: invalid syntax# for 前 if 不加 else
>>> [x if x % 2 == 0 for x in range(1, 11)]File "<stdin>", line 1[x if x % 2 == 0 for x in range(1, 11)]^
SyntaxError: invalid syntax
总结
for...in...
最先,if 或 if else
随后,i-expression
最后for 前 if
必加 else,for 后 if
不加 elsefor 前 if
是对 for的输出进行处理,for 后 if
是对for的输出进行控制过滤
生成器 Generator
普通形式
元组生成式 生成一个生成器对象,通过for或者next遍历,遍历后,原生成器对象就不存在了
( i-expression for i in Iterations )
( i-expression for i in Iterations if expression )
( i-expression if expression else expression for i in Iterations )
(··· for ··· in ··· )
(··· for ··· in ··· if ··· )
(··· if ··· else ··· for ··· in ··· )
生成器,是一种一边循环一边计算的机制
比如现在需要一个1到100W的平方
的列表,用列表生成式表示为[ x * x for x in range(1000000)]
但如果只需要经常访问前面几个元素,则浪费了很大的空间
而生成器是保存了一种算法,它不会直接创建100W个数,而是等到调用的时候通过计算获得
也就是说:列表生成式是一种缩写,生成器是一种算法
生成器 vs 列表生成式:
列表生成式 是使用[]
,生成器 是使用()
列表生成式是一个列表,可以直接列出所有元素;生成器要用next()
或遍历
来列出所有元素
>>> L = [ x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]>>> G = ( x * x for x in range(10) )
>>> G
<generator object <genexpr> at 0x00000204807D8D60>
>>> next(G)
0
>>> next(G)
1
>>> next(G)
4
>>> next(G)
9
>>> next(G)
16
>>> next(G)
25
>>> next(G)
36
>>> next(G)
49
>>> next(G)
64
>>> next(G)
81
>>> next(G)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
StopIteration
生成器是算法,是规律,是计算方式,通过next(G)
计算出G的下一个元素的值,直到最后一个元素
没有更多元素的时候,抛出StopIteration
错误
但是这种不断调用next()
的方法显然不科学,
所以一般都是用for循环
G = ( x * x for x in range(10) )
for i in G:print(i, end=' ')# Output:
0 1 4 9 16 25 36 49 64 81
函数形式
生成器的另一种实现方式是 函数形式
def funcName():sthwhile True:yield sthsth
普通函数通过
return语句
返回
生成器通过yield语句
返回,并在下次调用时从yield语句
处继续
yield
可以看成return
,都是返回一个值出去
只不过使用yield
在下次调用时会从yield
处继续。
实例
例如打印杨辉三角
1/ \1 1/ \ / \1 2 1/ \ / \ / \1 3 3 1/ \ / \ / \ / \1 4 6 4 1/ \ / \ / \ / \ / \
1 5 10 10 5 1
期待输出是这样的
# [1]
# [1, 1]
# [1, 2, 1]
# [1, 3, 3, 1]
# [1, 4, 6, 4, 1]
# [1, 5, 10, 10, 5, 1]
# [1, 6, 15, 20, 15, 6, 1]
# [1, 7, 21, 35, 35, 21, 7, 1]
# [1, 8, 28, 56, 70, 56, 28, 8, 1]
# [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
实现思路:
先看杨辉三角的规律:头尾都是1,中间是上一层第n个
+第n+1个
,每一层都是list
而且第一层比较特殊,是 [1]
可以先把杨辉三角核心的算法搞定。
核心算法
L = [1]
L = [1] + [L[n] + L[n+1] for n in range(len(L)-1)] +[1]
[1] + [L[n] + L[n+1] for n in range(len(L)-1)] +[1]
就是核心算法了
把他拆开来看,可以发现这个表达式是由中间段加上头尾的 [1]
组成的
再看中间段 [L[n] + L[n+1] for n in range(len(L)-1)]
这是一个列表生成式
range(len(L)-1)
会生成 0 1 2 …
假设当前为第5层,准备生成 [1, 4, 6, 4, 1]
当前的 L 是 [1, 3, 3, 1],那么len(L)
则是4,
range(len(L) - 1)
则等价于range(3)
,会生成 0 1 2
[L[n] + L[n+1] for n in range(len(L)-1)]
则等价于
[L[0]+L[1], L[1]+L[2], L[2]+L[3]]
则等价于
[ 1 + 3, 3 + 3, 3 + 1 ]
则等价于
[4, 6, 4]
正好就是中间段
再加上头尾两个 [1]: [1, 4, 6, 4, 1]
做成生成器
因为第一层 特殊,所以用小括号列表生成式()
做不出来,改用函数形式
def triangles():L = [1]while True:yield LL = [1] + [L[x]+L[x+1] for x in range(len(L)-1)] + [1]
第一次迭代生成器triangles时,会执行 L = [1]
,然后进入循环,遇到yield L
把L返回出去
第二次迭代生成器triangles时,会从yield L
处继续,
然后执行核心算法 L = [1] + [L[x]+L[x+1] for x in range(len(L)-1)] + [1]
之后继续循环,又遇到yield L
,把更新过的 L 返回出去
接着第三次,第四次…
其实有点类似 C 语言中被static
修饰的局部变量,函数调用完不会被销毁,程序结束才销毁
遍历输出
for n, t in enumerate(triangles()):results.append(t)n += 1if n == 10:break
生成器也是一个可迭代对象,所以可以用 for...in...
来迭代输出
enumerate()
赋予了对应的下标
这个生成器可以无限循环下去,可以获得无穷层,这里打印10层作为示范即可
最后可以得到期待输出:
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
完整代码
def triangles():L = [1]while True:yield LL = [1] + [L[x]+L[x+1] for x in range(len(L)-1)] + [1]results = []
for n, t in enumerate(triangles()):results.append(t)n += 1if n == 10:breakfor t in results:print(t)if results == [[1],[1, 1],[1, 2, 1],[1, 3, 3, 1],[1, 4, 6, 4, 1],[1, 5, 10, 10, 5, 1],[1, 6, 15, 20, 15, 6, 1],[1, 7, 21, 35, 35, 21, 7, 1],[1, 8, 28, 56, 70, 56, 28, 8, 1],[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
]:print('测试通过!')
else:print('测试失败!')
总结
普通形式-生成器:把列表生成式的[]
换成()
函数形式-生成器:函数中带yield
,下一次调用时会从yield
处继续
迭代器 Iterator
可以被
next()
函数调用并不断返回下一个值的对象称为迭代器:Iterator
。
可迭代对象:
可以直接作用于 for 循环的对象统称为可迭代对象Iterable
可迭代对象Iterable
:
- List、Tuple、Dict、Set、String;
- 生成器Generator、带
yield
的Generator Function可以用
isinstance(obj, Iterable)
判断是否是可迭代对象
迭代器:
不但可以作用于 for 循环,还可以被next()
函数调用并不断返回下一个值则称为迭代器:Iterator
。
生成器Generator、带yield
的Generator Function就是迭代器
可以用isinstance(obj, Iterator)
判断是否是迭代器
所以:Generator、Generator Function 既是 Iterator
,也是 Iterable
而 List、Tuple、Dict、Set、String 仅仅只是 Iterable
,但是,使用iter()
函数可以使他们变成迭代器Iterator
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('Boii'), Iterator)
True
迭代器的本质
Python的Iterator对象
表示的是一个数据流,Iterator对象
可以被next()函数
调用并不断返回下一个数据,直到没有数据时抛出StopIteration
错误。
可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度
只能不断通过next()函数
实现按需计算下一个数据,所以Iterator
的计算是惰性的,只有在需要返回下一个数据时它才会计算
自定义可迭代类
只要类中实现了__iter__()
方法,这个类的对象就是可迭代对象Iterable
。
只要类中实现了__iter__()
和__next__()
方法,这个类就是个迭代器Iteratorn
。
__iter__()
方法必须返回一个迭代器。
那么代码就是这样子:
# 1. 创建一个类
class Classmate:def __init__(self):self.names = list()def add(self, value):self.names.append(value)# 2. 实现__iter__方法,返回一个迭代器def __iter__(self):"""只有实现了__iter__方法,才能可迭代"""return ClassmateIterator(self) # __iter__ 必须返回一个迭代器对象# 3. 创建一个迭代器
class ClassmateIterator:"""实现了__iter__和__next__方法,才是一个迭代器"""def __init__(self, obj):self.obj = objself.current_num = 0# 4. 迭代器需要实现 __iter__, __next__方法def __iter__(self):passdef __next__(self):"""实现了__iter__和__next__方法,才是一个迭代器"""if self.current_num < len(self.obj.names):res = self.obj.names[self.current_num]self.current_num += 1return reselse:raise StopIterationif __name__ == '__main__':clsm = Classmate()clsm.add(123)clsm.add(456)clsm.add(789)# 通过循环检查classmate对象是否可迭代for i in clsm:print(i)--------------------------------------------------# Output:
123
456
789
总结起来就是:
创建一个类并实现__iter__()
方法去返回一个迭代器
创建一个类并实现__iter__()
和__next__()
方法,使其成为迭代器。
这样看起来好像为了实现一个迭代器又生成了一个迭代器
既然我是想造一个迭代器,__iter__()
方法有需要返回一个迭代器对象,那我返回自己不行吗?
可以!
# 1. 创建一个类
class Classmate:def __init__(self):self.names = list()self.current_num = 0def add(self, value):self.names.append(value)# 2. 实现__iter__方法,返回一个迭代器def __iter__(self):"""只有实现了__iter__方法,才能可迭代"""return self # __iter__ 必须返回一个迭代器对象,这里就返回自己就行# 3. 实现__next__方法,这个方法会在外部使用next(Iterator)时调用。def __next__(self):"""实现了__iter__和__next__方法,才是一个迭代器"""if self.current_num < len(self.names):res = self.names[self.current_num]self.current_num += 1return reselse:raise StopIterationif __name__ == '__main__':clsm = Classmate()clsm.add(123)clsm.add(456)clsm.add(789)# 通过循环检查classmate对象是否可迭代for i in clsm:print(i)--------------------------------------------------# Output:
123
456
789
总结
- 可迭代对象和迭代器,通过函数
iter()
转换 - 迭代器:数据流,变长,惰性的
- 继承关系:Iterable>Iterator>Generator(参考python doc)
- Iterable:list、tuple、dict、set、str、Iterator、Generator等
- Iterator转化成Iterator:Iterator=iter(Iterable)
- 自定义迭代类时必须实现
__iter__()
和__next__()
方法 __iter__()
方法必须返回一个迭代器
Python【Feature】高级特性相关推荐
- python的高级特性:切片,迭代,列表生成式,生成器,迭代器
python的高级特性:切片,迭代,列表生成式,生成器,迭代器 1 #演示切片 2 k="abcdefghijklmnopqrstuvwxyz" 3 #取前5个元素 4 k[0:5 ...
- 一文了解Python部分高级特性
本部分主要介绍 Python 的部分高级特性,包括切片.迭代器.推导式.生成器.匿名函数.装饰器等.阅读本文预计需要 15 min. 一文了解Python部分高级特性 1. 前言 2. 切片 3. 迭 ...
- python 的高级特性:函数式编程,lambda表达式,装饰器
一.Python语言的高级特性 函数式编程 基于Lambda演算的一种编程方式 程序中只有函数 函数可以作为参数,同样可以作为返回值 纯函数式编程语言:LISP,Haaskell Python函数式编 ...
- python的高级特性3:神奇的__call__与返回函数
__call__是一个很神奇的特性,只要某个类型中有__call__方法,,我们可以把这个类型的对象当作函数来使用. 也许说的比较抽象,举个例子就会明白. In [107]: f = absIn [1 ...
- python 11高级特性
切片 取列表中前3个元素我们常见的方法有两种: [L[0],L[1],L[2]] 采用循环的方式如下图所示. 对这种经常取指定索引范围的操作,用循环十分繁琐,因此,Python提供了切片(Slice) ...
- 【Python】高级特性 一
切片 取一个list或tuple的部分元素 常规方法: 循环方法: 切片操作符: #切片 #取一个list或者tuple的部分元素是非常常见的操作 #取前三个元素 #利用切片操作,实现一个trim() ...
- python中io中的+模式_Python的高级特性,模块和IO操作
今天我们学习Python的高级特性.模块和IO操作,通过学习这些,我们可以更快的了解Python,使用Python. 高级特性中会讲述列表生成式.生成器.和一些高级函数,学习这些方便我们快速的生成列表 ...
- Python高级特性
我一直认为Python是一门很神奇的语言.神奇之处在于其既可阳春白雪,亦可下里巴人.也就是其简单到几乎所有的人稍加学习即可上手,但是你如果细细品味,就会发现他还有很多高深的东西.正如一位漂亮的姑娘,一 ...
- Python高级特性:切片、迭代、列表生成式、生成器与迭代器
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 接着廖雪峰老师的学习教程,小编要开始加快推进Python的学习进程 ...
- python函数第二次运行报错_Python学习笔记2-函数、高级特性
函数 调用函数 要调用一个函数,需要知道函数的名称和参数,比如求绝对值的函数abs,只有一个参数 >>> abs(100) 100 >>> abs(-20) 20 ...
最新文章
- JavaWeb学习总结(一)——JavaWeb开发入门(转载)
- hdu 4417(线段树OR树状数组)
- zookeeper在window下的搭建
- go java web框架_java程序员10分钟可上手的golang框架golang实战使用gin+xorm搭建go语言web框架restgo...
- anaconda怎么使用python包_Anaconda中python包的介绍与使用方法
- 检测SDWebImage有没有缓存图片 IOS 获取网络图片大小
- python网络爬虫系列(六)——数据提取 lxml模块
- windowswps怎么以文件形式发送_wps怎么以文件形式分享
- java骨架_基于Mat变换的骨架提取Java
- mongoose的操作及其常用命令
- CNN推理哪家强?英伟达/英特尔/骁龙/麒麟/ActionSemi大测评
- 冯永昌:云计算与大数据时代的量化投资
- postfix 配置
- python源码剖析新版_Python 源码剖析之基础知识
- CAD交互绘制虚线(网页版)
- anaconda中报错 Executing transaction: failed
- 睦星科技Kolmostar获1000万美元 A 轮融资,将推出更多元的GNSS定位解决方案
- uniapp引入字体图标库
- MySQL认证介绍 (转帖)
- BASE32编码 --记录