天天看點

瘋狂Python講義學習筆記(含習題)之 函數和lambda表達式一、函數入門二、函數的參數三、局部函數四、函數的進階内容五、局部函數與lambda表達式

函數是執行特定任務的一段代碼,程式通過将一段代碼定義成函數,并為該函數指定一個函數名,這樣即可在需要的時候多次調用這段代碼。

一、函數入門

通俗來講,所謂函數,就是指為一段實作特定功能的代碼“取”一個名字,以後即可通過該名字來執行(調用)該函數。

函數可以接收零個或多個參數,也可以傳回零個或多個值。

瘋狂Python講義學習筆記(含習題)之 函數和lambda表達式一、函數入門二、函數的參數三、局部函數四、函數的進階内容五、局部函數與lambda表達式

從函數定義者(實作函數的人)的角度來看,至少需要想清楚一下3點:

● 函數需要幾個關鍵的需要動态變化的資料,這些資料應該被定義成函數的參數。

● 函數需要傳出幾個重要的資料(就是調用該函數的人希望得到的資料),這些資料應該被定義成傳回值。

● 函數的内部實作過程。

函數定義文法格式:

def 函數名(形參清單):
    # 由零條到多條可執行語句組成的函數
    [return [傳回值]]
           

● 函數名:一個合法的辨別符。

● 形參清單:用于定義該函數可以接受的參數。由多個形參名組成,之間用英文逗号隔開。——誰調用,誰負責對形參指派。

在函數體中使用return語句可以顯式地傳回一個值,return語句傳回的值既可是有值的變量,也可是一個表達式。

通過内置的help()函數可以檢視函數的幫助文檔——隻要把一段字元串放在函數聲明之後、函數體之前,這段字元串将被作為函數的部分,這個文檔就是函數的說明文檔。

除了help()函數,也可通過__doc__屬性通路函數的說明文檔。

在一個函數體内調用它自身,被成為函數遞歸。函數遞歸包含了一種隐式的循環,它會重複執行某段代碼,但這種重複執行無須循環控制。

如:已知有一個數列:f(0) = 1, f(1) = 4, f(n+2) = 2*f(n+1) + f(n),其中n是大于0的整數,求f(10)的值。

def fn(n):
    if n == 0:
        return 1
    elif n == 1:
        return 4
    else:
        # 在函數體中調用它自身,就是函數遞歸
        return 2 * fn(n - 1) + fn(n - 2)
​
​
# 輸出fn(10)的結果
print("fn(10)的結果是:", fn(10))
           

※ 遞歸一定要向已知方向進行。

二、函數的參數

按照形參位置傳入的參數被稱為位置參數。根據參數名來傳入參數值被稱為關鍵字(keyword)參數。

使用位置參數的方式來傳入參數值,必須嚴格按照定義函數時指定的順序來傳入參數值,使用關鍵字參數調用時,可交換參數的位置。

如果混合使用了關鍵字參數和位置參數,則關鍵字參數必須位于位置參數之後。換句話說,關鍵字參數之後隻能是關鍵字參數。

Python要求将帶預設值的參數定義在形參清單的最後。

Python允許在形參前面添加一個星号(*),這樣就意味着該參數可接收多個參數值,多個參數值被當成元組傳入。

Python允許個數可變的形參處于形參清單的任意位置(不要求是形參清單的最後一個參數),但一個函數最多隻能帶一個支援“普通”參數收集的形參。

Python還可以收集關鍵字參數,此時Python會将這種關鍵字參數收內建字典。為了讓Python能收集關鍵字參數,需要在參數前面添加兩個星号。

所謂逆向參數收集,指的是在程式已有清單、元組、字典等對象的前提下,把它們的元素“拆開”後傳給函數的參數。逆向參數收集需要在傳入的清單、元組參數之前添加一個星号,在字典參數之前添加兩個星号。代碼如下:

def test(name, message):
    print("使用者是:", name)
    print("歡迎消息:", message)
​
​
my_list = ['劉德華', '歡迎來Python世界']
test(*my_list)
           

即使支援收集的參數,如果需要将一個元組傳給該參數,那麼同樣需要使用逆向收集。如:

def foo(name, *nums):
    print("name參數:", name)
    print("nums參數:", nums)
​
​
my_tuple = (1, 2, 3)
# 使用逆向收集,将my_tuple元組的元素傳給nums
foo('fkit', *my_tuple)
           

這裡的*号相當于解包操作符,它會将元組拆分成元素,然後依次指派給函數的形參。如果通過

foo(*my_tuple)
           

