6、函式的高階運用
1、作用域
- 所謂作用域,就是變數的有效範圍,就是變數可以在哪個範圍以內使用。
- 有些變數可以在整段程式碼的任意位置使用,有些變數只能在函式內部使用,有些變數只能在 for 迴圈內部使用。
- 變數的作用域由變數的定義位置決定,在不同位置定義的變數,它的作用域是不一樣的。
1.1、全域性變數與區域性變數
- 定義在模組最外層的變數是全域性變數,它是全域性範圍內可見的,當然在函式裡面也可以讀取到全域性變數的
- 定義在函式內部的變數是區域性變數,它僅在函式內部可見
A = 10 # 全域性變數,約定俗成需要大寫
def foo():
b = 5 # 區域性變數
print(A) # a是全域性變數,函式內部可見,故結果是10
print(b) # b是區域性變數,函式內部可見,故結果是5
foo()
print(b) # b是區域性變數,僅在函式內部可見,在函式外部不可見,此結果報錯
結果:
- 區域性作用域和全域性作用域的變數同名的情況
a=10 # 為了與區域性變數一致,這裡不大寫
def func():
a=5 # 如果區域性變數與全域性變數重名,需要記住兩者是不一樣的變數,此時的區域性變數是一個新定義的區域性變數
print(a) # 故func()函式的結果是直接列印 5
func() # 5
print(a) # 10
# 結果是:
# 5
# 10
預設情況下,在區域性作用域對全域性變數只能進行 讀取 和 修改內部元素(可變型別) 的操作,不能對全域性變數進行重新賦值。重新賦值的情況請參考上面 區域性作用域和全域性作用域的變數同名的情況
- 讀取:
CITY_LISY=['BEIJING','SHANGHAI','GUANGZHOU','SHENZHEN']
def download():
print(CITY_LISY)
download()
# ['BEIJING', 'SHANGHAI', 'GUANGZHOU', 'SHENZHEN']
- 修改內部元素:
CITY_LISY=['BEIJING','SHANGHAI','GUANGZHOU','SHENZHEN']
def download():
CITY_LISY.append("DONGGUAN")
print(CITY_LISY)
download()
# ['BEIJING', 'SHANGHAI', 'GUANGZHOU', 'SHENZHEN', 'DONGGUAN']
1.2、global
關鍵字
利用global
關鍵字在函式內部重新賦值全域性變數
CITY_LISY=['BEIJING','SHANGHAI','GUANGZHOU','SHENZHEN']
def download():
global CITY_LISY # 利用global關鍵字在函式內部重新賦值全域性變數
CITY_LISY=['北京','上海','廣州','深圳']
print(CITY_LISY)
download()
# ['北京', '上海', '廣州', '深圳']
print(CITY_LISY) # 全域性變數已經被重新賦值
# ['北京', '上海', '廣州', '深圳']
2、函式的物件
Python中,函式是「頭等公民」。我們可以將函式賦值給變數,也可以將其作為引數傳入其他函式,將它們儲存在其他資料結構(如 dicts)中,並將它們作為其他函式的返回值。
即:可以把函式當成變數去使用
在函式名的末尾不新增()
,只寫名稱的格式所表示的是函式本身。我們將其稱之為函式物件, 可以像值一樣將其代入到變數中去。
- 可以將函式名(函式物件)賦值給變數,此時變數轉化成函式物件,可直接呼叫
def foo():
print("foo")
bar=foo # 將函式賦值給變數bar,注意是函式名,不帶()
bar() # 相當於呼叫了 foo()
# foo
bar # bar變數就是函式,即bar就是函式物件
# <function __main__.foo()>
- 把函式物件當做引數傳給另外一個函式
# 先定義一個函式,用來求輸入引數的10倍
def func1(x):
r = x * 10
return r
# 再定義一個函式,這個函式用來接收上一個函式
def func2(x, y, f): # f表示此引數是函式作為的引數
s = x + y + f(x) + f(y)
return s
# 呼叫
func2(2, 5, func1) # s=2+5+2*10+5*10=77
# 77
- 把函式物件當做另外一個函式的返回值
# 先定義一個函式,用來求輸入引數的10倍
def func1(x):
r = x * 10
return r
# 再定義一個函式,該函式返回剛才定義的第一個函式
def func2(f): # f表示函式
return f
r=func2(func1) # 將func2賦值給變數,注意內部func1函式是函式名,此時r是函式
r(5) # 呼叫,相當於:func2(func1(5)) = func1(5) = 5*10 = 50
# 50
r
# <function __main__.func1(x)>
3、高階函式
函式物件與變數平級,具有以下幾個特性:
- 可以將函式物件賦值給變數,此時變數轉化成函式物件,可直接呼叫
- 可以把函式物件當做引數傳給另外一個函式
- 可以把函式物件當做另外一個函式的返回值
3.1、高階函式
一個函式可以接收另一個函式作為引數,這種函式稱之為高階函式
示例:
def add(x, y, f): # add函式是高階函式,除了接受x,y兩個形參外,還接受了函式f作為引數
return f(x) + f(y)
add(-5,6,abs) # x=-5,y=6,f=abs ---> abs(-5) + abs(6) = 11
# 11
3.2、幾個重要的高階函式
3.2.1、map()
函式
map()
函式接收兩個引數,一個是函式,一個是序列。map()
函式將傳入的函式一次作用到序列的每個原色,並將結果作為新的序列返回。
示例:
比如我們有一個函式f(x)=x*x
,要把這個函式作用在一個序列[1,2,3,4,5,6,7,8,9]上,如下:
def f(x):
return x*x
r=map(f,[1,2,3,4,5,6,7,8,9]) # 傳入函式物件,即f
r
# <map at 0x24d07c3bbb0>
type(r)
# map
list(r)
# [1, 4, 9, 16, 25, 36, 49, 64, 81]
示例:
序列[1,2,3,4,5,6,7,8,9],將序列的數字轉化為字串型別
a=[1,2,3,4,5,6,7,8,9]
r=map(str,a) # str即內建函式str()的函式物件
list(r)
# ['1', '2', '3', '4', '5', '6', '7', '8', '9']
3.2.2、reduce()
函式
在python3中,reduce()
不是內建函式,需要引用:from functools import reduce
reduce()
函式,把一個函式作用在序列[x1,x2,x3,x4...]
上,這個接受的函式必須是兩個引數,reduce()
函式把結果繼續和序列的下一個元素做累積計算,其效果是:
reduce(func(x,y),[x1,x2,x3,x4]) = func(func(func(x1,x2),x3),x4)
示例:
from functools import reduce
def f(x, y):
return x*y
r = reduce(f, [1, 2, 3, 4, 5])
r
# 120
圖解map函式遇reduce函式的區別
3.2.3、filter()
函式
filter()
函式用於過濾序列。
- 和
map()
類似,filter()
也接收一個函式和一個序列。 - 和
map()
不同的是,filter()
把傳入的函式依次作用於每個元素,然後根據返回值是True還是False決定保留還是丟棄該元素。
示例:在一個list中,刪掉奇數,只保留偶數
def oushu(x): # 定義一個函式oushu(),用來判斷輸入引數是否是偶數,如果是則返回True,如果否則返回False
return x%2==0
oushu(6)
# True
oushu(5)
# False
r = filter(oushu,[1,2,3,4,5,6,7,8,9]) # 利用filter過濾掉奇數
r
# <filter at 0x24d07bff2e0>
list(r)
# [2, 4, 6, 8]
3.2.4、sorted()
函式
sorted()
函式是python內建的,用來對序列排序的函式。
語法:
list = sorted(iterable, key=None, reverse=False)
-
iterable
表示指定的序列(可迭代物件)。 -
key
引數可以自定義排序規則,可選。 -
reverse
引數指定以升序(False,預設)還是降序(True)進行排序,可選。
sorted()
函式不會修改原本的序列,返回一個已經排好序的list。
示例:
對列表排序,返回的物件不會改變原列表
>>> list_1=[55,44,66,33,77]
>>> sorted(list_1) # 預設升序
[33, 44, 55, 66, 77]
>>> sorted(list_1,reverse=True) # reverse=True 降序
[77, 66, 55, 44, 33]
>>> list_1 # 繼續輸出 list_1 看下是否有變化
[55, 44, 66, 33, 77]
>>> r=sorted(list_1)
>>> type(r)
list
>>> r
[33, 44, 55, 66, 77]
示例:
對元組排序
tuple_1=(55,44,66,33,77)
sorted(tuple_1)
# [33, 44, 55, 66, 77]
示例:
根據自定義規則來排序,使用引數:key
# 根據字元的長短進行降序排序
chars=[ 'is', 'handsome','boy', 'bruce','a']
sorted(chars,key=lambda x:len(x),reverse=True) # lambda x:len(x) 匿名函式,返回每個字元的長度
# ['handsome', 'bruce', 'boy', 'is', 'a']
示例:
用一組tuple表示學生名字和成績:L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)],分別按名字排序(升序)與按成績從高到低排序。
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
# 按名字排序(升序)
L1 = sorted(L, key=lambda x: x[0], reverse=False) # lambda x: x[0] 表示取得序列內每個元素的第一個內容
L1
# [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]
# 按成績從高到低排序
L2 = sorted(L, key=lambda x: x[1], reverse=True)
L2
# [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]
4、匿名函式
匿名函式指一類無須定義識別符號的函式或子程式。Python用 lambda
語法定義匿名函式,只需用表示式而無需申明。
語法如下:
lambda [引數1 [,引數2, ... 引數N]] : 表示式
如:
按照一般函式定義方法,定義一個求x平方的函式
def funca(x):
return x**2
funca(10)
# 100
用匿名函式來表示就是:
f = lambda x: x**2 # 匿名函式也是物件,將匿名函式的函式物件賦值給變數f,使得f轉化為函式物件
f(10)
# 100
多引數
f2 = lambda a,b,c:a**2+b**2+c**2
f2(1,2,3)
# 14
預設值
f3 = lambda a,b,c=2:a**2+b**2+c**2 # c變數預設為2,注意:預設值只能放在最後,否則會出錯
f3(1,3)
# 14
5、三元表示式
三元表示式
如有下面的程式:
a = 90
if a >= 60:
result = "及格"
else:
result = "不及格"
print(result)
# 及格
那麼用三元表示式來改寫,則如下所示:
a = 90
result= "及格" if a>=60 else "不及格" # 三元表示式
print(result)
# 及格
匿名函式遇三元表示式的結合
一般寫法:
def f1(x):
if x >= 60:
result = "及格"
else:
result = "不及格"
print(result)
f1(90)
# 及格
匿名函式遇三元表示式結合的寫法:
result=lambda x: "及格" if x>=60 else "不及格"
result(90)
# '及格'