乐趣区

关于python:Python函数详解

函数是 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) # 函数应用函数名来调用,函数名后紧跟一对小括号,小括号里传入函数定义时的参数
8
Out[2]: 8

In [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 = 8
Out[6]: 8

In [7]: add(y=3, x=5) #参数依照定义时的变量名传递,这样的传参办法叫做关键字参数,关键字参数和程序无关
5 + 3 = 8
Out[7]: 8

In [8]: add(5, y=3) # 地位参数和关键字参数能够混用
5 + 3 = 8
Out[8]: 8

In [9]: add(x=3, 5)    # 地位参数不能放在关键字参数的前面
  File "<ipython-input-9-165b39de39ac>", line 1
    add(x=3, 5)
            ^
SyntaxError: positional argument follows keyword argument


In [10]: add('3', '5')    # python 是动静语言,传入的参数类型能够不固定
3 + 5 = 35
Out[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 ret

TypeError: 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]: 4

In [14]: inc(3, 2)
Out[14]: 5

In [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 argument


In [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.1
port => 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)
2
3
(4, 5, 7)
{'a': 1, 'b': 2}

In [27]: fn(2, 3)
2
3
()
{}

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)
2
3
()
{}

地位可变参数能够在一般参数之前,然而在地位可变参数之后的一般参数变成了 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 = 3
Out[35]: 3

In [36]: add(x=1, y=2)
1 + 2 = 3
Out[36]: 3

In [37]: t = [1, 2]

In [38]: add(t[0], t[1])    # 如果列表中的元素很多的时候,一个一个解开很不不便简洁
1 + 2 = 3
Out[38]: 3

In [39]: add(*t)    # 地位参数解构  加一个星号,能够把可迭代对象解形成地位参数
1 + 2 = 3
Out[39]: 3

In [40]: add(*range(2))
0 + 1 = 1
Out[40]: 1

二个星号

In [42]: d = {'x': 1, 'y':2}

In [43]: add(**d)
1 + 2 = 3
Out[43]: 3

参数解构产生在函数调用时,可变参数产生函数定义时,所以两者并不抵触

In [46]: def sum(*args):    # 可变参数产生在函数定义时
    ...:     ret = 0
    ...:     for x in args:
    ...:         ret += x
    ...:     return ret
    ...: 

In [47]: sum(*range(10))    # 参数解构产生在函数调用时
Out[47]: 45

In [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 given

In [56]: fn(x=3)
3

In [57]: def fn(x, *, y):
    ...:     print(x)
    ...:     print(y)
    ...:     

In [58]: fn(1, y=2)
1
2

In [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 3

In [65]: fn(10)    
Out[65]: 4

In [66]: def fn():
    ...:     pass    # 没有 return 时返回的是 None
    ...: 

In [67]: ret = fn()

In [68]: ret

In [69]: type(ret)
Out[69]: NoneType

In [70]: def fn():
    ...:     return 3, 5    # 当函数须要返回多个值时,会把返回值封装成一个元组
    ...: 

In [71]: ret = fn()

In [72]: type(ret)
Out[72]: tuple

In [73]: x, y = fn()    # 能够通过解构获取多个返回值

函数的嵌套

函数能够嵌套应用

In [75]: def outter():
    ...:     def inner():
    ...:         print('inner')
    ...:     print('outter')
    ...:     inner()
    ...:     

In [76]: outter()
outter
inner

作用域

变量的作用域为定义此变量的作用域

In [6]: def fn(): # 变量的作用域为定义此变量的作用域
   ...:         xx = 1
   ...:         print(xx)
   ...:     

In [7]: fn()
1

In [8]: xx
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-8-102f5037fe64> in <module>()
----> 1 xx

NameError: name 'xx' is not defined

表明变量的作用域就在 fn 函数之中

下级作用域对上级作用域只读可见

不同作用域变量不可见,然而上级作用域能够对下级作用域的变量只读可见

In [9]: def fn():    # 下级作用域对上级作用域可见
   ...:     xx = 1
   ...:     print(xx)
   ...:     def inner():
   ...:         print(xx)
   ...:     inner()
   ...:     

In [10]: fn()
1
1

In [11]: def fn():    # 下级作用域对上级作用域只读可见
    ...:     xx = 1
    ...:     print(xx)
    ...:     def inner():
    ...:         xx = 2
    ...:     inner()
    ...:     print(xx)
    ...:     

In [12]: fn()
1
1    # 能够发现 xx 并没有被上级作用域批改

不要应用全局变量 global

除非你分明的晓得 global 会带来什么,并且明确的晓得,非 global 不行,否则不要应用 global

In [13]: xx = 1

In [14]: def fn():
    ...:     global xx    # global 能够晋升变量作用域为全局变量
    ...:     xx += 1
    ...:     

In [15]: fn()

In [16]: xx
Out[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 inc

UnboundLocalError: 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]: f
Out[3]: <function __main__.counter.<locals>.inc>

In [4]: f()
Out[4]: 1

In [5]: f()
Out[5]: 2

In [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]: f
Out[9]: <function __main__.counter.<locals>.inc>

In [10]: f()
Out[10]: 1

In [11]: f()
Out[11]: 2

如果下级没有定义 nonlocal 的变量,应用 nonlocal 时会抛出语法错误

In [12]: def fn():
    ...:     nonlocal xxx
  File "<ipython-input-12-2d2b8104e945>", line 2
    nonlocal xxx
SyntaxError: 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__属性就是可变参数对应的 None
Out[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 + 1
Out[1]: <function __main__.<lambda>>

匿名函数有以下特点

  • lambda 来定义
  • 参数列表不须要用小括号
  • 冒号不是用来开启新语句块
  • 没有 return,最初一个表达式的值即返回值
  • 匿名函数(lambda 表达式)只能写在一行上,所以也叫单行函数

匿名函数的益处是

  • 函数没有名字,不用放心函数名抵触
  • 匿名函数也是一个函数对象,能够把匿名函数返回给一个变量,再利用变量调用函数
In [1]: lambda x: x + 1
Out[1]: <function __main__.<lambda>>

In [2]: f = lambda x: x + 1        # 间接把 lambda 函数返回给变量 f

In [3]: f(3)                    # 由变量 f 调用函数
Out[3]: 4

In [4]: f(5)
Out[4]: 6

In [5]: (lambda x: x * 2)(3)    # 第一对括号用来扭转优先级 第二对括号示意函数调用
Out[5]: 6

In [6]: (lambda : 1)()            # lambda 示意式参数能够为空
Out[6]: 1

In [7]: (lambda x, y: x + y)(3, 5)    # lambda 表达式的地位参数
Out[7]: 8

In [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 namedtuple

In [13]: point = namedtuple('point',['x','y'])    # 定义命名元组 point

In [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,一个是可迭代对象Iterablemap 将传入的函数顺次作用到可迭代对象的每个元素,并把后果放入 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]: 1

In [5]: next(ret)
Out[5]: 4

In [6]: lst = list(ret)                            # 也能够用 list 函数计算出所有的值

In [7]: lst
Out[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 + y
print(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}
    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 True

lst = 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]: r
Out[3]: <generator object g at 0x7f0e18543990>

In [4]: next(r)
Out[4]: 0

In [5]: next(r)
Out[5]: 1

In [6]: for x in r:
    ...:     print(x)
    ...:     
2
3
4

生成器的执行程序

In [1]: def g():
   ...:     print('a')
   ...:     yield 1
   ...:     print('b')
   ...:     yield 2
   ...:     return 3
   ...: 

In [2]: r = g()    # 执行生成器函数的时候函数并没有被执行 

In [3]: next(r)    # 执行到第一个 yield 就进行执行
a
Out[3]: 1

In [4]: next(r)    # 执行到第二个 yield 就进行执行
b
Out[4]: 2

In [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]: 1

In [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]: 1

In [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()    # 生成器 f

In [15]: next(f)
Out[15]: 1

In [16]: next(f)
Out[16]: 1

In [17]: next(f)
Out[17]: 2

In [18]: next(f)
Out[18]: 3

In [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 高级软件工程师、四年工作教训,回绝咸鱼争当龙头的斜杠程序员。

听我说,提高多,程序人生一把梭

如果有幸能帮到你,请帮我点个【赞】,给个关注,如果能顺带评论给个激励,将不胜感激。

职场亮哥文章列表:更多文章

自己所有文章、答复都与版权保护平台有单干,著作权归职场亮哥所有,未经受权,转载必究!

退出移动版