Python有很多使用的自帶函數:
>>> 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函數
>>> a(-1) # 所以也可以通過a調用abs函數
1
自定義函數
在Python中,定義一個函數要使用def語句,依次寫出函數名、括號、括號中的參數和冒號:,然后,在縮進塊中編寫函數體,函數的返回值用return語句返回。
def my_abs(x):
if x >= 0:
return x
else:
return -x
如果你已經把my_abs()的函數定義保存為abstest.py文件了,那么,可以在該文件的當前目錄下啟動Python解釋器,用from abstest import my_abs來導入my_abs()函數,注意abstest是文件名(不含.py擴展名):
>>> from abstest import my_abs
>>> my_abs(-9)
9
pass
pass
可以用來作為占位符,比如現(xiàn)在還沒想好怎么寫函數的代碼,就可以先放一個pass,讓代碼能運行起來。
def nop():
pass
isinstance
數據類型檢查可以用內置函數isinstance()實現(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的函數返回多值其實就是返回一個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)
函數參數
定義函數的時候,我們把參數的名字和位置確定下來,函數的接口定義就完成了。對于函數的調用者來說,只需要知道如何傳遞正確的參數,以及函數將返回什么樣的值就夠了,函數內部的復雜邏輯被封裝起來,調用者無需了解。
除了正常定義的必選參數外,還可以使用默認參數、可變參數和關鍵字參數,使得函數定義出來的接口,不但能處理復雜的參數,還可以簡化調用者的代碼。
默認參數
由于我們經常計算x2,所以,完全可以把第二個參數n的默認值設定為2:
def power(x, n=2):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
這樣,當我們調用power(5)時,相當于調用power(5, 2):
>>> power(5)
25
>>> power(5, 2)
25
而對于n > 2
的其他情況,就必須明確地傳入n,比如power(5, 3)
。 當函數有多個參數時,把變化大的參數放前面,變化小的參數放后面。變化小的參數就可以作為默認參數。使用默認參數最大的好處是能降低調用函數的難度。
默認參數必須指向不變對象! 我們在編寫程序時,如果可以設計一個不變對象,那就盡量設計成不變對象。
可變參數
def calc(numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
這個函數調用的時候,需要先組裝出一個list或tuple:
>>> calc([1, 2, 3])
14
>>> calc((1, 3, 5, 7))
84
如果利用可變參數,調用函數的方式可以簡化成這樣:
>>> calc(1, 2, 3)
14
>>> calc(1, 3, 5, 7)
84
我們把函數的參數改為可變參數:(僅僅是在變量的前面加個*
)
def calc(*numbers):
sum = 0
for nin numbers:
sum = sum + n * n
return sum
在函數內部,參數numbers接收到的是一個tuple,因此,函數代碼完全不變。但是,調用該函數時,可以傳入任意個參數,包括0個參數。
關鍵字參數
可變參數允許你傳入0個或任意個參數,這些可變參數在函數調用時自動組裝為一個tuple。而關鍵字參數允許你傳入0個或任意個含參數名的參數,這些關鍵字參數在函數內部自動組裝為一個dict。
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
函數person除了必選參數name和age外,還接受關鍵字參數kw。在調用該函數時,可以只傳入必選參數:
>>> person('Michael', 30)
name: Michael age: 30 other: {}
也可以傳入任意個數的關鍵字參數:
>>> 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'}
參數定義的順序必須是:必選參數、默認參數、可變參數、命名關鍵字參數和關鍵字參數。在函數調用的時候,Python解釋器自動按照參數位置和參數名把對應的參數傳進去。
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}
通過一個tuple和dict,你也可以調用上述函數:
>>> 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': '#'}
所以,對于任意函數,都可以通過類似func(*args, **kw)
的形式調用它,無論它的參數是如何定義的。
遞歸函數
在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數。遞歸函數的優(yōu)點是定義簡單,邏輯清晰。
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
使用遞歸函數需要注意防止棧溢出。在計算機中,函數調用是通過**棧(stack)**這種數據結構實現(xiàn)的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由于棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出。
Python標準的解釋器沒有針對尾遞歸做優(yōu)化,任何遞歸函數都存在棧溢出的問題。
附上其他文章的鏈接:
本文內容屬于筆記,大部分內容源自 廖雪峰老師的博客, 非常推薦大家去他的網站學習!