來調用,則會将1指派給name,2,3指派給nums。

如果不使用逆向收集,通過foo(my_tuple)則會将my_tuple整體作為參數值傳給name參數。

字典也支援逆向收集,以關鍵字參數的形式傳入函數。

Python中函數的參數傳遞機制都是“值傳遞”。就是将實際參數值的副本(複制品)傳入函數,而參數本身不會受到影響。

● 不管什麼類型的參數,在Python函數中對參數直接使用“=”符号指派是沒用的,直接使用“=”符号指派并不能改變參數。

● 如果需要讓函數修改某些資料,則可以通過把這些資料包裝成清單、字典等可變對象,然後把清單、字典等可變對象作為參數傳入函數,在函數中通過清單、字典的方法修改它們。

變量分兩種:

● 局部變量。在函數中定義的變量,包括參數,都被稱為局部變量。

● 全局變量。在函數外面、全局範圍内定義的變量,被稱為全局變量。

每個函數執行時,系統都會為該函數配置設定一塊“臨時記憶體空間”,所有的局部變量都被儲存在這塊臨時記憶體空間内,當函數執行完畢,這塊記憶體空間就被釋放了,局部變量也就失效了,是以離開函數之後就不能再通路局部變量了。

全局變量可以在所有函數内被通路。

Python提供了三個工具函數來擷取指定範圍内的“變量字典”

● globals():該函數傳回全局範圍内所有變量組成的“變量字典”

● locals():該函數傳回目前局部範圍内所有變量組成的“變量字典”

● vars(object):擷取在指定對象範圍内所有變量組成的“變量字典”。如果不傳入object參數,vars()和locals()的作用完全相同。

● locals()總是擷取目前局部範圍内所有變量組成的“變量字典”,如果在全局範圍内(在函數之外)調用locals()函數,同樣會擷取全局範圍内所有變量組成的“變量字典”;而globals()無論在哪裡執行,總是擷取全局範圍内所有變量組成的“變量字典”

● 使用locals()和globals()擷取的“變量字典”隻應被通路,不應被修改。

Python文法規定:在函數内部對不存在的變量指派時,預設就是重新定義新的局部變量。

可以通過globals()函數在函數内部定義全局變量。

為了避免在函數中對全局變量指派(不是重新定義局部變量),可以使用global語句來聲明全局變量。

三、局部函數

Python支援在函數體内定義函數,被成為局部函數。

Python提供了nonlocal關鍵字,可以聲明通路指派語句隻是通路該函數所在的函數内部的局部變量。

global用于聲明通路全局變量,而nonlocal用于聲明通路目前函數所在函數内的局部變量。

四、函數的進階内容

Python的函數也是一種值:所有函數都是function對象,這意味着可以把函數本身指派給變量,就像把整數、浮點數、清單、元組指派給變量一樣。

Python支援像使用其他參數一樣使用函數參數。

Python還支援使用函數作為其他函數的傳回值。

五、局部函數與lambda表達式

lambda表達式是現代程式設計語言争相引入的一種文法,如果說函數是命名的、友善複用的代碼塊,那麼lambda表達式則是功能更靈活的代碼塊,它可以在程式中被傳遞和調用。

Python要求lambda表達式隻能是單行表達式。

lambda表達式的文法格式如下:

lambda [parameter_list]: 表達式
           

● lambda表達式必須使用lambda關鍵字定義

● 在lambda關鍵字之後、冒号左邊的是參數清單,可以沒有參數,也可以有多個參數。如果有多個參數,則需要用逗号隔開,冒号右邊是該lambda表達式的傳回值。

lambda表達式的本質就是匿名的、單行函數體的函數。

lambda表達式的用途:

● 對于單行函數,使用lambda表達式可以省去定義函數的過程,讓代碼更簡潔。

● 對于不需要多次複用的函數,使用lambda表達式可以在用完之後立即釋放,提高了性能。

習題:

1. 定義一個函數,該函數可接收一個list 作為參數,該函數使用直接選擇排序對list 排序。

def sort_list(sort_list):
    temp_list = []
    for i in range(len(sort_list)):
        min_var = min(sort_list)
        sort_list.remove(min_var)
        temp_list.append(min_var)
    return temp_list
​
​
my_list = [3, 2, 3, 2, 1, 3, 2, 2, 1]
print(sort_list(my_list))
           

2. 定義一個函數,該函數可接收一個list 作為參數,該函數使用冒泡排序對list 排序。

