第十二章:函數 - 函數三

01.- 函數 - 匿名函數

1.filter(fnuction,iterable) --> filter(函數,可迭代的) -->filter(函數,序列)

可以從序列當中過濾出符合條件的元素,保存到一個新的序列當中
參數一 : 傳遞函數 參數二 : 需要過濾的序列
返回值 過濾後新的序列

# 定義一個函數 可以將指定列表當中的所有偶數,保存到一個新的列表中返回
l = [1,2,3,4,5,6,7,8,9,10]

# 定義一個函數,用來檢測一個任意的偶數
def fn2(i):
    if i % 2 == 0:
        return True

# 定義一個函數,用來檢測指定數字是否大於5
def fn3(i):
    if i > 5:
        return True
    return False

# 創建一個新的列表
new_list = []

# 定義一個函數
def fn4(i):

    if i % 3 == 0:
        return True
    return False

def fn(func,lst):    # 傳一個變量 n

    for n in lst:

        # 判斷 n 的奇偶
        # if not fn2(n):       # [2, 4, 6, 8, 10]
        # if fn3(n):           # [6, 7, 8, 9, 10]
        if func(n):            # [2, 4, 6, 8, 10]
            new_list.append(n)

    # 返回新的列表
    return new_list

print(fn(fn4,l))   #  [3, 6, 9]
# 當我們使用一個函數作爲參數時,實際上是將指定的代碼傳遞進了目標函數

print(filter(fn4,l))  # <filter object at 0x000002570D6966D8>
print(list(filter(fn4,l)))   # [3, 6, 9]

2.lambda表達式

lambda函數表達式專門用來創建一些簡單的函數,它是函數創建的另一種方式

語法 lambda 參數列表[a,b,c…] : 返回值

