Python 函數3000字使用總結

2020-08-12 16:22:57

今天是Python函數專題,目錄結構:

很多人學習python,不知道從何學起。
很多人學習python,掌握了基本語法過後,不知道在哪裏尋找案例上手。
很多已經做案例的人,卻不知道如何去學習更加高深的知識。
那麼針對這三類人,我給大家提供一個好的學習平臺,免費領取視訊教學,電子書籍,以及課程的原始碼!
QQ羣:101677771

  • Python 函數專題

  • 基礎部分

    • 1 函陣列成

    • 2 參照傳參

    • 3 預設參數與關鍵字參數

    • 4 可變參數

    • 5 內建函數

  • 進階部分

    • 6 偏函數

    • 7 遞回函數

    • 8 匿名函數

    • 9 高階函數

    • 10 巢狀函數

  • 總結

 

Python 函數專題

函數是一個接受輸入、進行特定計算併產生輸出的語句集。

我們把一些經常或反覆 反復被使用的任務放在一起,建立一個函數,而不是爲不同的輸入反覆 反復編寫相同的程式碼。

Python提供了printsortedmaxmap等內建函數,但我們也可以建立自己的函數,稱爲使用者定義函數。

基礎部分

1 函陣列成

如下自定義函數:

def foo(nums):
    """ 返回偶數序列"""
    evens = []
    for num in nums:
        if num%2==0:
            evens.append(num)
    return evens

