函數,作用域,遞歸

函數的5種參數類型

POSITIONAL_OR_KEYWORD(位置參數或關鍵字參數)

VAR_POSITIONAL(可變參數)

KEYWORD_ONLY(關鍵字參數)

VAR_KEYWORD(可變關鍵字參數)

POSITIONAL_ONLY(位置參數)

POSITIONAL_OR_KEYWORD如其名所見,既可以用位置傳參,也可以用關鍵字傳參

def foo(name):
    print(name)
foo('a')  # a
foo(name='a')  # a

VAR_POSITIONAL是可變參數,通過*來聲明,它會把接收到的值存入一個元組

def foo(*args):
    print(args)
foo(1, 2, 3)  # (1,2,3)

KEYWORD_ONLY只能通過關鍵字傳參,這種參數會在VAR_POSITIONAL參數類型的後面,只能通過指定關鍵字來傳參,不可以用位置傳參

def f(name, *, val):
    print(name, val)
f('a', val=1)  # a 1

VAR_KEYWORD是可變關鍵字參數,通過前綴**來聲明,這種參數類型可以接收0個或多個參數,並存入一個字典

def foo(**kw):
    for key, value in kw.items():
        print('%s=%s' % (key, value), end=' ')
foo(a=1, b=2, c=3)  # a=1 b=2 c=3

高版本的Python無法創建一個POSITIONAL_ONLY類型的參數,但是有些使用C語言實現且不接收關鍵字參數的函數(如divmod)支持

 

默認參數

  1. VAR系列的兩個參數(可變參數、可變的關鍵詞參數)不允許設置默認參數,而另外兩個參數(位置和關鍵詞參數、關鍵詞參數)可以設置默認參數。 因爲VAR_POSITIONAL的默認參數是tuple()空元祖,而VAR_KEYWORD的默認參數是dict()空字典。
  2. 默認參數的位置POSITIONAL_OR_KEYWORD類型的默認參數一定要放在後面,否則會報錯。
  3. KEYWORD_ONLY雖然沒有強制要求,因爲都是用關鍵字傳參,誰先誰後無所謂,但最好還是放在後面。
  4. 默認參數最好不要設置爲可變類型(如dict、list、set)。 如果把默認參數設置爲可變類型,並在函數中改變了該參數的值,下次再調用它就不再是默認值了。

 

return

return作用:

  1. 結束函數
  2. 返回對象

不寫return語句會默認返回None

 

高階函數

  1. python一切皆對象,函數也是對象。
  2. 函數本身可以賦值給變量,即變量可以指向函數對象。
  3. 函數名其實就是指向函數對象的變量。
  4. 因爲變量可以指向函數對象,函數的參數能接收變量,那麼一個函數就可以接收另一個函數作爲參數,這種函數稱之爲高階函數。
  5. 函數對象也可以作爲函數的返回值。
  6. 內置的高階函數有filter,map,reduce。

 

匿名函數

python 使用 lambda 來創建匿名函數。

  1. lambda只是一個表達式,函數體比def簡單很多。
  2. lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。
  3. lambda函數擁有自己的命名空間,且不能訪問自有參數列表之外或全局命名空間裏的參數。
  4. 雖然lambda函數看起來只能寫一行,卻不等同於C或C++的內聯函數,後者的目的是調用小函數時不佔用棧內存從而增加運行效率。

語法

lambda [arg1 [,arg2,.....argn]]:expression

 

變量作用域

L:local 函數內部作用域 

E:enclosing 外部嵌套函數的作用域

G:global 全局作用域 

B:build-in 內置作用域

要修改global作用域中變量的值,要用global關鍵字對變量進行聲明

num = 1
def foo():
    global num  # 需要使用 global 關鍵字聲明
    print(num)  # 1
    num = 123
    print(num)  # 123
foo()
print(num)  # 123

內部函數要修改外部函數的變量的值,用nonlocal關鍵字聲明變量

def outer():
    num = 10
    def inner():
        nonlocal num  # nonlocal關鍵字聲明
        num = 100
        print(num)  # 100
    inner()
    print(num)  # 100
outer()

 

遞歸

遞歸條件:

  1. 需要調用自身函數
  2. 要有遞歸出口,也就是結束條件

遞歸調用實際上是函數自己在調用自己,而函數的調用開銷是很大的,系統要爲每次函數調用分配存儲空間,並將調用點壓棧予以記錄。而在函數調用結束後,還要釋放空間,彈棧恢復斷點。所以說,函數調用不僅浪費空間,還浪費時間。同一個問題,如果遞歸解決方案的複雜度不明顯優於其它解決方案的話,那麼使用遞歸是不划算的。方式有些問題使用迭代算法是很難甚至無法解決的(比如漢諾塔問題)。這時遞歸的作用就顯示出來了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章