小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Python函數(shù)詳解

 nxhujiee 2023-04-26 發(fā)布于寧夏

函數(shù)是Python里組織代碼的最小單元,Python函數(shù)包含以下幾個(gè)部分:

  • 定義函數(shù)
  • 調(diào)用函數(shù)
  • 參數(shù)
  • 函數(shù)的返回值
  • 函數(shù)的嵌套
  • 作用域
  • 函數(shù)執(zhí)行流程
  • 遞歸函數(shù)
  • 匿名函數(shù)
  • 生成器
  • 高階函數(shù)

定義函數(shù)

def add(x, y):     # 函數(shù)定義 def 表示定義一個(gè)函數(shù), 緊接著是函數(shù)名 函數(shù)名后面用一對小括號(hào)列出參數(shù)列表,參數(shù)列表后面使用一個(gè)冒號(hào)開始函數(shù)體
    print(x + y)   # 函數(shù)體是正常的Python語句,可以包含任意結(jié)構(gòu)
    return  x + y  # return 語句表示函數(shù)的返回值

函數(shù)是有輸入(參數(shù))和輸出(返回值)的代碼單元, 把輸入轉(zhuǎn)化為輸出

調(diào)用函數(shù)

定義函數(shù)的時(shí)候,并不會(huì)執(zhí)行函數(shù)體, 當(dāng)調(diào)用函數(shù)的時(shí)候,才會(huì)執(zhí)行其中的語句塊

In [1]: def add(x, y):     # 函數(shù)定義 def 表示定義一個(gè)函數(shù), 緊接著是函數(shù)名 函數(shù)名后面用一對小括號(hào)
   ...:         print(x + y)   # 函數(shù)體是正常的Python語句,可以包含任意結(jié)構(gòu)
   ...:         return  x + y  # return 語句表示函數(shù)的返回值
   ...: 

In [2]: add(3, 5) # 函數(shù)使用函數(shù)名來調(diào)用,函數(shù)名后緊跟一對小括號(hào),小括號(hào)里傳入函數(shù)定義時(shí)的參數(shù)
8
Out[2]: 8

In [3]: add(3, 4, 5) # 傳入?yún)?shù)必須和函數(shù)定義時(shí)的參數(shù)相匹配,如果不匹配,會(huì)拋出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

參數(shù)

傳參方式

In [5]: def add(x, y):
   ...:     ret = x + y
   ...:     print('{} + {} = {}'.format(x, y, x+y))
   ...:     return ret
   ...: 

In [6]: add(3, 5) #參數(shù)按照定義的順序傳入,這樣的傳參方法叫做位置參數(shù)
3 + 5 = 8
Out[6]: 8

In [7]: add(y=3, x=5) #參數(shù)按照定義時(shí)的變量名傳遞,這樣的傳參方法叫做關(guān)鍵字參數(shù),關(guān)鍵字參數(shù)和順序無關(guān)
5 + 3 = 8
Out[7]: 8

In [8]: add(5, y=3) # 位置參數(shù)和關(guān)鍵字參數(shù)可以混用
5 + 3 = 8
Out[8]: 8

In [9]: add(x=3, 5)    # 位置參數(shù)不能放在關(guān)鍵字參數(shù)的后面
  File "<ipython-input-9-165b39de39ac>", line 1
    add(x=3, 5)
            ^
SyntaxError: positional argument follows keyword argument


In [10]: add('3', '5')    # python是動(dòng)態(tài)語言,傳入的參數(shù)類型可以不固定
3 + 5 = 35
Out[10]: '35'

In [11]: add(3, '5') # python是強(qiáng)類型語言,傳入的參數(shù)需要滿足強(qiáng)類型要求,否則會(huì)拋出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'

參數(shù)默認(rèn)值

參數(shù)可以有默認(rèn)值,當(dāng)一個(gè)參數(shù)有默認(rèn)值時(shí), 調(diào)用時(shí)如果不傳遞此參數(shù),會(huì)使用默認(rèn)值

