欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python中高階函數(shù)的小實(shí)踐分享

 更新時(shí)間:2023年05月18日 14:10:53   作者:Xu_Mingyong  
這篇文章主要為大家介紹了一些Python中高階函數(shù)的小實(shí)踐,文中的示例代碼講解詳細(xì),對(duì)我們深入學(xué)習(xí)Python有一定的幫助,需要的可以參考下

1. filter

1.1 把一個(gè)序列中的空字符串刪掉

例如將[‘A’, ‘’, ‘B’, None, ‘C’, ’ ']返回為[‘A’, ‘B’, ‘C’]

def not_empty(s):
    return s and s.strip()
list(filter(not_empty, ['A', '', 'B', None, 'C', '  ']))

可見用filter()這個(gè)高階函數(shù),關(guān)鍵在于正確實(shí)現(xiàn)一個(gè)“篩選”函數(shù)。

注意到filter()函數(shù)返回的是一個(gè)Iterator,也就是一個(gè)惰性序列,所以要強(qiáng)迫filter()完成計(jì)算結(jié)果,需要用list()函數(shù)獲得所有結(jié)果并返回list。

1.2 用filter求素?cái)?shù)

計(jì)算素?cái)?shù)的一個(gè)方法是埃氏篩法,它的算法理解起來非常簡單:

首先,列出從2開始的所有自然數(shù),構(gòu)造一個(gè)序列:

2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …

取序列的第一個(gè)數(shù)2,它一定是素?cái)?shù),然后用2把序列的2的倍數(shù)篩掉:

3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …

取新序列的第一個(gè)數(shù)3,它一定是素?cái)?shù),然后用3把序列的3的倍數(shù)篩掉:

5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …

取新序列的第一個(gè)數(shù)5,然后用5把序列的5的倍數(shù)篩掉:

7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, …

不斷篩下去,就可以得到所有的素?cái)?shù)。

用Python來實(shí)現(xiàn)這個(gè)算法,可以先構(gòu)造一個(gè)從3開始的奇數(shù)序列:

def _odd_iter():
    n = 1
    while True:
        n = n + 2
        yield n

注意這是一個(gè)生成器,并且是一個(gè)無限序列。

然后定義一個(gè)篩選函數(shù):

def _not_divisible(n):
    return lambda x: x % n > 0

最后,定義一個(gè)生成器,不斷返回下一個(gè)素?cái)?shù):

def primes():
    yield 2
    it = _odd_iter() # 初始序列
    while True:
        n = next(it) # 返回序列的第一個(gè)數(shù)
        yield n
        it = filter(_not_divisible(n), it) # 構(gòu)造新序列

這個(gè)生成器先返回第一個(gè)素?cái)?shù)2,然后,利用filter()不斷產(chǎn)生篩選后的新的序列。

由于primes()也是一個(gè)無限序列,所以調(diào)用時(shí)需要設(shè)置一個(gè)退出循環(huán)的條件:

# 打印1000以內(nèi)的素?cái)?shù):
for n in primes():
    if n < 1000:
        print(n)
    else:
        break

注意到Iterator是惰性計(jì)算的序列,所以我們可以用Python表示“全體自然數(shù)”,“全體素?cái)?shù)”這樣的序列,而代碼非常簡潔。

2. map(), reduce()

Python內(nèi)建了map()和reduce()函數(shù)。

如果你讀過Google的那篇大名鼎鼎的論文“MapReduce: Simplified Data Processing on Large Clusters”,你就能大概明白map/reduce的概念。

我們先看map。map()函數(shù)接收兩個(gè)參數(shù),一個(gè)是函數(shù),一個(gè)是Iterable,map將傳入的函數(shù)依次作用到序列的每個(gè)元素,并把結(jié)果作為新的Iterator返回。

舉例說明,比如我們有一個(gè)函數(shù)f(x)=x2,要把這個(gè)函數(shù)作用在一個(gè)list [1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map()實(shí)現(xiàn)如下:

            f(x) = x * x

                  │
                  │
  ┌───┬───┬───┬───┼───┬───┬───┬───┐
  │   │   │   │   │   │   │   │   │
  ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼

[ 1   2   3   4   5   6   7   8   9 ]

  │   │   │   │   │   │   │   │   │
  │   │   │   │   │   │   │   │   │
  ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼   ▼

[ 1   4   9  16  25  36  49  64  81 ]

現(xiàn)在,我們用Python代碼實(shí)現(xiàn):

def f(x):
    return x * x
r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(r))

map()傳入的第一個(gè)參數(shù)是f,即函數(shù)對(duì)象本身。由于結(jié)果r是一個(gè)Iterator,Iterator是惰性序列,因此通過list()函數(shù)讓它把整個(gè)序列都計(jì)算出來并返回一個(gè)list。

你可能會(huì)想,不需要map()函數(shù),寫一個(gè)循環(huán),也可以計(jì)算出結(jié)果:

L = []
for n in [1, 2, 3, 4, 5, 6, 7, 8, 9]:
    L.append(f(n))
print(L)

的確可以,但是,從上面的循環(huán)代碼,能一眼看明白“把f(x)作用在list的每一個(gè)元素并把結(jié)果生成一個(gè)新的list”嗎?

