
我的施工之路
目前已完成,以下五期Python專題總結:
1我的施工計劃
2數字專題
3字元串專題
4清單專題
5流程控制專題
6程式設計風格專題
今天是Python函數專題,目錄結構:
- Python 函數專題
- 基礎部分
- 1 函數組成
- 2 引用傳參
- 3 預設參數與關鍵字參數
- 4 可變參數
- 5 内置函數
- 進階部分
- 6 偏函數
- 7 遞歸函數
- 8 匿名函數
- 9 高階函數
- 10 嵌套函數
- 總結
Python 函數專題
函數是一個接受輸入、進行特定計算并産生輸出的語句集。
我們把一些經常或反複被使用的任務放在一起,建立一個函數,而不是為不同的輸入反複編寫相同的代碼。
Python提供了
print
、
sorted
、
max
、
map
等内置函數,但我們也可以建立自己的函數,稱為使用者定義函數。
基礎部分
1 函數組成
如下自定義函數:
def foo(nums):
""" 傳回偶數序列"""
evens = []
for num in nums:
if num%2==0:
evens.append(num)
return evens
可以看到函數主要組成部分:
- 函數名:
foo
- 函數形參:
nums
-
: 函數體的控制字元,作用類似:
或Java
的一對C++
{}
- 縮進:一般為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是關鍵字參數
确定以上調用後,才确定
width
和
length
是關鍵字參數,并且關鍵字參數不必按照形參表的順序調用。
4 可變參數
Java
和
C++
在解決同一個函數但參數個數不同時,會使用函數重載的方法。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 嵌套函數
- 總結