In [12]: def inc(x, y=1):    # 參數(shù)y默認(rèn)為1
    ...:     x += y
    ...:     return x
    ...: 

In [13]: inc(3)    # 傳參時(shí)只需要傳入x即可
Out[13]: 4

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

In [15]: def inc(x=1, y):    # 默認(rèn)參數(shù)不能再非默認(rèn)參數(shù)之前
    ...:     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')

參數(shù)默認(rèn)值和關(guān)鍵字參數(shù)一起使用,會(huì)讓代碼非常簡潔

可變參數(shù)

可變參數(shù)兩種形式:

  • 位置可變參數(shù) : 參數(shù)名前加一個(gè)星號(hào), 構(gòu)成元組, 傳參只能以位置參數(shù)的形式
  • 關(guān)鍵字可變參數(shù): 參數(shù)名前加兩個(gè)信號(hào), 構(gòu)成字典, 傳參只能以關(guān)鍵字參數(shù)的形式

位置可變參數(shù)

In [18]: def sum(*lst):
    ...:     print(type(lst))
    ...:     ret = 0
    ...:     for x in lst:
    ...:         ret += x
    ...:     return ret
    ...: 
# 參數(shù)前加一個(gè)星號(hào), 表示這個(gè)參數(shù)是可變的, 也就是可以接受任意多個(gè)參數(shù), 這些參數(shù)將構(gòu)成一個(gè)元組, 此時(shí)只能通過位置參數(shù)傳參
In [19]: sum(1, 2, 3)
<class 'tuple'>
Out[19]: 6

關(guān)鍵字可變參數(shù)

In [20]: def connect(**kwargs):
    ...:     print(type(kwargs))
    ...:     for k, v in kwargs.items():
    ...:         print('{} => {}'.format(k, v))
    ...:         
# 參數(shù)前加兩個(gè)星號(hào), 表示這個(gè)參數(shù)是可變的,可以接受任意多個(gè)參數(shù), 這些參數(shù)構(gòu)成一個(gè)字典,此時(shí)只能通過關(guān)鍵字參數(shù)傳參
In [21]: connect(host='127.0.0.1',port=3306)
<class 'dict'>
host => 127.0.0.1
port => 3306

位置可變參數(shù)和關(guān)鍵字可變參數(shù)混合使用

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}
# 以上說明位置可變參數(shù)和關(guān)鍵字可變參數(shù)可以混合使用

In [24]: def fn(**kwargs, *args): 
  File "<ipython-input-24-e42478d184b2>", line 1
    def fn(**kwargs, *args):
                   ^
SyntaxError: invalid syntax
# 以上說明當(dāng)位置可變參數(shù)和關(guān)鍵字可變參數(shù)一起使用時(shí), 位置可變參數(shù)必須在前面

可變參數(shù)和普通參數(shù)混合使用

普通參數(shù)可以和可變參數(shù)一起使用,但是傳參的時(shí)候必須匹配,演示如下

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有兩個(gè)值,一個(gè)2,一個(gè)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
()
{}

位置可變參數(shù)可以在普通參數(shù)之前, 但是在位置可變參數(shù)之后的普通參數(shù)變成了keyword-only參數(shù):

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)    # 必須將位置可變參數(shù)之后的普通參數(shù)變成keyword-only,否則TypeError
(2, 3)
4

關(guān)鍵字可變參數(shù)不允許在普通參數(shù)之前,演示如下:

In [33]: def fn(**kwargs, x=5):
  File "<ipython-input-33-889f99c1c889>", line 1
    def fn(**kwargs, x=5):
                   ^
SyntaxError: invalid syntax

關(guān)于默認(rèn)參數(shù)和可變參數(shù)的總結(jié):

通常來說:

  • 默認(rèn)參數(shù)靠后
  • 可變參數(shù)靠后
  • 默認(rèn)參數(shù)和可變參數(shù)一般不同時(shí)出現(xiàn)
  • 當(dāng)默認(rèn)參數(shù)和可變參數(shù)一起出現(xiàn)的時(shí)候, 默認(rèn)參數(shù)相當(dāng)于普通參數(shù)

