Python有很多使用的自帶函數(shù):
>>> abs(-20)
20
>>> max(2, 3, 1, -5)
3
>>> int('123')
123
>>> int(12.34)
12
>>> float('12.34')
12.34
>>> str(1.23)
'1.23'
>>> str(100)
'100'
>>> bool(1)
True
>>> bool('')
False
>>> a = abs # 變量a指向abs函數(shù)
>>> a(-1) # 所以也可以通過a調(diào)用abs函數(shù)
1
自定義函數(shù)
在Python中,定義一個(gè)函數(shù)要使用def語(yǔ)句,依次寫出函數(shù)名、括號(hào)、括號(hào)中的參數(shù)和冒號(hào):,然后,在縮進(jìn)塊中編寫函數(shù)體,函數(shù)的返回值用return語(yǔ)句返回。
def my_abs(x):
if x >= 0:
return x
else:
return -x
如果你已經(jīng)把my_abs()的函數(shù)定義保存為abstest.py文件了,那么,可以在該文件的當(dāng)前目錄下啟動(dòng)Python解釋器,用from abstest import my_abs來導(dǎo)入my_abs()函數(shù),注意abstest是文件名(不含.py擴(kuò)展名):
>>> from abstest import my_abs
>>> my_abs(-9)
9
pass
pass
可以用來作為占位符,比如現(xiàn)在還沒想好怎么寫函數(shù)的代碼,就可以先放一個(gè)pass,讓代碼能運(yùn)行起來。
def nop():
pass
isinstance
數(shù)據(jù)類型檢查可以用內(nèi)置函數(shù)isinstance()實(shí)現(xiàn):
def my_abs(x):
if not isinstance(x, (int, float)):
raise TypeError('bad operand type')
if x >= 0:
return x
else:
return -x
返回多值
Python的函數(shù)返回多值其實(shí)就是返回一個(gè)tuple。
def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
>>> x, y = move(100, 100, 60, math.pi / 6)
>>> print(x, y)
151.96152422706632 70.0
>>> r = move(100, 100, 60, math.pi / 6)
>>> print(r)
(151.96152422706632, 70.0)
函數(shù)參數(shù)
定義函數(shù)的時(shí)候,我們把參數(shù)的名字和位置確定下來,函數(shù)的接口定義就完成了。對(duì)于函數(shù)的調(diào)用者來說,只需要知道如何傳遞正確的參數(shù),以及函數(shù)將返回什么樣的值就夠了,函數(shù)內(nèi)部的復(fù)雜邏輯被封裝起來,調(diào)用者無需了解。
除了正常定義的必選參數(shù)外,還可以使用默認(rèn)參數(shù)、可變參數(shù)和關(guān)鍵字參數(shù),使得函數(shù)定義出來的接口,不但能處理復(fù)雜的參數(shù),還可以簡(jiǎn)化調(diào)用者的代碼。
默認(rèn)參數(shù)
由于我們經(jīng)常計(jì)算x2,所以,完全可以把第二個(gè)參數(shù)n的默認(rèn)值設(shè)定為2:
def power(x, n=2):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
這樣,當(dāng)我們調(diào)用power(5)時(shí),相當(dāng)于調(diào)用power(5, 2):
>>> power(5)
25
>>> power(5, 2)
25
而對(duì)于n > 2
的其他情況,就必須明確地傳入n,比如power(5, 3)
。 當(dāng)函數(shù)有多個(gè)參數(shù)時(shí),把變化大的參數(shù)放前面,變化小的參數(shù)放后面。變化小的參數(shù)就可以作為默認(rèn)參數(shù)。使用默認(rèn)參數(shù)最大的好處是能降低調(diào)用函數(shù)的難度。
默認(rèn)參數(shù)必須指向不變對(duì)象! 我們?cè)诰帉懗绦驎r(shí),如果可以設(shè)計(jì)一個(gè)不變對(duì)象,那就盡量設(shè)計(jì)成不變對(duì)象。
可變參數(shù)
def calc(numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
這個(gè)函數(shù)調(diào)用的時(shí)候,需要先組裝出一個(gè)list或tuple:
>>> calc([1, 2, 3])
14
>>> calc((1, 3, 5, 7))
84
如果利用可變參數(shù),調(diào)用函數(shù)的方式可以簡(jiǎn)化成這樣:
>>> calc(1, 2, 3)
14
>>> calc(1, 3, 5, 7)
84
我們把函數(shù)的參數(shù)改為可變參數(shù):(僅僅是在變量的前面加個(gè)*
)
def calc(*numbers):
sum = 0
for nin numbers:
sum = sum + n * n
return sum
在函數(shù)內(nèi)部,參數(shù)numbers接收到的是一個(gè)tuple,因此,函數(shù)代碼完全不變。但是,調(diào)用該函數(shù)時(shí),可以傳入任意個(gè)參數(shù),包括0個(gè)參數(shù)。
關(guān)鍵字參數(shù)
可變參數(shù)允許你傳入0個(gè)或任意個(gè)參數(shù),這些可變參數(shù)在函數(shù)調(diào)用時(shí)自動(dòng)組裝為一個(gè)tuple。而關(guān)鍵字參數(shù)允許你傳入0個(gè)或任意個(gè)含參數(shù)名的參數(shù),這些關(guān)鍵字參數(shù)在函數(shù)內(nèi)部自動(dòng)組裝為一個(gè)dict。
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
函數(shù)person除了必選參數(shù)name和age外,還接受關(guān)鍵字參數(shù)kw。在調(diào)用該函數(shù)時(shí),可以只傳入必選參數(shù):
>>> person('Michael', 30)
name: Michael age: 30 other: {}
也可以傳入任意個(gè)數(shù)的關(guān)鍵字參數(shù):
>>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
參數(shù)定義的順序必須是:必選參數(shù)、默認(rèn)參數(shù)、可變參數(shù)、命名關(guān)鍵字參數(shù)和關(guān)鍵字參數(shù)。在函數(shù)調(diào)用的時(shí)候,Python解釋器自動(dòng)按照參數(shù)位置和參數(shù)名把對(duì)應(yīng)的參數(shù)傳進(jìn)去。
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
通過一個(gè)tuple和dict,你也可以調(diào)用上述函數(shù):
>>> args = (1, 2, 3, 4)
>>> kw = {'d': 99, 'x': '#'}
>>> f1(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
>>> args = (1, 2, 3)
>>> kw = {'d': 88, 'x': '#'}
>>> f2(*args, **kw)
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}
所以,對(duì)于任意函數(shù),都可以通過類似func(*args, **kw)
的形式調(diào)用它,無論它的參數(shù)是如何定義的。
遞歸函數(shù)
在函數(shù)內(nèi)部,可以調(diào)用其他函數(shù)。如果一個(gè)函數(shù)在內(nèi)部調(diào)用自身本身,這個(gè)函數(shù)就是遞歸函數(shù)。遞歸函數(shù)的優(yōu)點(diǎn)是定義簡(jiǎn)單,邏輯清晰。
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
使用遞歸函數(shù)需要注意防止棧溢出。在計(jì)算機(jī)中,函數(shù)調(diào)用是通過**棧(stack)**這種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,每當(dāng)進(jìn)入一個(gè)函數(shù)調(diào)用,棧就會(huì)加一層棧幀,每當(dāng)函數(shù)返回,棧就會(huì)減一層棧幀。由于棧的大小不是無限的,所以,遞歸調(diào)用的次數(shù)過多,會(huì)導(dǎo)致棧溢出。
Python標(biāo)準(zhǔn)的解釋器沒有針對(duì)尾遞歸做優(yōu)化,任何遞歸函數(shù)都存在棧溢出的問題。
附上其他文章的鏈接:
本文內(nèi)容屬于筆記,大部分內(nèi)容源自 廖雪峰老師的博客, 非常推薦大家去他的網(wǎng)站學(xué)習(xí)!