lambda表达式
lambda表达式也称为匿名函数,能够使用一行代码实现比较复杂函数功能,使代码更加简洁。
语法规则
与传统函数的区别:
传统定义方式定义的函数,函数名是一个函数的引用
>>> def square(x):
return x*x
>>> square(3)
9
>>> square
<function square at 0x0000021CAB808B80>
而lambda表达式整个表达式是一个函数的引用
>>> squareY=lambda y:y*y
>>> squareY(3)
9
>>> squareY
<function <lambda> at 0x0000021CAB808C10>
好处
lambda是一个表达,它可以用在常规函数不可以使用的地方,比如:
- 把lambda放在列表中,
>>> y=[lambda x:x*x,2,3]
>>> y[0] //y[0]是一个函数的引用,调用这个函数时需要加小括号,并将参数放在小括号中
<function <lambda> at 0x0000021CAB808CA0>
>>> y[0](y[1]) //将列表中的第二个元素作为参数传入lambda表达式中,得到平方返回
4
>>> y[0](y[2])
9
- 把lambda表达式用在map函数中
>>> mapped=map(lambda x:ord(x)+10,"FishC") //使用lambda表达式实现
>>> list(mapped)
[80, 115, 125, 114, 77]
>>> def boring(x): //使用传统定义函数的方式将字符型转化为整型
return ord(x)+10
>>> list(map(boring,"FishC"))
[80, 115, 125, 114, 77]
map函数有两个参数,第一个参数要求传入一个用于计算的函数,是引用,第二个参数是序列类型,该函数的功能是把序列(第二个参数)中每个元素逐个传递给第一个参数指定的函数,在运算之后把他们的结果构成一个迭代器。
- 把lambda表达式用在filter函数中
>>> list(filter(lambda x:x%2,range(10)))
[1, 3, 5, 7, 9]
总结
lambda是一个表达式而非语句,因此可以使用lambda做简单的事情,用def语句去定义功能复杂的函数。
迭代器
定义
Python中一个实现了_iter_方法和_next_方法的类对象,就是迭代器.
对于list、string、tuple、dict等这些容器对象,使用for循环遍历是很方便的。在后台for语句对容器对象调用iter()函数。==iter()是python内置函数。iter()函数会返回一个定义了next()方法的迭代器对象,它在容器中逐个访问容器内的元素。next()也是python内置函数。在没有后续元素时,next()会抛出一个 StopIteration ==异常,通知for语句循环结束。
迭代器可以用来帮助我们记录每次迭代访问到的位置,当我们对迭代器使用next()函数的时候(调用了迭代器对象的_next_方法),迭代器会向我们返回它所记录位置的下一个位置的数据。
迭代器协议
对象需要提供next()方法,它要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代。
可迭代对象
实现了迭代器协议的对象。list、tuple、dict都是Iterable(可迭代对象),但不是Iterator(迭代器对象)。但可以使用内置函数iter(),把这些都变成Iterable(可迭代器对象)。
for item in Iterable 循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束
用迭代器实现斐波那契数列
>>> class Fibs:
def __init__(self):
self.a=0
self.b=1
def __iter__(self): //__iter__()返回迭代器本身
return self
def __next__(self): //__next__()制定迭代器的规则
self.a,self.b=self.b,self.a + self.b
return self.a
>>> fibs=Fibs()
>>> for each in fibs:
print(each)
1
1
2
3
5
8
13
21
34
55
89
144
233
377
生成器
Q:函数调用结束之后,一切都要从头再来,那么有没有办法让函数再退出之后还能保留状态呢?
A:①闭包(外层函数结束调用之后内层函数还是可以记住外层函数的参数)②生成器
Q:Python生成器是模仿协同程序实现的吗?
A:是的,协同程序是可以运行的独立函数调用,函数可以暂停或挂起,并在需要的时候从程序离开的地方继续或者重新开始。
定义
生成器使用yield语句来代替函数中的return语句,yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行。
使用
Q:如何使用生成器呢?
>>> def counter():
i=0
while i <= 5:
yield i //每次执行到yield语句时,就生成一个数据暂停并保留状态
i += 1 // 下一次调用从此处开始执行
>>> counter()
<generator object counter at 0x0000021CAB7DDF20>
>>> for i in counter():
print(i)
0
1
2
3
4
5
for语句的功能是从一个可迭代对象中每次获取一个数据;counter生成器的作用是每次调用的时候提供一个数据
Note:
- 生成器不像列表,元组这些可迭代对象,生成器是一个制作机器,作用是每调用一次提供一个数据,并且记住当时的状态,而列表,元组这些可迭代对象是容器,里面存放的是早已经生成好的所有数据
- 生成器是特殊的迭代器,支持next()函数,但是next函数不支持下标索引的方式。(因为并没有提前生成好)
>>> c=counter()
>>> c
<generator object counter at 0x0000021CAB81DBA0>
>>> next(c)
0
>>> next(c)
1
>>> next(c)
2
>>> next(c)
3
>>> next(c)
4
>>> next(c)
5
>>> next(c) //调用结束后,会抛出StopIteration异常
Traceback (most recent call last):
File "<pyshell#69>", line 1, in <module>
next(c)
StopIteration
用生成器实现斐波那契数列
# 菲波那切数列
def Fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return '亲!没有数据了...'
# 调用方法,生成出10个数来
f=Fib(10)
# 使用一个循环捕获最后return 返回的值,保存在异常StopIteration的value中
while True:
try:
x=next(f)
print("f:",x)
except StopIteration as e:
print("生成器最后的返回值是:",e.value)
break
>>> def fibs():
a=0
b=1
while True:
a,b=b,a+b
yield a
>>> for i in fibs():
if each > 100: //如果没有设置退出条件的话,会产生“无穷无尽项”,使用Ctrl+c停止
break
else:
print(each)
1
1
2
3
5
8
13
21
34
55
89
用闭包实现斐波那契数列
待更新…
生成器表达式
利用推导的形式获得生成器的方法,称为生成器表达式法:
>>> (i ** 2 for i in range(10))
<generator object <genexpr> at 0x0000021CAB81DC80>
>>> t=(i ** 2 for i in range(10))
>>> next(t) //每次产生一个数据
0
>>> for i in t:
print(i)
1
4
9
16
25
36
49
64
81
列表推导式(用方括号表示[]):
>>> a=[i for i in range(100) if not(i%2) and i%3]
>>> a
[2, 4, 8, 10, 14, 16, 20, 22, 26, 28, 32, 34, 38, 40, 44, 46, 50, 52, 56, 58, 62, 64, 68, 70, 74, 76, 80, 82, 86, 88, 92, 94, 98]
字典推导式(键值对):
>>> b={i:i%2==0 for i in range(10)}
>>> b
{0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False}
集合推导式(用{ }表示):
>>> c={i for i in [1,2,1,4,2,5,6,3,7,3]}
>>> c
{1, 2, 3, 4, 5, 6, 7}
元组推导式用圆括号表示(),就是生成器表达式
>>> e=(i for i in range(10))
>>> e
<generator object <genexpr> at 0x0000021CAB81DBA0>
>>> next(e)
0
>>> next(e)
1
>>> next(e)
2
>>> next(e)
3
>>> next(e)
4
>>> next(e)
5
>>> next(e)
6
>>> next(e)
7
>>> next(e)
8
>>> next(e)
9
>>> next(e)
Traceback (most recent call last):
File "<pyshell#198>", line 1, in <module>
next(e)
StopIteration
>>> sum(i for i in range(100) if i % 2)
2500
总结
实现生成器的两种方式:
- 将普通函数中的return替换成yield
- 使用生成器表达式