從零開始學Python:20課-函式使用進階
在之前的課程中,我們講到過關於函式的知識,我們還講到過Python中常用的資料型別,這些型別的變數都可以作為函式的引數或返回值;透過前幾節課的學習,我們又知道了寫在類中的函式通常稱之為方法,它代表了類或者物件可以接收的訊息。如果我們把這些知識彙總一下,我們的函式就可以做更多的事情。
關鍵字引數
下面是一個判斷傳入的三條邊長能否構成三角形的函式,在呼叫函式傳入引數時,我們可以指定引數名,也可以不指定引數名,程式碼如下所示。
def can_form_triangle(a, b,
c):
print(f'a = {a}, b = {b},
c = {
c}')
return a + b >
c and b +
c > a and a +
c > b
# 呼叫函式傳入引數不指定引數名按位置對號入座
print(can_form_triangle(
1,
2,
3))
# 呼叫函式透過“引數名=引數值”的形式按順序傳入引數
print(can_form_triangle(a=
1, b=
2,
c=
3))
# 呼叫函式透過“引數名=引數值”的形式不按順序傳入引數
print(can_form_triangle(
c=
3, a=
1, b=
2))
在沒有特殊處理的情況下,函式的引數都是 位置引數,也就意味著傳入引數的時候對號入座即可,如上面程式碼的第7行所示,傳入的引數值1、2、3會依次賦值給引數a、b、c。當然,也可以透過引數名=引數值的方式傳入函式所需的引數,因為指定了引數名,傳入引數的順序可以進行調整,如上面程式碼的第9行和第11行所示。
呼叫函式時,如果希望函式的呼叫者必須以引數名=引數值的方式傳參,可以用 命名關鍵字引數取代位置引數。所謂命名關鍵字引數,是在函式的引數列表中,寫在*之後的引數,程式碼如下所示。
def
can_form_triangle
(*, a, b, c):
print(
f'a =
{a}, b =
{b}, c =
{c}')
return a + b > c
and b + c > a
and a + c > b
# TypeError: can_form_triangle() takes 0 positional arguments but 3 were given
# print(is_valid_for_triangle(3, 4, 5))
# 傳參時必須使用“引數名=引數值”的方式,位置不重要
print(can_form_triangle(a=3, b=4, c=5))
print(can_form_triangle(c=5, b=4, a=3))
注意:上面的can_form_triangle函式,引數列表中的*是一個分隔符,*前面的引數都是位置引數,而*後面的引數就是命名關鍵字引數。
我們之前講過在函式的引數列表中可以使用 可變引數*args來接收任意數量的引數,但是我們需要看看,*args是否能夠接收帶引數名的引數。
def
calc
(*args):
result =
0
for arg
in args:
result += arg
return result
print(calc(a=
1, b=
2, c=
3))
執行上面的程式碼會引發TypeError錯誤,錯誤訊息為calc() got an unexpected keyword argument 'a',由此可見,*args並不能處理帶引數名的引數。我們在設計函式時,如果既不知道呼叫者會傳入的引數個數,也不知道呼叫者會不會指定引數名,那麼同時使用可變引數和 關鍵字引數。關鍵字引數會將傳入的帶引數名的引數組裝成一個字典,引數名就是字典中鍵值對的鍵,而引數值就是字典中鍵值對的值,程式碼如下所示。
def calc(*args, **kwargs):
result =
0
for
arg
in args:
result +=
arg
for value
in kwargs.values():
result += value
return total
print(calc()) #
0
print(calc(
1,
2,
3)) #
6
print(calc(a=
1, b=
2, c=
3)) #
6
print(calc(
1,
2, c=
3, d=
4)) #
10
提示: 不帶引數名的引數(位置引數)必須出現在帶引數名的引數(關鍵字引數)之前,否則將會引發異常。例如,執行calc(1, 2, c=3, d=4, 5)將會引發SyntaxError錯誤,錯誤訊息為positional argument follows keyword argument,翻譯成中文意思是“位置引數出現在關鍵字引數之後”。
高階函式的用法
在前面幾節課中,我們講到了物件導向程式設計,在物件導向的世界中,一切皆為物件,所以類和函式也是物件。函式的引數和返回值可以是任意型別的物件,這就意味著 函式本身也可以作為函式的引數或返回值,這就是所謂的 高階函式。
如果我們希望上面的calc函式不僅僅可以做多個引數求和,還可以做多個引數求乘積甚至更多的二元運算,我們就可以使用高階函式的方式來改寫上面的程式碼,將加法運算從函式中移除掉,具體的做法如下所示。
def
calc(
*args, init_value, op, **kwargs):
result = init_value
for arg
in args:
result = op(result, arg)
for
value
in kwargs.values():
result = op(result,
value)
return result
注意,上面的函式增加了兩個引數,其中init_value代表運算的初始值,op代表二元運算函式。經過改造的calc函式不僅僅可以實現多個引數的累加求和,也可以實現多個引數的累乘運算,程式碼如下所示。
def
add
(x, y):
return x + y
def mul(x, y):
return x * y
print(calc(
1,
2,
3, x=
4, y=
5, init_value=
0, op=add))
# 15
print(calc(1, 2, init_value=1, op=mul, x=3, y=4, z=5)) # 120
透過對高階函式的運用,calc函式不再和加法運算耦合,所以靈活性和通用性會變強,這是程式設計中一種常用的技巧,但是最初學者來說可能會稍微有點難以理解。需要注意的是,將函式作為引數和呼叫函式是有顯著的區別的, 呼叫函式需要在函式名後面跟上圓括號,而把函式作為引數時只需要函式名即可。上面的程式碼也可以不用定義add和mul函式,因為Python標準庫中的operator模組提供了代表加法運算的add和代表乘法運算的mul函式,我們直接使用即可,程式碼如下所示。
import
operator
print(calc(init_value=0,
op=operator.add,
1
,
2
,
3
,
x=4,
y=5))
# 15
print(calc(init_value=1, op=operator.mul, 1, 2, x=3, y=4, z=5)) # 120
Python內建函式中有不少高階函式,我們前面提到過的filter和map函式就是高階函式,前者可以實現對序列中元素的過濾,後者可以實現對序列中元素的對映,例如我們要去掉一個整數列表中的奇數,並對所有的偶數求平方得到一個新的列表,就可以直接使用這兩個函式來做到,具體的做法是如下所示。
def
is_even
(num):
return num %
2 ==
0
def square(num):
return num **
2
numbers1 = [
35,
12,
8,
99,
60,
52]
numbers2 = list(map(square, filter(is_even, numbers1)))
print(numbers2)
# [144, 64, 3600, 2704]
當然,要完成上面程式碼的功能,也可以使用列表生成式,列表生成式的做法更為簡單優雅。
numbers1
=
[35,
12
,
8
,
99
,
60
,
52
]
numbers2
=
[num
**
2
for
num
in
numbers1
if
num
%
2
==
0
]
print(numbers2)
# [144, 64, 3600, 2704]
Lambda函式
在使用高階函式的時候,如果作為引數或者返回值的函式本身非常簡單,一行程式碼就能夠完成,那麼我們可以使用 Lambda函式來表示。Python中的Lambda函式是沒有的名字函式,所以很多人也把它叫做 匿名函式,匿名函式只能有一行程式碼,程式碼中的表示式產生的運算結果就是這個匿名函式的返回值。上面程式碼中的is_even和square函式都只有一行程式碼,我們可以用Lambda函式來替換掉它們,程式碼如下所示。
numbers1
=
[35,
12
,
8
,
99
,
60
,
52
]
numbers2
=
list(map(lambda
x:
x
**
2
,
filter(lambda
x:
x
%
2
==
0
,
numbers1)))
print(numbers2)
# [144, 64, 3600, 2704]
透過上面的程式碼可以看出,定義Lambda函式的關鍵字是lambda,後面跟函式的引數,如果有多個引數用逗號進行分隔;冒號後面的部分就是函式的執行體,通常是一個表示式,表示式的運算結果就是Lambda函式的返回值,不需要寫return 關鍵字。
如果需要使用加減乘除這種簡單的二元函式,也可以用Lambda函式來書寫,例如呼叫上面的calc函式時,可以透過傳入Lambda函式來作為op引數的引數值。當然,op引數也可以有預設值,例如我們可以用一個代表加法運算的Lambda函式來作為op引數的預設值。
def
calc(
*args, init_value=
0, op=lambda x, y: x + y, **kwargs):
result = init_value
for arg
in args:
result = op(result, arg)
for
value
in kwargs.values():
result = op(result,
value)
return result
# 呼叫calc函式,使用init_value和op的預設值
print(calc(1, 2, 3, x=4, y=5)) # 15
# 呼叫calc函式,透過lambda函式給op引數賦值
print(calc(1, 2, 3, x=4, y=5, init_value=1, op=lambda x, y: x * y)) # 120
提示:注意上面的程式碼中的calc函式,它同時使用了可變引數、關鍵字引數、命名關鍵字引數,其中命名關鍵字引數要放在可變引數和關鍵字引數之間,傳參時先傳入可變引數,關鍵字引數和命名關鍵字引數的先後順序並不重要。
有很多函式在Python中用一行程式碼就能實現,我們可以用Lambda函式來定義這些函式,呼叫Lambda函式就跟呼叫普通函式一樣,程式碼如下所示。
import
operator,
functools
#
一行程式碼定義求階乘的函式
fac
=
lambda num:
functools.reduce(operator.mul,
range(1,
num
+
1
),
1
)
#
一行程式碼定義判斷素數的函式
is_prime
=
lambda x:
x
>
1
and
all(map(lambda
f:
x
%
f,
range(2,
int(x
**
0.5
)
+
1
)))
#
呼叫Lambda函式
print(fac(10))
# 3628800
print(is_prime(9)) # False
提示1:上面使用的reduce函式是Python標準庫functools模組中的函式,它可以實現對資料的歸約操作,通常情況下, 過濾(filter)、 對映(map)和 歸約(reduce)是處理資料中非常關鍵的三個步驟,而Python的標準庫也提供了對這三個操作的支援。
提示2:上面使用的all函式是Python內建函式,如果傳入的序列中所有布林值都是True,all函式就返回True,否則all函式就返回False。
簡單的總結
Python中的函式可以使用可變引數*args和關鍵字引數**kwargs來接收任意數量的引數,而且傳入引數時可以帶上引數名也可以沒有引數名,可變引數會被處理成一個元組,而關鍵字引數會被處理成一個字典。Python中的函式也是物件,所以函式可以作為函式的引數和返回值,也就是說,在Python中我們可以使用高階函式。如果我們要定義的函式非常簡單,只有一行程式碼且不需要名字,可以將函式寫成Lambda函式(匿名函式)的形式。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69923331/viewspace-2708121/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 從零開始學Python:21課-函式的高階應用Python函式
- 從零開始學Python:第八課-函式和模組Python函式
- 從零開始學Python:第十課-函式和字串的應用Python函式字串
- 從零開始學Python:19課-使用PyCharm開發Python應用程式PythonPyCharm
- 從零開始學PythonPython
- 從零開始學Python:第22課-Python標準庫初探Python
- 從零開始學Python—第六課:迴圈結構Python
- 從零學Python:17課-物件導向程式設計(進階)Python物件程式設計
- 【從零開始學習 MySql 資料庫】(2) 函式MySql資料庫函式
- Python 函式進階-高階函式Python函式
- 從零開始學黑蘋果-進階安裝教程(10.12.6)蘋果
- 從零開始學習 React 高階元件React元件
- 從零開始學Python:第九課-常用資料結構之字串Python資料結構字串
- 從零開始的Python學習Episode 15——正規表示式Python
- Python 函式進階-遞迴函式Python函式遞迴
- Python函式的進階Python函式
- 《Python深度學習從零開始學》簡介Python深度學習
- 從零開始學Python:第十一課-常用資料結構之列表Python資料結構
- 從零開始學Python:第十三課-列表和元組的應用Python
- Python進階07 函式物件Python函式物件
- Python 函式進階-迭代器Python函式
- 從零開始學Python:第十二課-常用資料結構之元組Python資料結構
- 《從零開始學Python網路爬蟲》概要Python爬蟲
- python Scrapy 從零開始學習筆記(一)Python筆記
- python Scrapy 從零開始學習筆記(二)Python筆記
- 從零開始學 Python 之基礎語法Python
- 【從零開始學爬蟲】模板的高階選項爬蟲
- 從零開始學 Spring BootSpring Boot
- 從零開始學正則
- 從零開始學習laravelLaravel
- 從零開始學習KafkaKafka
- 【ROS】從零開始學ROSROS
- 從零開始的Python學習Episode 6——字串操作Python字串
- 09-Python之路---函式進階Python函式
- python進階(17)偏函式partialPython函式
- python進階(20) 正規表示式的超詳細使用Python
- ??Java開發者的Python快速進修指南:函式進階JavaPython函式
- 無需手工設計,從零開始搜尋損失函式函式