可以看到函數主要組成部分:

  • 函數名:foo

  • 函數形參:nums

  • :: 函數體的控制字元,作用類似JavaC++的一對{}

  • 縮排:一般爲4個字元

  • """:爲函數新增註 加注釋

  • return: 函數返回值

以上函數求出列表nums中的所有偶數並返回,通過它瞭解Python函數的主要組成部分。

2 參照傳參

定義好一個函數後,使用:函數名+()+實參,呼叫函數,如下方法:

foo([10,2,5,4])

其中[10,2,5,4]爲實參,它通過by reference方式傳給形參nums,即nums指向列表頭,而不是重新複製一個列表給nums.

再看一個參照的例子:

def myFun(x): 
    x[0] = 20

如下呼叫:

lst = [10, 11, 12, 13, 14, 15] 
myFun(lst)

實參lst和形參x都指向同一個列表:

因此,對x[0]修改實際就是對實參lst的修改,結果如下:

但是,有時在函數內部形參指向改變,因此實參與形參的指向分離,如下例子:

def myFun(x):  
    x = [20, 30, 40]
    x[0] = 0

呼叫:

lst = [10, 11, 12, 13, 14, 15] 
myFun(lst)

x 被傳參後初始指向lst,如下所示:

但是,執行x = [20, 30, 40]後,物件x重新指向一個新的列表物件[20,30,40]

因此,對於x內元素的任何修改,都不會同時影響到lst,因爲指向已經分離。

3 預設參數與關鍵字參數

Python函數的參數,可以有初始預設值,在呼叫時如果不賦值,則取值爲預設值,如下例子:

def foo(length,width,height=1.0):
    return length*width*height

呼叫foo函數,沒有爲height傳參,所以取爲預設值1.0

r = foo(1.2,2.0)
print(r) # 2.4

使用預設值有一點需要區分,有的朋友會與關鍵字參數混淆,因爲它們都是para=value的結構,但是有一個很明顯的不同:預設值是宣告在函數定義時,關鍵字參數是在函數呼叫時使用的此結構。如下例子:

def foo(length,width,height=1.0): # height是預設參數
    return length*width*height

foo(width=2.0,length=1.2) #確定這種呼叫後才確定width和length是關鍵字參數

確定以上呼叫後,才確定widthlength是關鍵字參數,並且關鍵字參數不必按照形參表的順序呼叫。

4 可變參數

JavaC++在解決同一個函數但參數個數不同時,會使用函數過載的方法。Python使用可變參數的方法,非常靈活。

可變參數是指形參前帶有*的變數,如下所示:

def foo(length,*others):
    s = length
    for para in others:
        s *= para
    return s

我們可以像下面 下麪這樣方便的呼叫:

foo(1.2,2.0,1.0) # 2.4

如上,帶一個星號的參數被傳參後,實際被解釋爲元組物件。我們還可以這樣呼叫:

foo(1.2) # 1.2

5 內建函數

總結完函數的參數後,再舉幾個Python內建的常用函數。

pow

大部分朋友應該知道pow是個冪次函數,比如求:

pow(2,3) 

除此以外,pow還有第三個參數,使用更高效的演算法實現求冪後再求餘數:

pow(2,3,5) # 3

max,min

max,min用來求解最大最小值,實現relu函數:

def relu(x):
    return max(x,0)

sorted

sorted函數完成物件排序,它能接收一個指定排序規則的函數,完成定製排序。如下,根據字典值絕對值從小到大排序:

d = {'a':0,'b':-2,'c':1}
dr = sorted(d.items(),key=lambda x:abs(x[1])) 
print(dr) # [('a', 0), ('c', 1), ('b', -2)]

進階部分

Python有一個專門操作函數的模組:functools,能實現一些關於函數的特殊操作。

6 偏函數

偏函數固定函數的某些參數後,重新生成一個新的函數。

通常用法,當函數的參數個數太多,需要簡化時,使用partial建立一個新的函數。

假設我們要經常呼叫int函數轉換二進制字元,設定參數base爲2:

int('1010',base=2)

爲了避免每次都寫一個參數base,我們重新定義一個函數:

def int2(s):
    return int(s,base=2)

以後每次轉化字串時,只需int2('1010)即可,更加簡便。

偏函數也能實現上述功能:

from functools import partial

intp = partial(int,base=2) 

那麼有的朋友會問,偏函數就是個雞肋,重新定義的int2更加直觀容易理解,這個角度講確實是這樣。但是int2不能再接收base參數,但是intp函數還是能接收base參數,依然保留了原來的參數:

intp('10',base=16) # 16

可能看到這裏的讀者還是有些迷糊,不太確定怎麼使用偏函數。可以先記住:修改內建函數的預設參數,就像內建函數int預設參數base等於10,使用偏函數調整預設base值爲2.

7 遞回函數

遞回函數是指呼叫自身的函數。如下使用遞回反轉字串:

def reverseStr(s): 
    if not s:
        return s 
    return reverseStr(s[1:])+s[0]
    
print(reverseStr('nohtyp')) # python

reverseStr函數裏面又呼叫了函數reverseStr,所以它是遞回函數。

使用遞回函數需要注意找到正確的遞回基,防止陷入無限遞回。

更多使用遞回的例子大家可參考此公衆號之前推播。

8 匿名函數

匿名函數是指使用lambda關鍵字建立的函數。它的標準結構如下:

lambda 形參列表: 含有形參列表的表達式

表達式的計算值即爲lambda函數的返回值。

如下lambda函數:

lambda x,y: x+y

它等價於下面 下麪的f函數:

def f(x,y):
    return x+y

lambda函數常做爲max,sorted,map,filter等函數的key參數。

9 高階函數

可以用來接收另一個函數作爲參數的函數叫做高階函數。

如下f有一個參數g,而g又是函數,所以f是高階函數:

def f(g):
    g()

Python 中經常會遇到高階函數,今天介紹幾個內建的常用的高階函數。

map

map 函數第一個參數爲函數,它作用於列表中每個的元素。

如下,列表中的單詞未按照首字母大寫其他字元小寫的規則,使用map一一capitalize每個元素:

m = map(lambda s: s.capitalize(), ['python','Very','BEAUTIFUL'])
print(list(m))

結果:

['Python', 'Very', 'Beautiful']

reduce

reduce 高階函數實現化簡列表,它實現的效果如下:

如下例子,函數f等於x+y,求得兩數之和,然後再與第三個數相加,依次下去,直到列表尾部,進而得到整個列表的和:

from functools import reduce 

def f(x,y):
    return x+y

r = reduce(f, [1,3,2,4])
print(r) # 10

以上reduce求解過程等於:

需要注意:reduce函數要求f必須帶2個參數,只有這樣才能 纔能完成歸約化簡。

10 巢狀函數

巢狀函數是指裏面再巢狀函數的函數。

如下例子,將列錶轉化爲二元樹。已知列表nums

nums = [3,9,20,None,None,15,7],轉化爲下面 下麪二元樹:

二元樹定義:

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

構建滿足以上結構的二元樹,可以觀察到:樹的父節點和左右子節點的關係:

基於以上公式,再使用遞回構建二元樹。

遞回基情況:

if index >= len(nums) or nums[index] is None:
    return None

遞回方程:

根據以上分析,得到如下程式碼,list_to_binarytree函數是巢狀函數,它裏面還有一個level子函數:

def list_to_binarytree(nums):
    def level(index):
        if index >= len(nums) or nums[index] is None:
            return None
        
        root = TreeNode(nums[index])
        root.left = level(2 * index + 1)
        root.right = level(2 * index + 2)
        return root

    return level(0)

binary_tree = list_to_binarytree([3,9,20,None,None,15,7])

通常使用巢狀函數的場景:實現一個功能只需要編寫2個函數,寫成一個class好像顯得有些不必要,寫成巢狀後更簡潔,並且某些參數能共用,親和性會更好。不妨體會上面的nums參數。

總結

函數專題主要總結了以下:

  • Python 函數專題

  • 基礎部分

    • 1 函陣列成

    • 2 參照傳參

    • 3 預設參數與關鍵字參數

    • 4 可變參數

    • 5 內建函數

  • 進階部分

    • 6 偏函數

    • 7 遞回函數

    • 8 匿名函數

    • 9 高階函數

    • 10 巢狀函數