函式進階· 第3篇《常用內建函式filter()、map()、zip(),怎麼用的呢?》

清菡發表於2020-12-25

堅持原創輸出,點選藍字關注我吧

作者:清菡
部落格:oschina、雲+社群、知乎等各大平臺都有。

由於微信公眾號推送改為了資訊流的形式,防止走丟,請給加個星標 ⭐,你就可以第一時間接收到本公眾號的推送!

目錄

  • 一、filter()函式
    • 1.filter()過濾序列
    • 2.生成器、迭代器都是可迭代物件
  • 二、map()函式
  • 三、zip()函式
    • 1.什麼是 zip()函式
    • 2.zip()可以快速建立字典

常用的內建函式:

  • map()函式:會根據提供的函式對指定序列做對映。
  • filter()函式:函式用於過濾序列。
  • zip()函式:函式用於將可迭代的物件作為引數,將物件中對應的元素打包成一個個元組。

一、filter()函式

1.filter()過濾序列

filter:過濾序列。第一引數是函式;第二引數是可迭代物件。

看看filter()這個內建函式的原始碼:

class filter(object):
    """
    filter(function or None, iterable) --> filter object

    Return an iterator yielding those items of iterable for which function(item)
    is true. If function is None, return the items that are true.
    """
    def __getattribute__(self, *args, **kwargs): # real signature unknown
        """ Return getattr(self, name). """
        pass

    def __init__(self, function_or_None, iterable): # real signature unknown; restored from __doc__
        pass

    def __iter__(self, *args, **kwargs): # real signature unknown
        """ Implement iter(self). """
        pass

    @staticmethod # known case of __new__
    def __new__(*args, **kwargs): # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __next__(self, *args, **kwargs): # real signature unknown
        """ Implement next(self). """
        pass

    def __reduce__(self, *args, **kwargs): # real signature unknown
        """ Return state information for pickling. """
        pass

看原始碼發現居然是個類。

它接收到的是2個引數,2個引數在哪裡看呢?

__init__方法裡面看。既然是個類,呼叫的時候建立一個物件。

Python 中的可迭代物件在一個模組裡面。迭代器、生成器、可迭代物件都在這個模組裡面。

from collections import Iterator,Iterable,Generator

生成器屬於迭代器,生成器是可迭代物件。

列表是個可迭代物件。filter()這個內建函式傳 2 個引數後,會返回出一個物件。

filter()原始碼可以看出它是個類,呼叫它給它傳參,類返回的結果肯定是個物件。

filter()的作用是過濾,它會進行迭代操作。

它會把後面傳入的可迭代物件,裡面的元素全部遍歷一遍。然後把遍歷出來的元素當作引數傳到這個fun函式裡面。

當前這個fun()函式沒有定義引數,這個時候執行看看:

# 內建函式
def fun():
    pass

li = [1,2,122,331,11,22,33,4,6,7,2,88,31]

res=filter(fun,li)
print(list(res))

返回列表的時候報錯了,fun()需要 0 個引數,但是這裡給了一個引數:

當我們把它轉換成列表的時候,在這裡傳進去,它會返回一個物件,這個物件裡有一個函式,還有個可迭代物件filter(fun,li)

使用filter()傳出來的資料也是個迭代器。它也是個可迭代物件,就可以通過list把它轉換成列表。

當你轉換的時候,它會把第一個引數拿到,傳到fun()裡面去,會自動傳參的。

加個引數,再執行:

# 內建函式
def fun(n):
    pass

li = [1,2,122,331,11,22,33,4,6,7,2,88,31]

res=filter(fun,li)
print(list(res))

執行結果:

這個列表是空的。因為函式pass掉了。只寫個pass,呼叫這個函式,返回的值是沒有結果的。

filter()會根據傳進去的引數,呼叫func()函式,這個函式根據返回值pass,來確定函式li要不要新增到新的列表裡面。

如果將程式碼修改成這樣return True

def fun(n):
    return True

li = [1,2,122,331,11,22,33,4,6,7,2,88,31]

res=filter(fun,li)
print(list(res))

返回結果:

返回一個 False:

輸出結果是一個都沒有了。

filter()函式可以過濾,可以寫過濾條件。比如要保留n<10的資料要保留下來,n<10是個比較語句。

n<10返回的是個 True(當前傳入的引數保留,新增到新的列表裡面),n>10返回的是個 False(就把資料去掉不要了):

def fun(n):
    return n<10

li = [1,2,122,331,11,22,33,4,6,7,2,88,31]

res=filter(fun,li)
print(list(res))

其實和這段程式碼的操作是一樣一樣的:

li1 = []
for i in li:
    if i > 10:
        li1.append(i)

內部操作是這樣的:

定義了個新的列表li1,在這裡面來了一個for迴圈,判斷i是不是大於 10,如果大於 10,就把它新增到新的列表裡面。

會根據你傳入的引數fun(n)進行相應的判斷和比較。根據函式返回的是True還是None,來決定這個資料要不要保留起來。

2.生成器、迭代器都是可迭代物件

定義個生成器、可迭代物件、迭代器:

from collections import Iterator,Iterable,Generator
def fun(n):
    return n < 10

# 列表就是可迭代物件
li = [1, 2, 122, 331, 11, 22, 33, 4, 6, 7, 2, 88, 31]
res = filter(fun, li)

# 定義個迭代器
# 可以把一個可迭代物件轉換成一個迭代器
li2 = iter(li)

# 定義個生成器
li3 = (i for i in range(5))

# 用isinstance 判斷下列表是不是個可迭代物件
print(isinstance(li,Iterable))
print(isinstance(li2,Iterable))
print(isinstance(li3,Iterable))

isinstance() 函式來判斷一個物件是否是一個已知的型別,類似 type()

返回都是True,所以它們 3 個都是可迭代物件。

生成器屬於迭代器,那麼生成器也是可迭代物件。迭代器是可迭代物件,但是迭代器不是生成器。

二、map()函式

map()的機制和filter()是一樣的。它也會將後面的可迭代物件裡面的資料迭代出來,放到第一個函式裡面。

它接收的也是 2 個引數。第一個引數:func ,第二個引數:可迭代物件。

def fun(n):
    return n < 10

# 列表就是可迭代物件
li = [1, 2, 122, 331, 11, 22, 33, 4, 6, 7, 2, 88, 31]
res = filter(fun, li)

# map:將可迭代物件中的資料迭代出來,一個一個傳到函式中去呼叫,將返回結果放到新的物件中。
res2=map(fun,li)
print(list(res2))

它返回的結果全是TrueFalse

map()函式可以用來做:

1.把這些資料做統一的處理,比如算這些資料的階乘,有一批資料要算階乘,可以一起拿過去。

2.它會把資料當作個引數,放到函式裡去呼叫。

3.然後把函式的返回值放到一個列表裡面。

它返回什麼就放什麼,改成返回 1000:

改成n*2:

map()將可迭代物件裡面的元素迭代出來,每個元素當作一個引數,傳到前面這個函式fun裡面,然後把函式的返回值新增到新的列表裡面。

要統一處理一批資料的時候,就可以通過它來做。

三、zip()函式

1.什麼是 zip()函式

zip()函式後面接收的是個可迭代物件,後面可接收多個可迭代物件。

來看看 zip 的原始碼:

它的內部其實也是個類,那麼它返回的就是個可迭代物件。

準確得來說,它是個迭代器,迭代器也屬於可迭代物件。

例如:

# zip # 打包
res3 = zip([1, 2, 3], [11, 22, 33])
print(res3)

在 Python2 的時候,filter()map()zip()函式返回出來的直接是列表。Python3 做了個效能的優化,返回的是個迭代器,可以節約記憶體。

通過next()去取值,能獲取出來內容的話,說明它就是個迭代器:

直接一次性把它轉換成列表,方便看結果:

# zip # 打包
res3 = zip([1, 2, 3], [11, 22, 33])
print(list(res3))

它是這樣打包的:

使用zip()函式傳入 2 個可迭代物件,把第一個可迭代物件的第一個元素和第二個可迭代物件的第一個元素拿出來打包成一個元組,後面以此類推。

為什麼裡面放的是元組?

元組省記憶體啊。

如果可迭代物件裡面元素多少不一樣(長短不一)怎麼辦?

# zip # 打包
res3 = zip([1, 2, 3], [11, 22, 33,44,55],[111,222,333],[111,222,333])
print(list(res3))

它會只會保留最短的。

程式碼中最短的一組:這裡只有 3 個元素。

那麼這裡的話,只會分成 3 組。就算第二組有 5 個元素,只會拿第一個、第二個、第三個。多餘的資料清除掉了,不要了。

2.zip()可以快速建立字典

你看,和字典items()取值出來的資料是一樣的:

通過dict轉換下,你看,它變成了一個字典:

# zip # 打包
res3 = zip([1, 2, 3], [11, 22, 33])
print(dict(list(res3)))

dict1={"key1":1,"key2":2,"key3":3}
print(list(dict1.items()))

建立字典的時候,可通過這種方式快速建立字典。

把鍵放在一個列表裡,把值放在一個列表裡,通過zip()打包一下,通過dit()就能把它轉換成一個字典。


公眾號清菡軟體測試首發,更多原創文章:清菡軟體測試 112+原創文章,歡迎關注、交流,禁止第三方擅自轉載。

相關文章