def sort_list(sort_lst):
    lst_len = len(sort_lst)
    for i in range(0, lst_len):
        sort_flag = True
        for j in range(0,lst_len - i - 1):
            if sort_lst[j] > sort_lst[j + 1]:
                sort_lst[j], sort_lst[j + 1] = sort_lst[j + 1], sort_lst[j]
                sort_flag = False
        if sort_flag:
            break
    return sort_lst
​
​
my_lst = [5, 9, 3, 1, 2, 8, 4, 7, 6]
print(sort_list(my_lst))
           

3. 定義一個is_leap(year) 函數,該函數可判斷year是否為閏年。若是閏年,則傳回True ;否則傳回False 。

def is_leap(year):
    year = int(year)
    if(year % 4 == 0) and (year % 100 != 0):
        return True
    elif (year % 400 == 0):
        return True
​
    else:
        return False
​
​
while(True):
    year = input('請輸入一個年份:')
    if year == 'exit':
        import sys
        sys.exit(0)
    print('%s是閏年嗎?%s' % (year, is_leap(year)))
           

4. 定義一個count_str_ char( my_ str)函數,該函數傳回參數字元串中包含多少個數字、多少個英文字母、多少個空白字元、多少個其他字元。

def count_str_char(my_str):
    digit_count = 0
    char_count = 0
    blank_count = 0
    other_count = 0
    for ch in my_str:
        if ch.isdigit():
            digit_count += 1
        elif ch.encode('utf-8').isalpha():
            char_count += 1
        elif ch.isspace():
            blank_count += 1
        else:
            other_count += 1
    return digit_count, char_count, blank_count, other_count
​
​
while(True):
    my_str = input('請輸入一個字元串:')
    if my_str == 'exit':
        import sys
        sys.exit(0)
    digit_count, char_count, blank_count, other_count = count_str_char(my_str)
    print('字母個數:', char_count)
    print('數字個數', digit_count)
    print('空白個數:', blank_count)
    print('其他字元個數:', other_count)
5. 定義一個fn(n)函數,該函數傳回1~n的立方和,即求1+2*2*2+3*3*3+…+n*n*n。



def fn(n):
    result = 0
    for i in range(n + 1):
        result += pow(i, 3)
    return result
​
​
while(True):
    n = input('請輸入一個整數:')
    if n == 'exit':
        import sys
        sys.exit(0)
    if not n.isdigit():
        print('您輸入的不是一個數字!')
        continue
    print('1~n的立方和為:', fn(int(n)))
           

6. 定義一個fn(n)函數,該函數傳回n 的階乘。

def fn(n):
    if n == 0:
        return 1
    if n == 1:
        return 1
    return n * fn(n-1)
​
​
while(True):
    n = input('請輸入一個整數:')
    if n == 'exit':
        import sys
        sys.exit(0)
    if not n.isdigit():
        print('您輸入的不是一個數字!')
        continue
    print('%s的階乘是:%d' % (n, fn(int(n))))
           

7.  定義一個函數,該函數可接收一個list 作為參數,該函數用于去除list 中重複的元素。

def list_uniq(lst):
    temp_lst = set(lst)
    return list(temp_lst)
​
​
my_lst = [1, 2, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4]
print(list_uniq(my_lst))
           

8. 定義一個fn(n)函數,該函數傳回一個包含n 個不重複的0~ 100 之間整數的元組。

import random
​
​
def fn(n):
    temp_lst = []
    for i in range(n):
        while(True):
            num = random.randint(0, 100)
            if num not in temp_lst:
                temp_lst.append(num)
                break
    return tuple(temp_lst)
​
​
print(fn(10))
           

9. 定義一個fn(n)函數,該函數傳回一個包含n 個不重複的大寫字母的元組。

import random
​
​
def fn(n):
    temp_lst = []
    for i in range(n):
        while(True):
            ch = chr(random.randint(65, 91))
            if ch not in temp_lst:
                temp_lst.append(ch)
                break
    return tuple(temp_lst)
​
​
print(fn(10))
           

10. 定義一個fn(n)函數,其中n 表示輸入n 行n 列的矩陣(數的方陣〉。在輸出時,先輸出n行n 列的矩陣,再輸出該矩陣的轉置形式。例如,當參數為3 時,先輸出:

1 2 3

4 5 6

7 8 9

再輸出:

1 4 7

2 5 8

3 6 9

def fn(n):
    # 先輸出n行n列的矩陣
    for i in range(n):
        for j in range(n):
            print(i * n + j + 1, end=' ')
        print()
    # 再輸出轉置矩陣
    for i in range(n):
        for j in range(n):
            print(j * n + i + 1, end=' ')
        print()
​
​
fn(3)
           

繼續閱讀