函数是Python里组织代码的最小单元,Python函数蕴含以下几个局部:
- 定义函数
- 调用函数
- 参数
- 函数的返回值
- 函数的嵌套
- 作用域
- 函数执行流程
- 递归函数
- 匿名函数
- 生成器
- 高阶函数
<!--more-->
定义函数
def add(x, y): # 函数定义 def 示意定义一个函数, 紧接着是函数名 函数名前面用一对小括号列出参数列表,参数列表前面应用一个冒号开始函数体 print(x + y) # 函数体是失常的Python语句,能够蕴含任意构造 return x + y # return 语句示意函数的返回值
函数是有输出(参数)和输入(返回值)的代码单元, 把输出转化为输入
调用函数
定义函数的时候,并不会执行函数体, 当调用函数的时候,才会执行其中的语句块
In [1]: def add(x, y): # 函数定义 def 示意定义一个函数, 紧接着是函数名 函数名前面用一对小括号 ...: print(x + y) # 函数体是失常的Python语句,能够蕴含任意构造 ...: return x + y # return 语句示意函数的返回值 ...: In [2]: add(3, 5) # 函数应用函数名来调用,函数名后紧跟一对小括号,小括号里传入函数定义时的参数8Out[2]: 8In [3]: add(3, 4, 5) # 传入参数必须和函数定义时的参数相匹配,如果不匹配,会抛出TypeError---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-3-a11d83d1db7e> in <module>()----> 1 add(3, 4, 5)TypeError: add() takes 2 positional arguments but 3 were given
参数
传参形式
In [5]: def add(x, y): ...: ret = x + y ...: print('{} + {} = {}'.format(x, y, x+y)) ...: return ret ...: In [6]: add(3, 5) #参数依照定义的程序传入,这样的传参办法叫做地位参数3 + 5 = 8Out[6]: 8In [7]: add(y=3, x=5) #参数依照定义时的变量名传递,这样的传参办法叫做关键字参数,关键字参数和程序无关5 + 3 = 8Out[7]: 8In [8]: add(5, y=3) # 地位参数和关键字参数能够混用5 + 3 = 8Out[8]: 8In [9]: add(x=3, 5) # 地位参数不能放在关键字参数的前面 File "<ipython-input-9-165b39de39ac>", line 1 add(x=3, 5) ^SyntaxError: positional argument follows keyword argumentIn [10]: add('3', '5') # python是动静语言,传入的参数类型能够不固定3 + 5 = 35Out[10]: '35'In [11]: add(3, '5') # python是强类型语言,传入的参数须要满足强类型要求,否则会抛出TypeError---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-11-335767c130e1> in <module>()----> 1 add(3, '5')<ipython-input-5-e720706d1634> in add(x, y) 1 def add(x, y):----> 2 ret = x + y 3 print('{} + {} = {}'.format(x, y, x+y)) 4 return retTypeError: unsupported operand type(s) for +: 'int' and 'str'
参数默认值
参数能够有默认值,当一个参数有默认值时, 调用时如果不传递此参数,会应用默认值
In [12]: def inc(x, y=1): # 参数y默认为1 ...: x += y ...: return x ...: In [13]: inc(3) # 传参时只须要传入x即可Out[13]: 4In [14]: inc(3, 2)Out[14]: 5In [15]: def inc(x=1, y): # 默认参数不能再非默认参数之前 ...: return x + y File "<ipython-input-15-993be842d592>", line 1 def inc(x=1, y): ^SyntaxError: non-default argument follows default argumentIn [16]: def connect(host='127.0.0.1', port=3306, user='root', password='', dbname='test'): ...: pass ...: In [17]: connect('192.168.110.13',password='123456')
参数默认值和关键字参数一起应用,会让代码十分简洁
可变参数
可变参数两种模式:
- 地位可变参数 : 参数名前加一个星号, 形成元组, 传参只能以地位参数的模式
- 关键字可变参数: 参数名前加两个信号, 形成字典, 传参只能以关键字参数的模式
地位可变参数
In [18]: def sum(*lst): ...: print(type(lst)) ...: ret = 0 ...: for x in lst: ...: ret += x ...: return ret ...: # 参数前加一个星号, 示意这个参数是可变的, 也就是能够承受任意多个参数, 这些参数将形成一个元组, 此时只能通过地位参数传参In [19]: sum(1, 2, 3)<class 'tuple'>Out[19]: 6
关键字可变参数
In [20]: def connect(**kwargs): ...: print(type(kwargs)) ...: for k, v in kwargs.items(): ...: print('{} => {}'.format(k, v)) ...: # 参数前加两个星号, 示意这个参数是可变的,能够承受任意多个参数, 这些参数形成一个字典,此时只能通过关键字参数传参In [21]: connect(host='127.0.0.1',port=3306)<class 'dict'>host => 127.0.0.1port => 3306
地位可变参数和关键字可变参数混合应用
In [22]: def fn(*args, **kwargs): ...: print(args) ...: print(kwargs) ...: In [23]: fn(1, 2, 3, a=4, b=5)(1, 2, 3){'a': 4, 'b': 5}# 以上阐明地位可变参数和关键字可变参数能够混合应用In [24]: def fn(**kwargs, *args): File "<ipython-input-24-e42478d184b2>", line 1 def fn(**kwargs, *args): ^SyntaxError: invalid syntax# 以上阐明当地位可变参数和关键字可变参数一起应用时, 地位可变参数必须在后面
可变参数和一般参数混合应用
一般参数能够和可变参数一起应用,然而传参的时候必须匹配,演示如下
In [25]: def fn(x, y, *args, **kwargs): ...: print(x) ...: print(y) ...: print(args) ...: print(kwargs) ...: In [26]: fn(2, 3, 4, 5, 7, a=1, b=2)23(4, 5, 7){'a': 1, 'b': 2}In [27]: fn(2, 3)23(){}In [28]: fn(2, 3, 4, 5, x=1) # x有两个值,一个2,一个1,所以抛出TypeError---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-28-0f8d856dee50> in <module>()----> 1 fn(2, 3, 4, 5, x=1)TypeError: fn() got multiple values for argument 'x'In [29]: fn(2, y=3)23(){}
地位可变参数能够在一般参数之前, 然而在地位可变参数之后的一般参数变成了keyword-only参数:
In [30]: def fn(*args, x): ...: print(args) ...: print(x) ...: In [31]: fn(2, 3, 4)---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-31-fab2f7df0315> in <module>()----> 1 fn(2, 3, 4)TypeError: fn() missing 1 required keyword-only argument: 'x'In [32]: fn(2, 3, x=4) # 必须将地位可变参数之后的一般参数变成keyword-only,否则TypeError(2, 3)4
关键字可变参数不容许在一般参数之前,演示如下:
In [33]: def fn(**kwargs, x=5): File "<ipython-input-33-889f99c1c889>", line 1 def fn(**kwargs, x=5): ^SyntaxError: invalid syntax
对于默认参数和可变参数的总结:
通常来说:
- 默认参数靠后
- 可变参数靠后
- 默认参数和可变参数个别不同时呈现
- 当默认参数和可变参数一起呈现的时候, 默认参数相当于一般参数
参数解构
参数解构有两种模式
- 一个星号 解构的对象:可迭代对象 ,解构的后果:地位参数
- 两个星号 解构的对象:字典 ,解构的后果:关键字参数
一个星号的状况
In [34]: def add(x, y): ...: ret = x + y ...: print('{} + {} = {}'.format(x, y, ret)) ...: return ret ...: In [35]: add(1, 2)1 + 2 = 3Out[35]: 3In [36]: add(x=1, y=2)1 + 2 = 3Out[36]: 3In [37]: t = [1, 2]In [38]: add(t[0], t[1]) # 如果列表中的元素很多的时候,一个一个解开很不不便简洁1 + 2 = 3Out[38]: 3In [39]: add(*t) # 地位参数解构 加一个星号, 能够把可迭代对象解形成地位参数1 + 2 = 3Out[39]: 3In [40]: add(*range(2))0 + 1 = 1Out[40]: 1
二个星号
In [42]: d = {'x': 1, 'y':2}In [43]: add(**d)1 + 2 = 3Out[43]: 3
参数解构产生在函数调用时, 可变参数产生函数定义时,所以两者并不抵触
In [46]: def sum(*args): # 可变参数产生在函数定义时 ...: ret = 0 ...: for x in args: ...: ret += x ...: return ret ...: In [47]: sum(*range(10)) # 参数解构产生在函数调用时Out[47]: 45In [48]: def fn(**kwargs): ...: print(kwargs) ...: In [49]: fn(**{'a-b':1}){'a-b': 1}In [50]: fn(**{123:1}) # 关键字参数解构, key必须是str---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-50-3c8b8b3fdf0b> in <module>()----> 1 fn(**{123:1})TypeError: fn() keywords must be strings
keyword-only 参数
应用办法参见:Python: 函数参数列表中单个星号的意思,Keyword-Only Arguments
星号能够以一个参数的模式呈现在函数申明中的参数列表中,但星号之后的所有参数都必须有关键字(keyword),这样在函数调用时,星号*之后的所有参数都必须以keyword=value
的模式调用,而不能以地位顺序调用。
应用示例如下:也可参考下面链接中的示例
In [54]: def fn(*, x): ...: print(x) ...: In [55]: fn(3)---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-55-f005f2a6106f> in <module>()----> 1 fn(3)TypeError: fn() takes 0 positional arguments but 1 was givenIn [56]: fn(x=3)3In [57]: def fn(x, *, y): ...: print(x) ...: print(y) ...: In [58]: fn(1, y=2)12In [59]: fn(1, 2)---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-59-c159019d3516> in <module>()----> 1 fn(1, 2)TypeError: fn() takes 1 positional argument but 2 were given
函数的返回值
- return 语句除了返回值之外,还会完结函数, return之后的语句将不会被执行
- 一个函数能够有多个return语句, 执行到哪个return由哪个return返回后果并完结函数
- 函数中 return能够提前结束循环
- 当函数没有return语句的时候,返回None
- 当函数须要返回多个值时, 能够用封装把返回值封装成一个元组
- 能够通过解构获取到多返回值
- return None 能够简写为 return, 通常用于完结函数
In [63]: def fn(x): ...: for i in range(x): ...: if i > 3: ...: return i # return能够提前退出循环 ...: else: ...: print('not bigger than 3') ...: In [64]: fn(2)not bigger than 3In [65]: fn(10) Out[65]: 4In [66]: def fn(): ...: pass # 没有return时返回的是None ...: In [67]: ret = fn()In [68]: retIn [69]: type(ret)Out[69]: NoneTypeIn [70]: def fn(): ...: return 3, 5 # 当函数须要返回多个值时, 会把返回值封装成一个元组 ...: In [71]: ret = fn()In [72]: type(ret)Out[72]: tupleIn [73]: x, y = fn() # 能够通过解构获取多个返回值
函数的嵌套
函数能够嵌套应用
In [75]: def outter(): ...: def inner(): ...: print('inner') ...: print('outter') ...: inner() ...: In [76]: outter()outterinner
作用域
变量的作用域为定义此变量的作用域
In [6]: def fn(): # 变量的作用域为定义此变量的作用域 ...: xx = 1 ...: print(xx) ...: In [7]: fn()1In [8]: xx---------------------------------------------------------------------------NameError Traceback (most recent call last)<ipython-input-8-102f5037fe64> in <module>()----> 1 xxNameError: name 'xx' is not defined
表明变量的作用域就在fn函数之中
下级作用域对上级作用域只读可见
不同作用域变量不可见, 然而上级作用域能够对下级作用域的变量只读可见
In [9]: def fn(): # 下级作用域对上级作用域可见 ...: xx = 1 ...: print(xx) ...: def inner(): ...: print(xx) ...: inner() ...: In [10]: fn()11In [11]: def fn(): # 下级作用域对上级作用域只读可见 ...: xx = 1 ...: print(xx) ...: def inner(): ...: xx = 2 ...: inner() ...: print(xx) ...: In [12]: fn()11 # 能够发现xx并没有被上级作用域批改
不要应用全局变量global
除非你分明的晓得global会带来什么,并且明确的晓得,非global不行, 否则不要应用global
In [13]: xx = 1In [14]: def fn(): ...: global xx # global 能够晋升变量作用域为全局变量 ...: xx += 1 ...: In [15]: fn()In [16]: xxOut[16]: 2
闭包函数
闭包定义(Wikipedia):在一些语言中,在函数中能够(嵌套)定义另一个函数时,如果外部的函数援用了内部的函数的变量,则可能产生闭包。闭包能够用来在一个函数与一组“公有”变量之间创立关联关系。在给定函数被屡次调用的过程中,这些公有变量可能放弃其持久性
艰深了解:当某个函数被当成对象返回时,夹带了内部变量,就造成了一个闭包。
如果咱们想实现一个有限增长的计数器,能够写一个counter函数,函数外部进行自增就行。假设咱们依照以下写法:就会报错
In [17]: def counter(): ...: c = 0 ...: def inc(): ...: c += 1 # c[0] = c[0] + 1 ...: return c ...: return inc ...: In [18]: f = counter()In [19]: f()---------------------------------------------------------------------------UnboundLocalError Traceback (most recent call last)<ipython-input-19-0ec059b9bfe1> in <module>()----> 1 f()<ipython-input-17-9dd4cd4942f6> in inc() 2 c = 0 3 def inc():----> 4 c += 1 # c[0] = c[0] + 1 5 return c 6 return incUnboundLocalError: local variable 'c' referenced before assignment
在 python 的函数内,能够间接援用内部变量,但不能改写内部变量,因而如果在闭包中间接改写父函数的变量,就会产生谬误。比方上述程序间接改写父函数中的变量c
python的闭包中如果想改写父函数的变量能够用可变容器实现,这也是python2实现的惟一形式
In [1]: def counter(): ...: c=[0] ...: def inc(): ...: c[0] += 1 ...: return c[0] ...: return inc ...: In [2]: f = counter()In [3]: fOut[3]: <function __main__.counter.<locals>.inc>In [4]: f()Out[4]: 1In [5]: f()Out[5]: 2In [6]: f()Out[6]: 3
nonlocal关键字
在python3中改写父变量还有一种方就是应用nonlocal
关键字
nonlocal 关键字用于标记一个变量由他的下级作用域定义, 通过nonlocal标记的变量, 可读可写
In [7]: def counter(): ...: c = 0 ...: def inc(): ...: nonlocal c ...: c += 1 ...: return c ...: return inc ...: In [8]: f = counter()In [9]: fOut[9]: <function __main__.counter.<locals>.inc>In [10]: f()Out[10]: 1In [11]: f()Out[11]: 2
如果下级没有定义nonlocal的变量,应用nonlocal时会抛出语法错误
In [12]: def fn(): ...: nonlocal xxx File "<ipython-input-12-2d2b8104e945>", line 2 nonlocal xxxSyntaxError: no binding for nonlocal 'xxx' found
函数的__defaults__
属性
可变参数和不可变参数的__defaults__
属性不一样
参数可变时
当应用可变类型作为默认值参数默认值时,须要特地留神,会扭转函数的__default__
属性
In [1]: def fn(xxyy=[]): ...: xxyy.append(1) ...: print(xxyy) ...: In [2]: fn()[1]In [3]: fn()[1, 1]In [4]: fn.__defaults__ # 参数是函数对象的属性Out[4]: ([1, 1],)In [5]: fn()[1, 1, 1]In [6]: fn.__defaults__ # 所有的函数参数封装成一个元组,第一个函数参数时列表在动态变化Out[6]: ([1, 1, 1],)
参数不可变时
应用不可变类型作为默认值,函数体内不扭转默认值
In [8]: def fn(x=0, y=0): ...: x = 3 # 赋值即定义 ...: y = 3 # 赋值即定义 ...: In [9]: fn.__defaults__Out[9]: (0, 0)In [10]: fn()In [11]: fn.__defaults__Out[11]: (0, 0)
可变参数时None的应用
通常如果应用一个可变类型作为默认参数时, 会应用None来代替
In [1]: def fn(lst=None): # 向一个列表中插入元素3,列表默认为None ...: if lst is None: ...: lst = [] ...: lst.append(3) ...: print(lst) ...: In [2]: fn.__defaults__ # 函数的__defaults__属性就是可变参数对应的NoneOut[2]: (None,)In [3]: fn()[3]In [4]: fn() # 如果不传入值,函数执行的时候会先创立一个空列表,而后append[3]In [5]: fn.__defaults__Out[5]: (None,)In [6]: fn([1,2])[1, 2, 3]In [7]: fn.__defaults__ # 传入值之后,也不会扭转函数的__default__属性Out[7]: (None,)
Python作用域、闭包、装璜器材料
- Python 的闭包和装璜器
- 说说Python中的闭包 - Closure
- Python Enclosing作用域、闭包、装璜器话聊上篇
- Python Enclosing作用域、闭包、装璜器话聊下篇
函数执行流程
函数的执行过程就是压栈和出栈的过程。具体如下
当调用函数的时候, 解释器会把以后现场压栈,而后开始执行被调函数, 被调函数执行实现,解释器弹出以后栈顶,复原现场
递归函数
递归函数的定义就是函数调用函数本身。
- 递归函数必须要有退出条件
- 为了爱护解释器, Python对最大递归深度有限度
- 绝大多数递归都能够转化为循环应用
- 尽量避免应用递归
- sys模块中的getrecursionlimit和setrecursionlimit能够获取和设置最大递归深度
匿名函数
In [1]: lambda x: x + 1Out[1]: <function __main__.<lambda>>
匿名函数有以下特点
- lambda来定义
- 参数列表不须要用小括号
- 冒号不是用来开启新语句块
- 没有return,最初一个表达式的值即返回值
- 匿名函数(lambda表达式)只能写在一行上,所以也叫单行函数
匿名函数的益处是
- 函数没有名字,不用放心函数名抵触
- 匿名函数也是一个函数对象,能够把匿名函数返回给一个变量,再利用变量调用函数
In [1]: lambda x: x + 1Out[1]: <function __main__.<lambda>>In [2]: f = lambda x: x + 1 # 间接把lambda函数返回给变量fIn [3]: f(3) # 由变量f调用函数Out[3]: 4In [4]: f(5)Out[4]: 6In [5]: (lambda x: x * 2)(3) # 第一对括号用来扭转优先级 第二对括号示意函数调用Out[5]: 6In [6]: (lambda : 1)() # lambda示意式参数能够为空Out[6]: 1In [7]: (lambda x, y: x + y)(3, 5) # lambda表达式的地位参数Out[7]: 8In [8]: (lambda *args: args)(*range(3)) # lambda表达式的地位可变参数Out[8]: (0, 1, 2)In [9]: (lambda *args, **kwargs: print(args, kwargs))(*range(3), **{str(x):x for x in range(3)}) # lambda表达式的地位可变参数和关键字可变参数(0, 1, 2) {'0': 0, '1': 1, '2': 2}In [10]: (lambda *, x: x)(x=3) # *号前面的地位参数必须应用关键字参数Out[10]: 3
一般函数所反对的参数的变动,匿名函数都反对
匿名函数的常见用法:通常用于高阶函数的参数, 当此函数十分短小的时候,就适宜应用匿名函数
比方匿名函数能够作为sorted
函数的自定义键函数(custom key function)
In [11]: help(sorted) Help on built-in function sorted in module builtins: sorted(iterable, key=None, reverse=False) Return a new list containing all items from the iterable in ascending order. A custom key function can be supplied to customise the sort order, and the reverse flag can be set to request the result in descending order.In [12]: from collections import namedtupleIn [13]: point = namedtuple('point',['x','y']) # 定义命名元组pointIn [14]: points = [point(1, 2), point(4, 3), point(8, 9)]In [15]: def getY(point): ...: return point.y ...: In [16]: sorted(points, key=getY) # 简短的函数能够作为自定义键函数Out[16]: [point(x=1, y=2), point(x=4, y=3), point(x=8, y=9)]In [17]: sorted(points, key=lambda x: x.y) # lambda示意也能够作为自定义键函数Out[17]: [point(x=1, y=2), point(x=4, y=3), point(x=8, y=9)]
高阶函数
高阶函数的定义
高阶函数英文叫Higher-order function。
在数学和计算机科学中,高阶函数是至多满足下列一个条件的函数:
- 承受一个或多个函数作为输出:通常用于大多数逻辑固定,少部分逻辑不固定的场景
- 输入一个函数:函数作为返回值: 通常是用于闭包的场景, 须要封装一些变量
常见的高阶函数有map,reduce,filter
高阶函数:插入排序
插入排序时,排序程序分为升序和降序,咱们能够应用一个函数作为插入排序函数的参数来管制是升序还是降序。
首先看一下依照升序插入排序,而后再改良成升序降序可控的插入排序
def insertSort(iter): ret = [] for x in iter: for i, y in enumerate(ret): if x < y: # 批改处 ret.insert(i, x) break else: ret.append(x) return ret
如果想让这个函数降序排序,则只须要批改代码中的正文处,改成x > y
即可
如果传入一个函数来管制if前面的bool值,则就实现了通过参数管制升降了
def insertSort(iter, cmp = lambda x, y: x < y): ret = [] for x in iter: for i, y in enumerate(ret): if cmp(x, y): ret.insert(i, x) break else: ret.append(x) return ret
这个函数就默认为升序排序了,然而能够传入一个比拟函数变成降序,如下
lst = insertSort([1, 3, 2, 4, 6, 8, 5],lambda x, y: x > y)
map
map()
函数原型:map(func, *iterables) --> map object
map()
函数接管两个参数,一个是函数func
,一个是可迭代对象Iterable
,map
将传入的函数顺次作用到可迭代对象的每个元素,并把后果放入map对象
这个迭代器中。所以map
函数是高阶函数。
map
类中存在__iter__
和__next__
函数
map应用示例
把list中的所有数字的平方
In [1]: def f(x): # 定义平方函数f ...: return x ** 2 ...: In [2]: ret = map(f, [1, 2, 3, 4, 5, 6, 7]) # 函数f和列表作为map的参数In [3]: ret # map的返回值只是一个返回值Out[3]: <map at 0x7f2d539a7470>In [4]: next(ret) # 能够用next办法输入map的后果Out[4]: 1In [5]: next(ret)Out[5]: 4In [6]: lst = list(ret) # 也能够用list函数计算出所有的值In [7]: lstOut[7]: [9, 16, 25, 36, 49]
reduce
map
函数是map
类的函数,然而reduce函数属于functools
包的reduce
模块中
from functools import reduce
而后能够应用help
办法查看reduce
函数的应用
help(reduce)
输入后果如下
Help on built-in function reduce in module _functools:reduce(...) reduce(function, sequence[, initial]) -> value Apply a function of two arguments cumulatively to the items of a sequence, from left to right, so as to reduce the sequence to a single value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates ((((1+2)+3)+4)+5). If initial is present, it is placed before the items of the sequence in the calculation, and serves as a default when the sequence is empty.
reduce应用示例
- 输入1到10的和
def add(x,y): return x + yprint(reduce(add, range(1, 11)))
输入后果为55
- 把字符串转化为
int
,不实用int()
函数
def str2int(s): def char2num(c): return {'0': 0, '1': 1, '2': 2 ,'3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[c] def f(x, y): return 10 * x + y return reduce(f, map(char2num, s))
str2int('1234321') => 1234321
filter
help(filter)
之后能够发现filter
是一个类,其中有一个filter
函数,原型如下
filter(function or None, iterable) --> filter object
和map()
相似,filter()
也接管一个函数和一个序列。和map()
不同的是,filter()
把传入的函数顺次作用于每个元素,而后依据返回值是True
还是False
决定保留还是抛弃该元素。返回值也是一个迭代器。
filter应用示例
应用filter筛选出list中的回文数
def is_palindrome(n): m = str(n) for i in range(len(m)//2): if m[i] != m[len(m) - i -1]: return False else: return Truelst = list(filter(is_palindrome, [12321, 194, 13431]))print(lst)# 后果: [12321, 13431]
所以filter()
函数用于过滤序列,重点在于抉择一个正确的筛选函数。
生成器
带yield语句的函数称之为生成器函数, 生成器函数的返回值是生成器
- 生成器函数执行的时候,不会执行函数体
- 当next生成器的时候, 以后代码执行到之后的第一个yield,会弹出值,并且暂停函数
- 当再次next生成器的时候,从上次暂停处开始往下执行
- 当没有多余的yield的时候,会抛出StopIteration异样,异样的value是函数的返回值
生成器的根本模式
In [1]: def g(): ...: for x in range(5): ...: yield x # 弹出x ...: In [2]: r = g() # 函数调用实现之后函数现场并没有被销毁In [3]: rOut[3]: <generator object g at 0x7f0e18543990>In [4]: next(r)Out[4]: 0In [5]: next(r)Out[5]: 1In [6]: for x in r: ...: print(x) ...: 234
生成器的执行程序
In [1]: def g(): ...: print('a') ...: yield 1 ...: print('b') ...: yield 2 ...: return 3 ...: In [2]: r = g() # 执行生成器函数的时候函数并没有被执行 In [3]: next(r) # 执行到第一个yield就进行执行aOut[3]: 1In [4]: next(r) # 执行到第二个yield就进行执行bOut[4]: 2In [5]: next(r) # 从第二个yield开始,当没有更多yield的时候,抛出StopIteration异样,异样的值正好是return的返回值---------------------------------------------------------------------------StopIteration Traceback (most recent call last)<ipython-input-5-0b5056469c9c> in <module>()----> 1 next(r)StopIteration: 3
生成器的利用
计数器第一种模式
In [1]: def counter(): ...: x = 0 ...: while True: ...: x += 1 ...: yield x # 每次将+1之后的x弹出 ...: In [2]: def inc(c): ...: return next(c) ...: In [3]: c = counter() # counter函数执行的后果就是一个生成器,所以c就是生成器In [4]: inc(c)Out[4]: 1In [5]: inc(c)Out[5]: 2
计数器第二种模式
In [6]: def make_inc(): ...: def counter(): ...: x = 0 ...: while True: ...: x += 1 ...: yield x ...: c = counter() ...: return lambda : next(c) # 应用lambda表达式将next(c)作为函数返回,而不是只返回一个next(c) ...: In [7]: make_inc()Out[7]: <function __main__.make_inc.<locals>.<lambda>> # make_inc实质是一个匿名函数In [8]: inc = make_inc()In [9]: inc()Out[9]: 1In [10]: inc()Out[10]: 2
斐波拉契数列
In [11]: def fib(): ...: a = 1 ...: b = 1 ...: while True: ...: yield a ...: a, b = b, a + b ...: In [12]: fib()Out[12]: <generator object fib at 0x7f9ff2746830>In [13]: f = fib() # 生成器fIn [15]: next(f)Out[15]: 1In [16]: next(f)Out[16]: 1In [17]: next(f)Out[17]: 2In [18]: next(f)Out[18]: 3In [19]: g = fib()In [20]: ret = [] # 将yield的值都保留在ret中In [21]: for _ in range(1000): # 遍历生成器 ...: ret.append(next(g)) ...: In [22]: ret[-1] # 取ret列表的最初一个元素值,速度很快Out[22]: 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875
生成器的高级用法
生成器的高级用法是协程
- 协程:协程运行在一个线程之内, 在用户态调度
生成器参考资料
- python生成器到底有什么长处?
- Understanding Generators in Python
- Introduction to Python Generators
- 生成器材料汇总
记得帮我点赞哦!
精心整顿了计算机各个方向的从入门、进阶、实战的视频课程和电子书,依照目录正当分类,总能找到你须要的学习材料,还在等什么?快去关注下载吧!!!
朝思暮想,必有回响,小伙伴们帮我点个赞吧,非常感谢。
我是职场亮哥,YY高级软件工程师、四年工作教训,回绝咸鱼争当龙头的斜杠程序员。听我说,提高多,程序人生一把梭
如果有幸能帮到你,请帮我点个【赞】,给个关注,如果能顺带评论给个激励,将不胜感激。
职场亮哥文章列表:更多文章
自己所有文章、答复都与版权保护平台有单干,著作权归职场亮哥所有,未经受权,转载必究!