函數
- 調用函數
要調用一個函數,需要知道函數的名稱和參數,比如求絕對值的函數abs,只有一個參數
>>> abs(100)
100
>>> abs(-20)
20
>>> abs(12.34)
12.34
如果對要調用的函數有不清楚的地方,可以通過help(abs)查看函數的幫助信息
返回值: 函數可以返回tuple,如x, y = move(100, 100, 60, math.pi / 6)
,就像返回一次返回多個值一樣。
- 創建函數
2.1 默認參數
python支持默認參數,格式如
def power(x, n=2):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
默認參數確實帶來了很多方便,不過也有些細節要注意:
一、必選參數在前,默認參數在后,否則Python的解釋器會報錯
二、如何設置默認參數。
三、當函數有多個參數時,把變化大的參數放前面,變化小的參數放后面。變化小的參數就可以作為默認參數。
還有一點:
Python函數在定義的時候,默認參數L的值就被計算出來了,即[],因為默認參數L也是一個變量,它指向對象[],每次調用該函數,如果改變了L的內容,則下次調用時,默認參數的內容就變了,不再是函數定義時的[]了。
所以,定義默認參數要牢記一點:默認參數必須指向不變對象!
2.2 可變參數
在Python函數中,還可以定義可變參數,格式如下
def sum(*nums):
s=0
for n in nums:
s=s+n
return s
如果要直接傳入list或tuple,可以這樣:
nums = [1, 2, 3]
sum(*nums)
2.3關鍵字參數
可變參數允許你傳入0個或任意個參數,這些可變參數在函數調用時自動組裝為一個tuple。而關鍵字參數允許你傳入0個或任意個含參數名的參數,這些關鍵字參數在函數內部自動組裝為一個dict。請看示例:
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
和可變參數類似,也可以先組裝出一個dict,然后,把該dict轉換為關鍵字參數傳進去:
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, city=extra['city'], job=extra['job'])
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
上面復雜的調用可以用簡化的寫法:
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
如果要限制關鍵字參數的名字,就可以用命名關鍵字參數,例如,只接收city和job作為關鍵字參數。這種方式定義的函數如下:
def person(name, age, *args, city, job):
print(name, age, args, city, job)
如果函數定義中已經有了一個可變參數,后面跟著的命名關鍵字參數就不再需要一個特殊分隔符*了:
def person(name, age, *args, city, job):
print(name, age, args, city, job)
2.4參數組合
在Python中定義函數,可以用必選參數、默認參數、可變參數、關鍵字參數和命名關鍵字參數,這5種參數都可以組合使用。但是請注意,參數定義的順序必須是:必選參數、默認參數、可變參數、命名關鍵字參數和關鍵字參數。
如
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)
對于任意函數,都可以通過類似func(*args, **kw)的形式調用它,無論它的參數是如何定義的。
高級特性
- 切片
對于經常取指定索引范圍的操作,用循環十分繁瑣,因此,Python提供了切片(Slice)操作符,能大大簡化這種操作。
如下:
>>> L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
>>> L[0:3]
['Michael', 'Sarah', 'Tracy']
其實就是獲取左閉右開的子集,如果第一個索引是0,還可以省略,另外python還支持倒序切片,如:
>>> L[-2:]
['Bob', 'Jack']
>>> L[-2:-1]
['Bob']
記住倒數第一個元素的索引是-1.如果是L[0:4:2]
就是從第0個到第四個,每兩個數取一個的意思
字符串'xxx'也可以看成是一種list,每個元素就是一個字符。因此,字符串也可以用切片操作,只是操作結果仍是字符串,如下所示:
>>> 'ABCDEFG'[:3]
'ABC'
>>> 'ABCDEFG'[::2]
'ACEG'
- 迭代
如果給定一個list或tuple,我們可以通過for循環來遍歷這個list或tuple,這種遍歷我們稱為迭代(Iteration)。python的迭代其實和Java的for each 循環比較類似,不過其抽象程度高于Java的迭代,像list這種數據類型雖然有下標,但很多其他數據類型是沒有下標的,但是,只要是可迭代對象,無論有無下標,都可以迭代,比如dict就可以迭代:
>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> for key in d:
... print(key)
...
a
c
b
因為dict的存儲不是按照list的方式順序排列,所以,迭代出的結果順序很可能不一樣。
默認情況下,dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同時迭代key和value,可以用for k, v in d.items()。
當我們使用for循環時,只要作用于一個可迭代對象,for循環就可以正常運行,而我們不太關心該對象究竟是list還是其他數據類型。
那么,如何判斷一個對象是可迭代對象呢?方法是通過collections模塊的Iterable類型判斷,如下:
>>>isinstance('abc', Iterable)
True
- 列表生成式
列表生成式即List Comprehensions,是Python內置的非常簡單卻強大的可以用來創建list的生成式。舉個例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
可以用list(range(1, 11))
但如果要生成[1x1, 2x2, 3x3, ..., 10x10]
怎么做?方法一是循環:
>>> L = []
>>> for x in range(1, 11):
... L.append(x * x)
...
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
但是循環太繁瑣,而列表生成式則可以用一行語句代替循環生成上面的list:
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
for循環后面還可以加上if判斷,這樣我們就可以篩選出僅偶數的平方:
>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]
用列表生成式可以寫出很簡潔的代碼,不過個人感覺可讀性略差,可能習慣了就好
- 生成器
簡單的說生成器是一個函數,它記住上一次返回時在函數體中的位置。對生成器函數的第二次(或第 n 次)調用跳轉至該函數中間,而上次調用的所有局部變量都保持不變。
生成器不僅“記住”了它數據狀態;生成器還“記住”了它在流控制構造(在命令式編程中,這種構造不只是數據值)中的位置。
生成器的特點:
生成器是一個函數,而且函數的參數都會保留。
迭代到下一次的調用時,所使用的參數都是第一次所保留下的,即是說,在整個所有函數調用的參數都是第一次所調用時保留的,而不是新創建的。如下:
>>>g=(x*x for x in range(1,11))
>>>print(next(g))
1
>>>print(next(g))
4
>>>print(next(g))
9
>>>print(next(g))
16
>>>print(next(g))
25
如上所示,next()用起來不是很方便,所以我們創建了一個generator后,基本上永遠不會調用next(),而是通過for循環來迭代它,并且不需要關心StopIteration的錯誤。
generator非常強大。如果推算的算法比較復雜,用類似列表生成式的for循環無法實現的時候,還可以用函數來實現。