參數(shù)解構(gòu)

參數(shù)解構(gòu)有兩種形式

  • 一個(gè)星號(hào) 解構(gòu)的對象:可迭代對象 ,解構(gòu)的結(jié)果:位置參數(shù)
  • 兩個(gè)星號(hào) 解構(gòu)的對象:字典 ,解構(gòu)的結(jié)果:關(guān)鍵字參數(shù)

一個(gè)星號(hào)的情況

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])    # 如果列表中的元素很多的時(shí)候,一個(gè)一個(gè)解開很不方便簡潔
1 + 2 = 3
Out[38]: 3

In [39]: add(*t)    # 位置參數(shù)解構(gòu)  加一個(gè)星號(hào), 可以把可迭代對象解構(gòu)成位置參數(shù)
1 + 2 = 3
Out[39]: 3

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

二個(gè)星號(hào)

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

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

參數(shù)解構(gòu)發(fā)生在函數(shù)調(diào)用時(shí), 可變參數(shù)發(fā)生函數(shù)定義時(shí),所以兩者并不沖突

In [46]: def sum(*args):    # 可變參數(shù)發(fā)生在函數(shù)定義時(shí)
    ...:     ret = 0
    ...:     for x in args:
    ...:         ret += x
    ...:     return ret
    ...: 

In [47]: sum(*range(10))    # 參數(shù)解構(gòu)發(fā)生在函數(shù)調(diào)用時(shí)
Out[47]: 45

In [48]: def fn(**kwargs):
    ...:     print(kwargs)
    ...:     

In [49]: fn(**{'a-b':1})
{'a-b': 1}

In [50]: fn(**{123:1})    # 關(guān)鍵字參數(shù)解構(gòu), 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 參數(shù)

使用方法參見:Python: 函數(shù)參數(shù)列表中單個(gè)星號(hào)的意思,Keyword-Only Arguments

星號(hào)可以以一個(gè)參數(shù)的形式出現(xiàn)在函數(shù)聲明中的參數(shù)列表中,但星號(hào)之后的所有參數(shù)都必須有關(guān)鍵字(keyword),這樣在函數(shù)調(diào)用時(shí),星號(hào)*之后的所有參數(shù)都必須以keyword=value的形式調(diào)用,而不能以位置順序調(diào)用。

使用示例如下:也可參考上面鏈接中的示例

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

函數(shù)的返回值

  • return 語句除了返回值之外,還會(huì)結(jié)束函數(shù), return之后的語句將不會(huì)被執(zhí)行
  • 一個(gè)函數(shù)可以有多個(gè)return語句, 執(zhí)行到哪個(gè)return由哪個(gè)return返回結(jié)果并結(jié)束函數(shù)
  • 函數(shù)中 return可以提前結(jié)束循環(huán)
  • 當(dāng)函數(shù)沒有return語句的時(shí)候,返回None
  • 當(dāng)函數(shù)需要返回多個(gè)值時(shí), 可以用封裝把返回值封裝成一個(gè)元組
  • 可以通過解構(gòu)獲取到多返回值
  • return None 可以簡寫為 return, 通常用于結(jié)束函數(shù)
In [63]: def fn(x):
    ...:     for i in range(x):
    ...:         if i > 3:
    ...:             return i    # return可以提前退出循環(huán)
    ...:     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時(shí)返回的是None
    ...: 

In [67]: ret = fn()

In [68]: ret

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

In [70]: def fn():
    ...:     return 3, 5    # 當(dāng)函數(shù)需要返回多個(gè)值時(shí), 會(huì)把返回值封裝成一個(gè)元組
    ...: 

In [71]: ret = fn()

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

In [73]: x, y = fn()    # 可以通過解構(gòu)獲取多個(gè)返回值

函數(shù)的嵌套

函數(shù)可以嵌套使用

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

In [76]: outter()
outter
inner

作用域