所以,map()作為高階函數(shù),事實(shí)上它把運(yùn)算規(guī)則抽象了,因此,我們不但可以計(jì)算簡單的f(x)=x2,還可以計(jì)算任意復(fù)雜的函數(shù),比如,把這個(gè)list所有數(shù)字轉(zhuǎn)為字符串:

list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
# ['1', '2', '3', '4', '5', '6', '7', '8', '9']

只需要一行代碼。

再看reduce的用法。reduce把一個(gè)函數(shù)作用在一個(gè)序列[x1, x2, x3, ...]上,這個(gè)函數(shù)必須接收兩個(gè)參數(shù),reduce把結(jié)果繼續(xù)和序列的下一個(gè)元素做累積計(jì)算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

比方說對(duì)一個(gè)序列求和,就可以用reduce實(shí)現(xiàn):

from functools import reduce
def add(x, y):
    return x + y
reduce(add, [1, 3, 5, 7, 9])

當(dāng)然求和運(yùn)算可以直接用Python內(nèi)建函數(shù)sum(),沒必要?jiǎng)佑胷educe。

但是如果要把序列[1, 3, 5, 7, 9]變換成整數(shù)13579,reduce就可以派上用場:

from functools import reduce
def fn(x, y):
    return x * 10 + y
reduce(fn, [1, 3, 5, 7, 9])

這個(gè)例子本身沒多大用處,但是,如果考慮到字符串str也是一個(gè)序列,對(duì)上面的例子稍加改動(dòng),配合map(),我們就可以寫出把str轉(zhuǎn)換為int的函數(shù):

from functools import reduce
def fn(x, y):
 return x * 10 + y
def char2num(s):
  digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
    return digits[s]
reduce(fn, map(char2num, '13579'))

整理成一個(gè)str2int的函數(shù)就是:

from functools import reduce
DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
def str2int(s):
    def fn(x, y):
        return x * 10 + y
    def char2num(s):
        return DIGITS[s]
    return reduce(fn, map(char2num, s))
print(str2int('12306'))

還可以用lambda函數(shù)進(jìn)一步簡化成:

from functools import reduce
DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
def char2num(s):
    return DIGITS[s]
def str2int(s):
    return reduce(lambda x, y: x * 10 + y, map(char2num, s))

也就是說,假設(shè)Python沒有提供int()函數(shù),你完全可以自己寫一個(gè)把字符串轉(zhuǎn)化為整數(shù)的函數(shù),而且只需要幾行代碼!

lambda函數(shù)的用法在后面介紹。

3. sorted()

排序也是在程序中經(jīng)常用到的算法。無論使用冒泡排序還是快速排序,排序的核心是比較兩個(gè)元素的大小。如果是數(shù)字,我們可以直接比較,但如果是字符串或者兩個(gè)dict呢?直接比較數(shù)學(xué)上的大小是沒有意義的,因此,比較的過程必須通過函數(shù)抽象出來。

Python內(nèi)置的sorted()函數(shù)就可以對(duì)list進(jìn)行排序:

sorted([36, 5, -12, 9, -21])

此外,sorted()函數(shù)也是一個(gè)高階函數(shù),它還可以接收一個(gè)key函數(shù)來實(shí)現(xiàn)自定義的排序,例如按絕對(duì)值大小排序:

sorted([36, 5, -12, 9, -21], key=abs)

key指定的函數(shù)將作用于list的每一個(gè)元素上,并根據(jù)key函數(shù)返回的結(jié)果進(jìn)行排序。對(duì)比原始的list和經(jīng)過key=abs處理過的list:

list = [36, 5, -12, 9, -21]
keys = [36, 5,  12, 9,  21]

然后sorted()函數(shù)按照keys進(jìn)行排序,并按照對(duì)應(yīng)關(guān)系返回list相應(yīng)的元素:

keys排序結(jié)果 => [5, 9,  12,  21, 36]
最終結(jié)果     => [5, 9, -12, -21, 36]

我們再看一個(gè)字符串排序的例子:

>>> sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']

默認(rèn)情況下,對(duì)字符串排序,是按照ASCII的大小比較的,由于'Z' < 'a',結(jié)果,大寫字母Z會(huì)排在小寫字母a的前面。

現(xiàn)在,我們提出排序應(yīng)該忽略大小寫,按照字母序排序。要實(shí)現(xiàn)這個(gè)算法,不必對(duì)現(xiàn)有代碼大加改動(dòng),只要我們能用一個(gè)key函數(shù)把字符串映射為忽略大小寫排序即可。忽略大小寫來比較兩個(gè)字符串,實(shí)際上就是先把字符串都變成大寫(或者都變成小寫),再比較。

這樣,我們給sorted傳入key函數(shù),即可實(shí)現(xiàn)忽略大小寫的排序:

sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']

要進(jìn)行反向排序,不必改動(dòng)key函數(shù),可以傳入第三個(gè)參數(shù)reverse=True:

>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']

從上述例子可以看出,高階函數(shù)的抽象能力是非常強(qiáng)大的,而且,核心代碼可以保持得非常簡潔。

小結(jié)

sorted()也是一個(gè)高階函數(shù)。用sorted()排序的關(guān)鍵在于實(shí)現(xiàn)一個(gè)映射函數(shù)。

以上就是Python中高階函數(shù)的小實(shí)踐分享的詳細(xì)內(nèi)容,更多關(guān)于Python高階函數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論