Python學習日記3

Python 學習日記3

——函數和Lambda表達式

3.1 函數

函數是代碼複用的重要手段,使程序更加簡潔。
定義函數要明白以下幾點

  1. 函數需要動態變化的數據,即爲函數定義的參數;
  2. 函數需要傳出調用函數後得到的數據,這些數據應被定義爲返回值。
  3. 函數具體實現的過程,即函數主體。

3.1.1 定義和調用函數

定義函數的語法格式:

def 函數名(參數列表):
    ...
    函數主體
    ...
    [return[返回值]]

  • 函數名只要是一個合法的標識符即可
  • 形參列表:參數之間以逗號隔開
  • retuen語句可以顯式的返回一個值,這個值可以是有具體值的變量也可以是一個表達式。

示例代碼:

def my_fun(x,y):
    z=x if x>y else y
    return z
result=my_fun(8,15)
print('result:',result)  #輸出結果:15
有多個返回值時

如果程序需要多個返回值,則既可以把多個值包裝成列表之後返回,也可以直接返回多個值。如果Python函數直接返回多個值,Python會自動將多個返回值封裝成元組。

3.1.2 遞歸函數

函數不僅可以調用其他函數也可以調用函數自身,即爲函數遞歸。函數遞歸包含了一種隱式的循環,它會重複執行某段代碼,但是這種重複執行無需循環控制。經典的例子有求斐波那契數列、求階乘和求冪等。
遞歸一定要向已知方向進行:在某個時刻函數的返回值是確定的,即不再調用它自身,否則遞歸就成了無窮遞歸,類似死循環。

示例:斐波那契數列

def fibonacci(i):
    if i<=2 and i>0:
        return 1
    else:
        return (fibonacci(i-2)+fibonacci(i-1))


for j in range(1,11):
    print(fibonacci(j),end='  ')  #打印斐波那契數列前十位數字
1  1  2  3  5  8  13  21  34  55 

3.2 函數的參數

3.2.1 關鍵字參數、位置參數

Python函數的參數名不是無意義的,其允許在調用函數時通過名字來傳入參數值。
按照參數位置傳入的爲位置參數,它是按位置順序傳入的;如果根據參數名來傳入參數,則位置順序就無關緊要。

def Data(width,height):
    return(2*(width*height))
print(Data(4,5)) #根據位置順序傳入參數
print(Data(height=5,width=4)) # 根據關鍵字傳入參數,可調換位置

但是,要求在調用函數時關鍵字參數關鍵字參數必須位於位置參數之後。

3.2.2 參數收集與逆向參數收集

  1. 參數收集

很多語言都允許定義個數可變的參數,這樣可以在嗲用函數時傳入任意多個參數。
Python也一樣,其方法實在形參前面添加一個星號 ‘*’,與序列在封包時一樣,表示該參數可以接收多個參數值,這些值被當成元組傳入。
Python還可以收集關鍵字參數,會將這些參數收集成字典,此時需要在參數前面添加兩個星號。

  1. 逆向參數收集

逆向收集參數即值在程序已有列表、元組等對象的前提下,把他們的元素拆開之後傳給函數的參數。
方法也一樣,在需要傳入的列表元組參數之前添加一個星號,在字典參數之前添加兩個星號。

3.2.3 參數的傳遞機制

Python中函數的參數傳遞機制都是‘值傳遞’。所謂值傳遞,就是將實際參數值的副本(複製品)傳入函數,而參數本身不會受到任何影響。

  • 不管什麼類型的參數,在函數中對函數直接使用“=”符號賦值是沒有用的,直接使用等號賦值並不能改變參數。
  • 如果要讓函數修改某些數據,則可以通過把這些數據包裝成列表、字典等可修改對象,然後把列表、字典等可變對象作爲參數傳入函數,在函數中通過列表、字典的方法修改他們。

3.2.4 變量作用域

  • 局部變量
  • 全局變量
    Python提供瞭如下三個工具函數來獲取指定範圍內的“變量字典”:
  • globals() :返回全局範圍內所有變量組成的“變量字典”;
  • locals(): 返回當前局部範圍內所有變量組成的“變量字典”;
  • vars(object): 獲取在指定對象範圍內所有變量組成的“變量字典”,如不傳入參數,其跟globals()作用一致。

全局變量默認在所有函數內都可以被訪問,但是在函數中定義了與全局變量同名的變量,此時就會發生局部變量遮蔽(hide)全局變量的情形。

name='James'
def NBA():
    print(name)
    name='Durant'
test()
print(name)

#報錯:
C:\Users\WD\PycharmProjects:
UnboundLocalError: local variable 'name' referenced before assignment

解決方法:

  1. 通過globals()函數訪問name全局變量
  2. 在函數中聲明全局變量

3.3 函數的高級內容

函數本身也作爲一個對象,既可以用於賦值,也可以用作其他函數的參數,還可以作爲其他函數的返回值。

1.使用函數變量
Python的函數也是一種值,所有的函數都時function對象,可以把函數本身賦值給變量,賦值之後程序也可以通過調用變量來調用函數。

2.使用函數作爲函數形參

3.使用函數作爲返回值

def get_math_fun(type):
    def square(n):
        return n*n   #計算平方的局部函數
    def cube(n):
        return n*n*n   #計算立方的局部函數
    def factorial(n):  #計算階乘的局部函數
        result=1
        for i in range(2,n+1):
            result*=i
        return  result
    if type=='square':
        return square
    if type=='cube':
        return cube
    else:
        return factorial    #函數作爲返回值

math_fn=get_math_fun('cube')
print(math_fn(5)

3.4 局部函數與lambd表達式

在上一段代碼中我們引入了三個局部函數來分別計算,但是局部函數的作用域默認僅停留在其封閉函數之內,因而其作用及其有限——僅僅在程序的if語句中作爲返回值使用,一旦離開函數體就失去了意義。

既然局部函數名沒有太大意義,那麼就考慮使用lambda表達式來簡化局部函數的寫法,如下:

def get_math_fun(type):
    if type=='square':
        return lambda n: n*n
    if type=='cube':
        return lambda n: n*n*n
    else:
        return lambda n: n*(n+1)/2
math_fn=get_math_fun('cube')
print(math_fn(5))

明顯簡化了很多很多。

lambd表達式的語法格式如下:

lambda[參數列表]:表達式

實際上,lambda表達式的本質就是匿名的、單行函數體的函數。雖然lambda表達式只能創建簡單的函數對象,知識和函數體爲單行的情形,但他依然有如下兩個用途:

  • 對於單行函數,使用lambda表達式省去定義函數的過程,讓代碼更加簡潔。
  • 對於不需要多次複用的函數,使用lambda表達式可以在用完之後立即釋放,提高了性能。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章