變量的作用域?yàn)槎x此變量的作用域

In [6]: def fn(): # 變量的作用域?yàn)槎x此變量的作用域
   ...:         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函數(shù)之中

上級(jí)作用域?qū)ο录?jí)作用域只讀可見

不同作用域變量不可見, 但是下級(jí)作用域可以對上級(jí)作用域的變量只讀可見

In [9]: def fn():    # 上級(jí)作用域?qū)ο录?jí)作用域可見
   ...:     xx = 1
   ...:     print(xx)
   ...:     def inner():
   ...:         print(xx)
   ...:     inner()
   ...:     

In [10]: fn()
1
1

In [11]: def fn():    # 上級(jí)作用域?qū)ο录?jí)作用域只讀可見
    ...:     xx = 1
    ...:     print(xx)
    ...:     def inner():
    ...:         xx = 2
    ...:     inner()
    ...:     print(xx)
    ...:     

In [12]: fn()
1
1    # 可以發(fā)現(xiàn)xx并沒有被下級(jí)作用域修改

不要使用全局變量global

除非你清楚的知道global會(huì)帶來什么,并且明確的知道,非global不行, 否則不要使用global

In [13]: xx = 1

In [14]: def fn():
    ...:     global xx    # global 可以提升變量作用域?yàn)槿肿兞?    ...:     xx += 1
    ...:     

In [15]: fn()

In [16]: xx
Out[16]: 2

閉包函數(shù)

閉包定義(Wikipedia):在一些語言中,在函數(shù)中可以(嵌套)定義另一個(gè)函數(shù)時(shí),如果內(nèi)部的函數(shù)引用了外部的函數(shù)的變量,則可能產(chǎn)生閉包。閉包可以用來在一個(gè)函數(shù)與一組“私有”變量之間創(chuàng)建關(guān)聯(lián)關(guān)系。在給定函數(shù)被多次調(diào)用的過程中,這些私有變量能夠保持其持久性

通俗理解:當(dāng)某個(gè)函數(shù)被當(dāng)成對象返回時(shí),夾帶了外部變量,就形成了一個(gè)閉包。

如果我們想實(shí)現(xiàn)一個(gè)無限增長的計(jì)數(shù)器,可以寫一個(gè)counter函數(shù),函數(shù)內(nèi)部進(jìn)行自增就行。假定我們按照以下寫法:就會(huì)報(bào)錯(cuò)

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 的函數(shù)內(nèi),可以直接引用外部變量,但不能改寫外部變量,因此如果在閉包中直接改寫父函數(shù)的變量,就會(huì)發(fā)生錯(cuò)誤。比如上述程序直接改寫父函數(shù)中的變量c

python的閉包中如果想改寫父函數(shù)的變量可以用可變?nèi)萜鲗?shí)現(xiàn),這也是python2實(shí)現(xiàn)的唯一方式

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關(guān)鍵字

在python3中改寫父變量還有一種方就是使用nonlocal關(guān)鍵字

nonlocal 關(guān)鍵字用于標(biāo)記一個(gè)變量由他的上級(jí)作用域定義, 通過nonlocal標(biāo)記的變量, 可讀可寫

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

如果上級(jí)沒有定義nonlocal的變量,使用nonlocal時(shí)會(huì)拋出語法錯(cuò)誤

In [12]: def fn():
    ...:     nonlocal xxx
  File "<ipython-input-12-2d2b8104e945>", line 2
    nonlocal xxx
SyntaxError: no binding for nonlocal 'xxx' found

函數(shù)的__defaults__屬性

可變參數(shù)和不可變參數(shù)的__defaults__屬性不一樣

參數(shù)可變時(shí)

當(dāng)使用可變類型作為默認(rèn)值參數(shù)默認(rèn)值時(shí),需要特別注意,會(huì)改變函數(shù)的__default__屬性

In [1]: def fn(xxyy=[]):
   ...:     xxyy.append(1)
   ...:     print(xxyy)
   ...:     

In [2]: fn()
[1]

