函數(shù)就是一段封裝好的,可以重復(fù)使用的代碼,它使得我們的程序更加模塊化,不需要編寫(xiě)大量重復(fù)的代碼。函數(shù)還可以接收參數(shù),并根據(jù)參數(shù)的不同做出不同的操作,最后再把處理結(jié)果返回給我們。函數(shù)的本質(zhì)就是一段有特定功能、可以重復(fù)使用的代碼。
基本語(yǔ)法:
def functionname( parameters ):
'函數(shù)_文檔字符串'
function_suite
return [expression]
函數(shù)調(diào)用的基本語(yǔ)法格式:
[返回值] = 函數(shù)名([形參值])
在使用函數(shù)時(shí),經(jīng)常會(huì)用到形式參數(shù)(簡(jiǎn)稱“形參”)和實(shí)際參數(shù)(簡(jiǎn)稱“實(shí)參”),二者之間的區(qū)別是:
Python 函數(shù)的參數(shù)傳遞:
◆ 不可變類型:類似 C++ 的傳值調(diào)用(實(shí)際上重新復(fù)制了一個(gè)副本給形參,不改變調(diào)用函數(shù)實(shí)參變量的內(nèi)容),如 整數(shù)、字符串、元組。如fun(a),傳遞的只是a的值,沒(méi)有影響a對(duì)象本身。比如在 fun(a)內(nèi)部修改 a 的值,只是修改另一個(gè)復(fù)制的對(duì)象,不會(huì)影響 a 本身。
◆ 可變類型:類似 C++ 的引用傳遞(也叫傳址調(diào)用:將實(shí)參地址給形參,將改變調(diào)用函數(shù)實(shí)參變量的內(nèi)容),如 列表,字典。如 fun(a),則是將 a 真正的傳過(guò)去,修改后fun外部的a也會(huì)受影響
調(diào)用函數(shù)時(shí)常用的參數(shù)使用類型:
◆ 位置參數(shù)(必選參數(shù)):函數(shù)調(diào)用時(shí),實(shí)參默認(rèn)按位置順序進(jìn)行傳遞,并且要求個(gè)數(shù)和形參完全匹配。
◆ 默認(rèn)參數(shù):調(diào)用函數(shù)時(shí),默認(rèn)參數(shù)的值如果沒(méi)有傳入,則被認(rèn)為是默認(rèn)值。
◆ 命名參數(shù) (關(guān)鍵字參數(shù)):使用關(guān)鍵字參數(shù)允許函數(shù)調(diào)用時(shí)參數(shù)的順序與聲明時(shí)不一致,通過(guò)參數(shù)名進(jìn)行匹配。
◆ 可變參數(shù):你可能需要一個(gè)函數(shù)能處理比當(dāng)初聲明時(shí)更多的參數(shù),這些參數(shù)叫做不定長(zhǎng)參數(shù)或可變參數(shù)。
# 函數(shù)中參數(shù)的用法# 位置參數(shù)def location_param(a, b, c): print(a, b, c)location_param(1, 2, 3) # 1 2 3# 默認(rèn)參數(shù)def default_param(a, b, c=20): # 默認(rèn)值要放在最后面 print(a, b, c)default_param(8, 9) # 8,9,20 未傳入默認(rèn)值時(shí),打印默認(rèn)值default_param(8, 9, 10) # 8,9,10 傳入默認(rèn)值時(shí),實(shí)際傳入的值會(huì)覆蓋默認(rèn)值# 命名參數(shù)default_param(b=5, a=9, c=10) # 9 5 10 命名參數(shù)的順序可以自定義# 可變參數(shù)-元組形式def variable_param_1(a, *b): print(a, b)variable_param_1(1, 2, 3) # 1 (2, 3)# 可變參數(shù)-字典形式def variable_param_2(a, **b): print(a, b)variable_param_2(1, name='jigang.chen', age=28) # 1 {'name': 'jigang.chen', 'age': 28}# 可變參數(shù)-萬(wàn)能參數(shù)def variable_param_2(*a, **b): # 元組參數(shù)要放在字典參數(shù)前面 print(a, b)variable_param_2(15252162666, '徐州市', name='jigang.chen',age=28) # 相同類型的參數(shù)要放在一起 (15252162666, '徐州市') {'name': 'jigang.chen', 'age': 28}
Python中,用 def 語(yǔ)句創(chuàng)建函數(shù)時(shí),可以用 return 語(yǔ)句指定應(yīng)該返回的值,該返回值可以是任意類型。需要注意的是,return 語(yǔ)句在同一函數(shù)中可以出現(xiàn)多次,但只要有一個(gè)得到執(zhí)行,就會(huì)直接結(jié)束函數(shù)的執(zhí)行。 函數(shù)中,使用 return 語(yǔ)句的語(yǔ)法格式如下:
return [返回值]
其中,返回值參數(shù)可以指定,也可以省略不寫(xiě)(將返回空值 None)。
# 多個(gè)return情況,只會(huì)有一個(gè)返回值def fun_return(a): if a > 0: return True else: return Falseresult = fun_return(1)print(result) # Truedef func_return_param(a, b): c = a + b return c, a, b # 會(huì)自動(dòng)返回一個(gè)元組add = func_return_param(10, 20)# 函數(shù)賦值給變量x, y, z = func_return_param(10, 20)print(add) # (30, 10, 20)print(x, y, z) # 30 10 20
所謂作用域(Scope),就是變量的有效范圍,變量可以在哪個(gè)范圍以內(nèi)使用。有些變量可以在整段代碼的任意位置使用,有些變量只能在函數(shù)內(nèi)部使用,有些變量只能在 for 循環(huán)內(nèi)部使用。 變量的作用域由變量的定義位置決定,在不同位置定義的變量,它的作用域是不一樣的。本節(jié)我們只講解兩種變量: 局部變量和全局變量。
在函數(shù)內(nèi)部定義的變量,它的作用域也僅限于函數(shù)內(nèi)部,出了函數(shù)就不能使用了,我們將這樣的變量稱為局部變量(Local Variable)。
# 局部變量def local_variable(): age = 28 # 函數(shù)體內(nèi)定義的變量為局部變量、無(wú)法被外部調(diào)用 print(f'函數(shù)體內(nèi)的局部變量為:{locals()}')def local_variable_2(height, weight): # 函數(shù)傳入的參數(shù)也是局部變量,只能在函數(shù)體內(nèi)使用 print(height, weight)local_variable() # {'age': 28}local_variable_2('175cm', '75kg') # 175cm 75kg
除了在函數(shù)內(nèi)部定義變量,Python 還允許在所有函數(shù)的外部定義變量,這樣的變量稱為全局變量(Global Variable)。
和局部變量不同,全局變量的默認(rèn)作用域是整個(gè)程序,即全局變量既可以在各個(gè)函數(shù)的外部使用,也可以在各函數(shù)內(nèi)部使用。
# 全局變量name = 'python'def global_variable(): print(f'函數(shù)體內(nèi)訪問(wèn)全局變量:{name}')def global_variable_2(): global name # 使用global修飾的變量為全局變量 name = 'java' print(f'函數(shù)體內(nèi)訪問(wèn)全局變量:{name}')def global_variable_3(): global work_number work_number = 227 print(f'函數(shù)體內(nèi)的全局變量為:{globals()}')global_variable() # pythonprint(f'函數(shù)體外訪問(wèn)全局變量:{name}') # pythonglobal_variable_2() # java 由于在函數(shù)中使用global修飾了name變量并對(duì)name再次進(jìn)行了賦值,因此改變了全局變量name的值global_variable_3() # {......'name': 'java', 'work_number': 227}print(f'函數(shù)體外的全局變量為:{globals()}') # {......'name': 'java', 'work_number': 227}print(f'函數(shù)體外的局部變量為:{locals()}') # 當(dāng)locals()在函數(shù)體內(nèi)調(diào)用,獲取的是函數(shù)體內(nèi)的局部變量;當(dāng)locals()在函數(shù)體外調(diào)用,獲取的是全局變量,作用等同于globals();
globals() 函數(shù)為 Python 的內(nèi)置函數(shù),它可以返回一個(gè)包含全局范圍內(nèi)所有變量的字典,該字典中的每個(gè)鍵值對(duì), 鍵為變量名,值為該變量的值。
# 在函數(shù)體內(nèi)調(diào)用def global_variable_3(): global work_number work_number = 227 print(f'函數(shù)體內(nèi)的全局變量為:{globals()}')# 在函數(shù)體外調(diào)用print(f'函數(shù)體外的全局變量為:{globals()}')
locals() 函數(shù)也是 Python 內(nèi)置函數(shù)之一,通過(guò)調(diào)用該函數(shù),我們可以得到一個(gè)包含當(dāng)前作用域內(nèi)所有變量的字典。 這里所謂的“當(dāng)前作用域”指的是,在函數(shù)內(nèi)部調(diào)用 locals() 函數(shù),會(huì)獲得包含所有局部變量的字典;
# 當(dāng)locals()在函數(shù)體內(nèi)調(diào)用,獲取的是函數(shù)體內(nèi)的局部變量def local_variable(): age = 28 # 函數(shù)體內(nèi)定義的變量為局部變量、無(wú)法被外部調(diào)用 print(f'函數(shù)體內(nèi)的局部變量為:{locals()}')# 當(dāng)locals()在函數(shù)體外調(diào)用,獲取的是全局變量,作用等同于globals()print(f'函數(shù)體外的局部變量為:{locals()}')
vars() 函數(shù)也是 Python 內(nèi)置函數(shù),其功能是返回一個(gè)指定 object 對(duì)象范圍內(nèi)所有變量組成的字典。如果不傳入 object 參數(shù),vars() 和 locals() 的作用完全相同。
# 獲取指定范圍內(nèi)的變量class demo: name = 'python' city = 'suzhou'print(vars(demo)) # {'__module__': '__main__', 'name': 'python', 'city': 'suzhou'...}
Python還支持在函數(shù)體內(nèi)定義函數(shù),這種被放在函數(shù)體內(nèi)定義的函數(shù)稱為局部函數(shù)。 在默認(rèn)情況下,局部函數(shù)對(duì)外部是隱藏的,局部函數(shù)只能在其封閉(enclosing)函數(shù)內(nèi)有效。
# 局部函數(shù),形式一:在外部函數(shù)中調(diào)用內(nèi)部函數(shù)def fun_a(): def fun_b(): print('i need python') fun_b()# 局部函數(shù),形式二:將內(nèi)部函數(shù)作為外部函數(shù)的返回值def fun_c(): def fun_d(): print('i love testing') return fun_d # 返回函數(shù)對(duì)象fun_a() # i need pythonfun_cc = fun_c() # fun_cc變量接收的是fun_c()函數(shù)的返回值,等同于fun_d,如果想要調(diào)用fun_d,使用fun_cc()即可fun_cc() # i love testing
nonlocal關(guān)鍵字:內(nèi)部函數(shù)本身可以直接調(diào)用外部函數(shù)的變量,但若在內(nèi)部函數(shù)想要聲明一個(gè)和外部函數(shù)重名的變量,需使用nonlocal關(guān)鍵字聲明
# 局部函數(shù):在內(nèi)部函數(shù)聲明和外部函數(shù)相同名稱的變量--nonlocaldef fun_f(): name = 'python' def fun_h(): nonlocal name # 若在內(nèi)部函數(shù)想要聲明一個(gè)和外部函數(shù)重名的變量,需使用nonlocal關(guān)鍵字聲明 name = 'java' print(name) fun_h()
在定義函數(shù)的時(shí)候,不想給函數(shù)起一個(gè)名字,這個(gè)時(shí)候就可以用lambda來(lái)定義一個(gè)匿名函數(shù),lambda 表達(dá)式, 又稱匿名函數(shù)。
語(yǔ)法:
變量名= lambda 參數(shù):表達(dá)式
◆ 參數(shù):可選,通常以逗號(hào)分隔的變量表達(dá)式形式,也就是位置參數(shù)
◆ 表達(dá)式:不能包含循環(huán)、return,可以包含if...else...
可以理解 lambda 表達(dá)式,就是簡(jiǎn)單函數(shù)(函數(shù)體僅是單行的表達(dá)式)的簡(jiǎn)寫(xiě)版本。相比函數(shù),lamba 表達(dá)式具 有以下 2 個(gè)優(yōu)勢(shì):
# 匿名函數(shù)--lambda# 不帶參數(shù)的lambda函數(shù)def lam_1(): return 1 + 2# 帶參數(shù)的lambda函數(shù)def lam_2(x, y, z): return x + y + za = lambda: 1 + 2print(a()) # 3b = lambda x, y, z: x + y + zprint(b(1, 2, 3)) # 6
在Python中,一個(gè)函數(shù)可以調(diào)用其他函數(shù)。函數(shù)甚至也可以調(diào)用自身,這類函數(shù)稱為遞歸函數(shù)(Recursive Function)。如果一個(gè)函數(shù)直接或者間接地調(diào)用函數(shù)本身,那么就是遞歸函數(shù)。這意味著,函數(shù)將不斷地調(diào)用本身并重復(fù)函數(shù)的內(nèi)容,直到達(dá)到某個(gè)條件才返回一個(gè)結(jié)果。所有的遞歸函數(shù)都有著同樣的結(jié)構(gòu),這個(gè)結(jié)構(gòu)由兩部分組成:基礎(chǔ)部分,遞歸部分。
# 遞歸# 1!=1*1# 2!=1*2# 3!=1*2*3# ...# n!=1*2*3*...*n = n * (n-1)!# 階乘函數(shù)def recursive_fun(n): if n == 1: return n else: n = n * recursive_fun(n - 1) return nprint(recursive_fun(4)) # 24
# 遞歸實(shí)現(xiàn)斐波那契數(shù)列# 1,1,2,3,5,8,13,21,34,55...# f(1)=1+0 f(2)=f(1)+1 f(3)=f(2)+f(1) f(4)=f(3)+f(2)# f(n)=f(n-1)+f(n-2)def fib3(n): if not isinstance(n, int): raise ValueError('n must be an Integer !') elif n < 0: raise ValueError('n must greater than 0 !') elif 1 <= n <= 2: return 1 else: return fib3(n - 1) + fib3(n - 2) # 斐波那契數(shù)列# 1,1,2,3,5,8,13,21,34,55...def fib1(n): i, a, b = 0, 0, 1 while i < n: a, b = b, a + b print(a, end=' ') i = i + 1# 通過(guò)生成器實(shí)現(xiàn)斐波那契數(shù)列def fib2(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 print('Done')
函數(shù)式:
編程將一個(gè)問(wèn)題分解成一系列函數(shù),通過(guò)把大段代碼拆成函數(shù),通過(guò)一層一層的函數(shù)調(diào)用,就可以把復(fù)雜任務(wù)分解成簡(jiǎn)單的任務(wù),這種分解可以稱之為面向過(guò)程的程序設(shè)計(jì)。函數(shù)就是面向過(guò)程的程序設(shè)計(jì)的基本單元。 函數(shù)式編程還具有一個(gè)特點(diǎn):允許把函數(shù)本身作為參數(shù)傳入另一個(gè)函數(shù),還允許返回一個(gè)函數(shù)。
高階函數(shù):
函數(shù)對(duì)象也可以作為參數(shù)傳遞給函數(shù),還可以作為函數(shù)的返回值。參數(shù)為函數(shù)對(duì)象的函數(shù)或返回函數(shù)對(duì)象的函數(shù)稱為高階函數(shù),即函數(shù)的函數(shù)。
map() 函數(shù)的基本語(yǔ)法格式:
map(function, iterable)
其中,function 參數(shù)表示要傳入一個(gè)函數(shù),可以是內(nèi)置函數(shù)、自定義函數(shù)或者 lambda 匿名函數(shù);iterable 表示 一個(gè)或多個(gè)可迭代對(duì)象,可以是列表、字符串等。 map() 函數(shù)的功能是對(duì)可迭代對(duì)象中的每個(gè)元素,都調(diào)用指定的函數(shù),并返回一個(gè) map 對(duì)象,不是list。
# map()函數(shù)def fun_a(x): return x ** 2list1 = range(1, 10)new_list = list(map(fun_a, list1))print(new_list) # [1, 4, 9, 16, 25, 36, 49, 64, 81]
filter()函數(shù)的基本語(yǔ)法格式:
filter(function, iterable)
funcition 參數(shù)表示要傳入一個(gè)函數(shù),iterable 表示一個(gè)可迭代對(duì)象。
filter() 函數(shù)的功能是對(duì) iterable 中的每個(gè)元素,都使用 function 函數(shù)判斷,并返回 True 或者False,最后將返回 True 的元素組成一個(gè)新的可遍歷的集合。
# filter()函數(shù)def fun_b(x): return x % 2 == 1list2 = [1, 2, 3, 4, 5, 6]new_list1 = list(filter(fun_b, list2))print(new_list1) # [1, 3, 5]
reduce() 函數(shù)通常用來(lái)對(duì)一個(gè)集合做一些累積操作,基本語(yǔ)法格式為:
reduce(function, iterable)
其中,function 規(guī)定必須是一個(gè)包含 2 個(gè)參數(shù)的函數(shù);iterable 表示可迭代對(duì)象。
注意:由于 reduce() 函數(shù)在 Python 3.x 中已經(jīng)被移除,放入了 functools 模塊,因此在使用該函數(shù)之前,需先導(dǎo) 入 functools 模塊,需要引用:from functools import reduce
from functools import reduce# reduce()函數(shù)list3 = (1, 3, 5, 7, 9)new_list2 = reduce(lambda x, y: x + y, list3) # + - * / 均可計(jì)算print(new_list2) # 25
本篇主要介紹Python函數(shù)相關(guān)的知識(shí),涉及到的內(nèi)容比較多,總體來(lái)說(shuō)分為以下幾個(gè)部分:
1.函數(shù)的定義、調(diào)用,形參、實(shí)參的定義;
2.函數(shù)的傳值調(diào)用和傳址調(diào)用:
3.變量作用域:
4.獲取指定作用域范圍中的變量:
5.局部函數(shù):放在函數(shù)體內(nèi)定義的函數(shù)稱為局部函數(shù),使用nonlocal關(guān)鍵字,可以在內(nèi)部函數(shù)聲明一個(gè)和外部函數(shù)重名的變量;
6.匿名函數(shù)--lambda:函數(shù)的簡(jiǎn)寫(xiě)版本,可以省去定義函數(shù)的過(guò)程,讓代碼更加簡(jiǎn)潔;
7.遞歸:利用遞歸實(shí)現(xiàn)階乘以及斐波那契數(shù)列;
8.Python高階函數(shù):
聯(lián)系客服