((lambda a,b : a+b)(10,20) 一般不這麼寫

print(fn5(123,456))      # 579
print(lambda a,b : a+b)  # <function <lambda> at 0x00000130CEA1B2F0>     打印結果比一般的打印結果少個名稱,所以才叫做匿名函數
print((lambda a,b : a+b)(10,20)) # 30  一般不這麼寫

def fn5(a,b):
    return a + b
fn6 = lambda a,b: a+b
print(fn6(30,20))    # 50      一般這麼寫

3.lambda函數表達式的應用

l = [1,2,3,4,5,6,7,8,9,10]

# def fn(i):
#     return i % 3 == 0
# lambda i : i % 3 == 0

r = filter(lambda i : i > 5,l)
print(list(r))
>>>[6,7,8,9,10]

4. map()

map()函數可以對可迭代對象中所有的元素做指定操作,然後將其添加到一個新的對象返回

 = [1,2,3,4,5,6,7,8,9,10]

r = map(lambda i : i + 1,l)   #  匿名函數一般都是作爲參數使用,其他地方一般不用
print(list(r))                # [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

5. sort()函數

該方法用來對列表當中的元素進行排序
sort()方法是直接默認比較列表中元素的大小


l = ['bb','aaaa','c','fff','dddddddd']
l.sort()   # sort()直接默認:比較列表中元素的大小
print(l)   # ['aaaa', 'bb', 'c', 'dddddddd', 'fff']

6.在sort()函數中可以接收一個關鍵字參數 key

key需要一個函數作爲參數

l = ['bb','aaaa','c','fff','dddddddd']
l.sort(key=len)   # 對列表中的字符串長度進行一個排序
print(l)          # ['c', 'bb', 'fff', 'aaaa', 'dddddddd']

7.如果要將數字和字符串比較大小,就要用到l.sort(key=int)

l = [2,3,'1',3,'5',4]
l.sort(key=int)
print(l)  # ['1', 2, 3, 3, 4, '5']

8. sorted()

sorted() 它有返回值, 會返回一個新的列表

l = [2,3,'1',3,'5',4]

print('排序前:',l)

sorted(l,key=int)

print('排序後:',l)
>>>
排序前: [2, 3, '1', 3, '5', 4]
排序後: [2, 3, '1', 3, '5', 4]

對sorted()進行打印之後會出現一個結果,這個表示sorted()函數有返回值,打印之後會返回一個新的排好順序的列表

l = [2,3,'1',3,'5',4]

print('排序前:',l)

print(sorted(l,key=int))    # 對sorted()進行打印之後會出現一個結果,這個表示sorted()函數有返回值,打印之後會返回一個新的排好順序的列表

print('排序後:',l)
>>>
排序前: [2, 3, '1', 3, '5', 4]
['1', 2, 3, 3, 4, '5']
排序後: [2, 3, '1', 3, '5', 4]

02. - 函數 - 閉包

1.閉包含義:將函數作爲返回值返回也是一種高階函數,俗稱閉包

def  fn():

    # 在函數內部再定義一個函數
    def inner():
        print('我是fn2')

    # 將函數內部 inner()作爲返回值
    return inner

print(fn)     # <function fn at 0x00000155A7683EA0>
print(fn())   #  <function fn.<locals>.inner at 0x000001A045CE3E18>


def  fn():
    a = 10
    # 在函數內部再定義一個函數
    def inner():
        print('我是fn2',a)

    # 將函數內部 inner()作爲返回值
    return inner

# r是一個函數,是調用fn()後返回的函數
# 這個函數fn()內部定義的,並不是全局函數
# 所以這個函數總是能訪問到fn()函數內部的變量
r = fn()
r()               # 我是fn2 10

所以這個函數總是能訪問fn()函數的內部變量

print(a)   # NameError: name 'a' is not defined (名稱錯誤:未定義名稱“a”),在這個函數
裏面找不到一個定義名稱爲 a的變量,是因爲 變量a 處在一個函數的環境是閉包的一個函數中.

2. 創建閉包的好處是什麼?

通過閉包可以創建一些只有當前函數可以訪問到的變量(可以將一些私有的數據藏到閉包當中)

(1).求多個數的平均值(常規操作)

nums = [50,20,30,10,77]
print(sum(nums)/len(nums))

(2). 求多個數的平均值(高級操作)

# 定義一個函數,用來求平均值
def make_average():

    #創建一個空的列表
    nums = []

    # 創建一個函數,用來接收元素,來求平均值,
    def average(n):

        # 將元素添加到列表裏面
        nums.append(n)

        # 求平均值
        return sum(nums)/len(nums)

    # 返回一個函數對象
    return average

average = make_average()
print(average(10))      #  10.0
print(average(20))      #  15.0
nums = []               # 清空列表依然對函數沒有什麼影響
print(average(60))      #  30.0

(3). 總結:形成閉包的條件:

1.函數嵌套
2.將內部函數作爲返回值返回
3.內部函數必須要使用到外部函數的變量

(4). 什麼時候用閉包呢?

當你有些數據不希望別人訪問,不希望別人修改的時候,就需要用到閉包,這樣能確保我們的數據安全

03. - 函數 - 裝飾器引入

# 打印開始計算,打印計算結束
def add(a,b):

    # 求任意兩個數的和

    print('計算開始...')
    r = a + b
    print('計算結束...')
    return r

def mul(a,b):
    # 求任意兩個數的積
    return a * b

r = add(1,2)    # 3
r = mul(1,2)    # 2
print(r)

1.通過剛纔以上的步驟來實現當前的這個需要,我們發現了以下一些問題

(1).如果需要修改的函數過多,修改起來比較麻煩
(2).不方便後期維護
(3).這樣會違反一個開閉原則(ocp)
(4).我們在開發的時候,要求可以開發對程序的擴展,但是要關閉對程序的修改

改善後的程序:

# 打印開始計算,打印計算結束
def add(a,b):

    # 求任意兩個數的和
    r = a + b
     return r
     
def mul(a,b):
    # 求任意兩個數的積
    return a * b

r = add(1,2)
r = mul(1,2)



# 在不修改原函數的情況下,來對函數進行擴展
def fn():

    print('我是fn函數')

# 我創建一個新的函數

def fn2():

    print('函數開始執行......')

    fn()

    print('函數執行結束......')

# fn2()
def new_add(a,b):
    print('函數開始執行......')

    r = add(a,b)

    print('函數執行結束......')

    return r

r = new_add(1,2)
print(r)
>>>
函數開始執行......
函數執行結束......
3

04. - 函數 - 裝飾器的使用

1. 引導

# 打印開始計算,打印計算結束
def add(a,b):

    # 求任意兩個數的和

    # print('計算開始...')
    r = a + b
    # print('計算結束...')
    return r

def mul(a,b):
    # 求任意兩個數的積
    return a * b

r = add(1,2)    # 3
r = mul(1,2)    # 2
# print(r)



def start_end(old):

    # 用來對其他函數進行擴展,是其他函數可以在執行前打印執行開始,執行後打印執行結束

    # 創建一個函數
    def new_function(a,b):
        print('開始執行......')

        # 調用被擴展的函數
        result = old(a,b)

        print('開始結束......')
        return result

    # 返回函數
    return new_function

f = start_end(add)
r = f(1,2)
print(r)
>>>
開始執行......
開始結束......
3

2.接下來我們要用函數裝飾器來對任何函數進行一個擴展(例如關鍵字參數,位置參數,一百個各種各樣五花八門的函數),這個時候就需要用到一個一個參數 : args

*args : 接收的是所有的位置參數 ; **kwargs : 接受所有的關鍵字參數

# 在不修改原函數的情況下,來對函數進行擴展
def fn():

    print('我是fn函數')

# 我創建一個新的函數

def fn2():

    print('函數開始執行......')

    fn()

    print('函數執行結束......')

# fn2()
def new_add(a,b):
    print('函數開始執行......')

    r = add(a,b)

    print('函數執行結束......')

    return r




def start_end(old):

    # 用來對其他函數進行擴展,是其他函數可以在執行前打印執行開始,執行後打印執行結束

    # 創建一個函數    *args 接收的是所有的位置參數  **kwargs  接受所有的關鍵字參數
    def new_function(*args,**kwargs):
        print('開始執行......')

        # 調用被擴展的函數
        result = old(*args,**kwargs)

        print('開始結束......')
        return result

    # 返回函數
    return new_function

f = start_end(fn)
r = f()
print(r)
>>>
開始執行......
我是fn函數
開始結束......
None

3. 像 start_end(old) 這種函數我們就稱之爲裝飾器

通過裝飾器 可以在不修改原來函數的基礎之上來歲函數進行擴展

在開發當中,我們都是通過裝飾器來擴展函數的功能

(1)
# 打印開始計算,打印計算結束
def add(a,b):

    # 求任意兩個數的和

    # print('計算開始...')
    r = a + b
    # print('計算結束...')
    return r

def mul(a,b):
    # 求任意兩個數的積
    return a * b

r = add(1,2)    # 3
r = mul(1,2)    # 2

(2)
# 在不修改原函數的情況下,來對函數進行擴展
def fn():

    print('我是fn函數')

# 我創建一個新的函數

def fn2():

    print('函數開始執行......')

    fn()

    print('函數執行結束......')

# fn2()
def new_add(a,b):
    print('函數開始執行......')

    r = add(a,b)

    print('函數執行結束......')

    return r

(3)
ef start_end(old):

    # 用來對其他函數進行擴展,是其他函數可以在執行前打印執行開始,執行後打印執行結束

    # 創建一個函數    *args 接收的是所有的位置參數  **kwargs  接受所有的關鍵字參數
    def new_function(*args,**kwargs):
        print('開始執行......')

        # 調用被擴展的函數
        result = old(*args,**kwargs)

        print('開始結束......')
        return result

    # 返回函數
    return new_function

f = start_end(fn)
f2 = start_end(add)
# r = f()
r = f2(123,456)
print(r)
>>>
開始執行......
開始結束......
579
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章