In [3]: fn()
[1, 1]

In [4]: fn.__defaults__        # 參數(shù)是函數(shù)對象的屬性
Out[4]: ([1, 1],)

In [5]: fn()
[1, 1, 1]

In [6]: fn.__defaults__     # 所有的函數(shù)參數(shù)封裝成一個(gè)元組,第一個(gè)函數(shù)參數(shù)時(shí)列表在動(dòng)態(tài)變化
Out[6]: ([1, 1, 1],)

參數(shù)不可變時(shí)

使用不可變類型作為默認(rèn)值,函數(shù)體內(nèi)不改變默認(rèn)值

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)

可變參數(shù)時(shí)None的使用

通常如果使用一個(gè)可變類型作為默認(rèn)參數(shù)時(shí), 會(huì)使用None來代替

In [1]: def fn(lst=None):    # 向一個(gè)列表中插入元素3,列表默認(rèn)為None
   ...:     if lst is None:
   ...:         lst = []
   ...:     lst.append(3)
   ...:     print(lst)
   ...:     

In [2]: fn.__defaults__        # 函數(shù)的__defaults__屬性就是可變參數(shù)對應(yīng)的None
Out[2]: (None,)

In [3]: fn()
[3]

In [4]: fn()                # 如果不傳入值,函數(shù)執(zhí)行的時(shí)候會(huì)先創(chuàng)建一個(gè)空列表,然后append
[3]

In [5]: fn.__defaults__
Out[5]: (None,)

In [6]: fn([1,2])
[1, 2, 3]

In [7]: fn.__defaults__        # 傳入值之后,也不會(huì)改變函數(shù)的__default__屬性
Out[7]: (None,)

Python作用域、閉包、裝飾器資料

函數(shù)執(zhí)行流程

函數(shù)的執(zhí)行過程就是壓棧和出棧的過程。具體如下

當(dāng)調(diào)用函數(shù)的時(shí)候, 解釋器會(huì)把當(dāng)前現(xiàn)場壓棧,然后開始執(zhí)行被調(diào)函數(shù), 被調(diào)函數(shù)執(zhí)行完成,解釋器彈出當(dāng)前棧頂,恢復(fù)現(xiàn)場

遞歸函數(shù)

遞歸函數(shù)的定義就是函數(shù)調(diào)用函數(shù)自身。

  • 遞歸函數(shù)必須要有退出條件
  • 為了保護(hù)解釋器, Python對最大遞歸深度有限制
  • 絕大多數(shù)遞歸都可以轉(zhuǎn)化為循環(huán)使用
  • 盡量避免使用遞歸
  • sys模塊中的getrecursionlimit和setrecursionlimit可以獲取和設(shè)置最大遞歸深度

匿名函數(shù)

In [1]: lambda x: x + 1
Out[1]: <function __main__.<lambda>>

匿名函數(shù)有以下特點(diǎn)

  • lambda來定義
  • 參數(shù)列表不需要用小括號(hào)
  • 冒號(hào)不是用來開啟新語句塊
  • 沒有return,最后一個(gè)表達(dá)式的值即返回值
  • 匿名函數(shù)(lambda表達(dá)式)只能寫在一行上,所以也叫單行函數(shù)

匿名函數(shù)的好處是

  • 函數(shù)沒有名字,不必?fù)?dān)心函數(shù)名沖突
  • 匿名函數(shù)也是一個(gè)函數(shù)對象,可以把匿名函數(shù)返回給一個(gè)變量,再利用變量調(diào)用函數(shù)
In [1]: lambda x: x + 1
Out[1]: <function __main__.<lambda>>

In [2]: f = lambda x: x + 1        # 直接把lambda函數(shù)返回給變量f

In [3]: f(3)                    # 由變量f調(diào)用函數(shù)
Out[3]: 4

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

In [5]: (lambda x: x * 2)(3)    # 第一對括號(hào)用來改變優(yōu)先級(jí) 第二對括號(hào)表示函數(shù)調(diào)用
Out[5]: 6

