Python 學習日記3
——函數和Lambda表達式
3.1 函數
函數是代碼複用的重要手段,使程序更加簡潔。
定義函數要明白以下幾點
- 函數需要動態變化的數據,即爲函數定義的參數;
- 函數需要傳出調用函數後得到的數據,這些數據應被定義爲返回值。
- 函數具體實現的過程,即函數主體。
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 參數收集與逆向參數收集
- 參數收集
很多語言都允許定義個數可變的參數,這樣可以在嗲用函數時傳入任意多個參數。
Python也一樣,其方法實在形參前面添加一個星號 ‘*’,與序列在封包時一樣,表示該參數可以接收多個參數值,這些值被當成元組傳入。
Python還可以收集關鍵字參數,會將這些參數收集成字典,此時需要在參數前面添加兩個星號。
- 逆向參數收集
逆向收集參數即值在程序已有列表、元組等對象的前提下,把他們的元素拆開之後傳給函數的參數。
方法也一樣,在需要傳入的列表元組參數之前添加一個星號,在字典參數之前添加兩個星號。
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
解決方法:
- 通過globals()函數訪問name全局變量
- 在函數中聲明全局變量
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表達式可以在用完之後立即釋放,提高了性能。