In [6]: (lambda : 1)()            # lambda表示式參數(shù)可以為空
Out[6]: 1

In [7]: (lambda x, y: x + y)(3, 5)    # lambda表達(dá)式的位置參數(shù)
Out[7]: 8

In [8]: (lambda *args: args)(*range(3))    # lambda表達(dá)式的位置可變參數(shù)
Out[8]: (0, 1, 2)

In [9]: (lambda *args, **kwargs: print(args, kwargs))(*range(3), **{str(x):x for x in range(3)})    # lambda表達(dá)式的位置可變參數(shù)和關(guān)鍵字可變參數(shù)
(0, 1, 2) {'0': 0, '1': 1, '2': 2}

In [10]: (lambda *, x: x)(x=3)    # *號(hào)后面的位置參數(shù)必須使用關(guān)鍵字參數(shù)
Out[10]: 3

普通函數(shù)所支持的參數(shù)的變化,匿名函數(shù)都支持

匿名函數(shù)的常見用法:通常用于高階函數(shù)的參數(shù), 當(dāng)此函數(shù)非常短小的時(shí)候,就適合使用匿名函數(shù)

比如匿名函數(shù)可以作為sorted函數(shù)的自定義鍵函數(shù)(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)    # 簡短的函數(shù)可以作為自定義鍵函數(shù)
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表示也可以作為自定義鍵函數(shù)
Out[17]: [point(x=1, y=2), point(x=4, y=3), point(x=8, y=9)]

高階函數(shù)

高階函數(shù)的定義

高階函數(shù)英文叫Higher-order function。

在數(shù)學(xué)和計(jì)算機(jī)科學(xué)中,高階函數(shù)是至少滿足下列一個(gè)條件的函數(shù):

  • 接受一個(gè)或多個(gè)函數(shù)作為輸入:通常用于大多數(shù)邏輯固定,少部分邏輯不固定的場景
  • 輸出一個(gè)函數(shù):函數(shù)作為返回值: 通常是用于閉包的場景, 需要封裝一些變量

常見的高階函數(shù)有map,reduce,filter

高階函數(shù):插入排序

插入排序時(shí),排序順序分為升序和降序,我們可以使用一個(gè)函數(shù)作為插入排序函數(shù)的參數(shù)來控制是升序還是降序。

首先看一下按照升序插入排序,然后再改進(jìn)成升序降序可控的插入排序

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

如果想讓這個(gè)函數(shù)降序排序,則只需要修改代碼中的注釋處,改成x > y即可

如果傳入一個(gè)函數(shù)來控制if后面的bool值,則就實(shí)現(xiàn)了通過參數(shù)控制升降了

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

這個(gè)函數(shù)就默認(rèn)為升序排序了,但是可以傳入一個(gè)比較函數(shù)變成降序,如下

lst = insertSort([1, 3, 2, 4, 6, 8, 5],lambda x, y: x > y)

map

map()函數(shù)原型:map(func, *iterables) --> map object

map()函數(shù)接收兩個(gè)參數(shù),一個(gè)是函數(shù)func,一個(gè)是可迭代對象Iterablemap將傳入的函數(shù)依次作用到可迭代對象的每個(gè)元素,并把結(jié)果放入map對象這個(gè)迭代器中。所以map函數(shù)是高階函數(shù)。

map類中存在__iter____next__函數(shù)

map使用示例

把list中的所有數(shù)字的平方

In [1]: def f(x):                                # 定義平方函數(shù)f
   ...:         return x ** 2
   ...: 

In [2]: ret = map(f, [1, 2, 3, 4, 5, 6, 7])        # 函數(shù)f和列表作為map的參數(shù)

In [3]: ret                                        # map的返回值只是一個(gè)返回值
Out[3]: <map at 0x7f2d539a7470>

In [4]: next(ret)                                # 可以用next方法輸出map的結(jié)果
Out[4]: 1

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

In [6]: lst = list(ret)                            # 也可以用list函數(shù)計(jì)算出所有的值

In [7]: lst
Out[7]: [9, 16, 25, 36, 49]

reduce

map函數(shù)是map類的函數(shù),但是reduce函數(shù)屬于functools包的reduce模塊中

from functools import reduce

然后可以使用help方法查看reduce函數(shù)的使用

help(reduce)

輸出結(jié)果如下

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)))

輸出結(jié)果為55

  • 把字符串轉(zhuǎn)化為int,不適用int()函數(shù)
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)之后可以發(fā)現(xiàn)filter是一個(gè)類,其中有一個(gè)filter函數(shù),原型如下

filter(function or None, iterable) --> filter object

map()類似,filter()也接收一個(gè)函數(shù)和一個(gè)序列。和map()不同的是,filter()把傳入的函數(shù)依次作用于每個(gè)元素,然后根據(jù)返回值是True還是False決定保留還是丟棄該元素。返回值也是一個(gè)迭代器。

filter使用示例

使用filter篩選出list中的回文數(shù)

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)
# 結(jié)果: [12321, 13431]

所以filter()函數(shù)用于過濾序列,重點(diǎn)在于選擇一個(gè)正確的篩選函數(shù)。

生成器

帶yield語句的函數(shù)稱之為生成器函數(shù), 生成器函數(shù)的返回值是生成器

  • 生成器函數(shù)執(zhí)行的時(shí)候,不會(huì)執(zhí)行函數(shù)體
  • 當(dāng)next生成器的時(shí)候, 當(dāng)前代碼執(zhí)行到之后的第一個(gè)yield,會(huì)彈出值,并且暫停函數(shù)
  • 當(dāng)再次next生成器的時(shí)候,從上次暫停處開始往下執(zhí)行
  • 當(dāng)沒有多余的yield的時(shí)候,會(huì)拋出StopIteration異常,異常的value是函數(shù)的返回值

生成器的基本形式

In [1]: def g():
    ...:     for x in range(5):
    ...:         yield x    # 彈出x
    ...:         

In [2]: r = g()        # 函數(shù)調(diào)用完成之后函數(shù)現(xiàn)場并沒有被銷毀

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

生成器的執(zhí)行順序

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

In [2]: r = g()    # 執(zhí)行生成器函數(shù)的時(shí)候函數(shù)并沒有被執(zhí)行 

In [3]: next(r)    # 執(zhí)行到第一個(gè)yield就停止執(zhí)行
a
Out[3]: 1

In [4]: next(r)    # 執(zhí)行到第二個(gè)yield就停止執(zhí)行
b
Out[4]: 2

In [5]: next(r)    # 從第二個(gè)yield開始,當(dāng)沒有更多yield的時(shí)候,拋出StopIteration異常,異常的值正好是return的返回值
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-5-0b5056469c9c> in <module>()
----> 1 next(r)

StopIteration: 3

生成器的應(yīng)用

計(jì)數(shù)器第一種形式

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函數(shù)執(zhí)行的結(jié)果就是一個(gè)生成器,所以c就是生成器

In [4]: inc(c)
Out[4]: 1

In [5]: inc(c)
Out[5]: 2

計(jì)數(shù)器第二種形式

In [6]: def make_inc():
   ...:     def counter():
   ...:         x = 0
   ...:         while True:
   ...:             x += 1
   ...:             yield x
   ...:     c = counter()
   ...:     return lambda : next(c)    # 使用lambda表達(dá)式將next(c)作為函數(shù)返回,而不是只返回一個(gè)next(c)
   ...: 

In [7]: make_inc()
Out[7]: <function __main__.make_inc.<locals>.<lambda>>    # make_inc本質(zhì)是一個(gè)匿名函數(shù)

In [8]: inc = make_inc()

In [9]: inc()
Out[9]: 1

In [10]: inc()
Out[10]: 2

斐波拉契數(shù)列

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列表的最后一個(gè)元素值,速度很快
Out[22]: 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請遵守用戶 評(píng)論公約

    類似文章 更多