- 當出現函數的時候世界的曙光出現了,重複的事情變得簡單
python提供了很多內置的函數供開發者使用,方便了管理,對於API的使用,可以使用help(命令)形同於linux下的man手冊
def Whichbig(a,b,c):
x=(max(a,b,c))
return x
投機取巧打個包裝,當然做一個比較還是很簡單的沒事試試吧
對於一個空函數
def MyNull():
pass
意味着什麼都不做,在以後的大型編程中可能是意味着在這裏留一個接口,供後續使用
import math
是一個導包的過程形同於C的 - include又有所不同,真要說像的話是和java的packge是一樣的 道理
返回多個值,當然在外面你的類型要是一樣,要可以接受這些返回值例如元組,列表。這在爬蟲中經常使用
def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
- 定義函數時,需要確定函數名和參數個數;如果有必要,可以先對參數的數據類型做檢查;函數體內部以用return隨時返回函數結果;函數執行完畢也沒有return語句時,自動return None。
- 函數可以同時返回多個值,但其實就是一個tuple關於函數的參數,有這麼幾點注意,函數可以是多個參數,從無到無窮不等,函數也可以是默認參數,要注意的是默認參數,必須是不可變參數,也就是我們說的常量,變量有太多可變性,具有不可預知性。
def add_list(L=[]):
L.append('ONE')
return L
這是有錯的,會出現不可預知的後果,因爲不能總是得到你想要看到的結果,原因就是因爲參數是不可預知的
- 對於可變參數的問題,有這麼幾種解決方法,一個是給函數中傳遞list或者tuple對象,一種是函數參數對象添加*號,例如*nums,這樣的感覺就是C中的指針但是在python中是沒有指針的
這樣就解決了可變長參數的問題
def GetNums(*nums):
print (nums[0])
GetNums(0)
- 解釋器會自動將參數合成爲一個tuple
當你使用關鍵字作爲參數時,傳遞會自動合成dict,例如
def MyFamilyMem(name,age,**Familynote):
print(name,age,Familynote)
MyFamilyMem("Bob",15,sex='boy')
- Python的函數具有非常靈活的參數形態,既可以實現簡單的調用,又可以傳入非常複雜的參數。
默認參數一定要用不可變對象,如果是可變對象,程序運行時會有邏輯錯誤!要注意定義可變參數和關鍵字參數的語法: *args是可變參數,args接收的是一個tuple;**kw是關鍵字參數,kw接收的是一個dict。 以及調用函數時如何傳入可變參數和關鍵字參數的語法: 可變參數既可以直接傳入:func(1, 2, 3),又可以先組裝list或tuple,再通過args傳入:func((1, 2, 3)); - 關鍵字參數既可以直接傳入:func(a=1, b=2),又可以先組裝dict,再通過kw傳入:func({‘a’: 1, ‘b’: 2})。 使用*args和**kw是Python的習慣寫法,當然也可以用其他參數名,但最好使用習慣用法。
命名的關鍵字參數是爲了限制調用者可以傳入的參數名,同時可以提供默認值。定義命名的關鍵字參數不要忘了寫分隔符*,否則定義的將是位置參數
對於遞歸函數
def fact(n):
if n==1:
return 1
return n*fact(n-1)
- 典型的 斐波那契函數,對於遞歸函數時通過不停的壓棧來運行的,棧的空間有限,不能無限遞歸。和調用函數相同又不相同解決棧溢出的方法是爲遞歸
- 尾遞歸就相當於將其變成循環函數,調用一次釋放一次,所以不會出現棧溢出的情況
def factextern(n):
return fact_iter(n,1)
def fact_iter(num,prodect):
if num==1:
return prodect
return fact_iter(num-1,num*prodect)
- 在返回的時候減少了調用棧的過程
- 尾遞歸調用時,如果做了優化,棧不會增長,因此,無論多少次調用也不會導致棧溢出。
- 遺憾的是,大多數編程語言沒有針對尾遞歸做優化,Python解釋器也沒有做優化,所以,即使把上面的fact(n)函數改成尾遞歸方式,也會導致棧溢出
- 使用遞歸函數的優點是邏輯簡單清晰,缺點是過深的調用會導致棧溢出。
- 針對尾遞歸優化的語言可以通過尾遞歸防止棧溢出。尾遞歸事實上和循環是等價的,沒有循環語句的編程語言只能通過尾遞歸實現循環。
- Python標準的解釋器沒有針對尾遞歸做優化,任何遞歸函數都存在棧溢出的問題
- python崇尚的極簡原則。高級特性
- 1、切片。對於一個列表中有多個元素,我們想提取其中第n到m個怎麼辦?for循環遍歷算一種,一個一個輸出,也算提取,但是這樣是否麻煩呢?
- 去一兩個元素,你說一下兩下的提取確實很方便,要是有50多,100多呢甚至更多。要是列表中有1000個呢for循環也浪費了那麼多次輪詢,當然額,可以使用條件判斷終止循環。但是明明可以一行代碼解決,浪費那麼多體力幹什麼,哈哈,這就是切片
Listone=[]
for i in range (1000):
Listone.append(i)
print (Listone)
Listone=list(range(100)) - 初始化的簡便方式
print(Listone[2:50]) - 這就是切片
Listone[:50] - 省略了開頭
Listone[20:] - 省略了結尾
print (Listone[20::2])
print (Listone[-10:])
tupleone=tuple(range(100))
print(tupleone[10:15]) - 對於列表和元鏃都可以使用切片技術
- 對於可迭代對象,形同於for循環中變量的 增長依賴上一次 的結果,在數值計算這門課上有相應的介紹與學習。有興趣可以去學習
for x,y in ((1,1),(2,4)):
print (x,y)
- 列表生成式
- 一個列表想要生成1..100的x^2,for 循環依舊可以,但是還是比較繁瑣
L=[]
for i in range(100):
L.append(i*i)
- 也可以這樣幹
[x*x for x in range (199)]
- 甚至可以在此基礎上篩選想要的結果
Listtwo=[i*i for i in range(10,50,2) if i%5==0]
print (Listtwo)
- 在此基礎上還可以套用循環,多層循環,生成表達式。但是一般不超過三層循環,這樣違背了簡單的 原則。可以將他們分開來寫。當然一行代碼能完成的事,也是很酷的
- 我們已經知道,可以直接作用於for循環的數據類型有以下幾種:
- 一類是集合數據類型,如list、tuple、dict、set、str等;
- 一類是generator,包括生成器和帶yield的generator function。
- 這些可以直接作用於for循環的對象統稱爲可迭代對象:Iterable。
- 可以使用isinstance()判斷一個對象是否是Iterable對象
- 對於生成器和迭代器,其實迭代器算是生成器 的一種高級抽像,因爲生成器的思想中也是迭代
def _odd_iter():
n = 1
while True:
n = n + 2
yield n
- 凡是可作用於for循環的對象都是Iterable類型;
- 凡是可作用於next()函數的對象都是Iterator類型,它們表示一個惰性計算的序列;
- 集合數據類型如list、dict、str等是Iterable但不是Iterator,不過可以通過iter()函數獲得一個Iterator對象。
- Python的for循環本質上就是通過不斷調用next()函數實現
- 高階函數的使用
- 高階函數 的思想是,函數也可以作爲函數的變量和參數使用
intA=max(1,2,3,4,5,6)
maxA=max
intB=maxA(1,4,5,6,7,8)
print(intA,intB)
- 結果是一樣的
def add_My(x,y,f):
return f(x^2,y)+f(y^2,x)
print (add_My(10,2,max))
- map()作爲高階函數,事實上它把運算規則抽象map()傳入的第一個參數是f,即函數對象本身。由於結果r是一個Iterator,Iterator是惰性序列,因此通過list()函數讓它把整個序列都計算出來並返回一個list
def f(x):
return x*x
r=map(f,[1,20,40,5,3,2,3,42])
list (r)
- 對於reduce
from functools import reduce
def add_reduce(x,y):
return x+y
a=reduce(add_reduce,[1,2,7,4,3,5])
print (a)
def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
def str2int(s):
return reduce(lambda x, y: x * 10 + y, map(char2num, s))
- 對於filter 就相當於map加上了篩選功能
def is_palindrom(n):
return n == int(str(n)[::-1]) - 進行一個迴文數的判斷,就是將整數轉化爲字符串,然後進行一一判斷
- 對於高階函數sorted ,內置函數作爲排序使用,還可以接受自定義鍵值來排序,用sorted()排序的關鍵在於實現一個映射函數。
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def sort_byname(t):
return t[0]
def sort_byscore(t):
return t[1]
La=sorted(L,key=sort_byname)
print (La)
Lb=sorted(L,key=sort_byscore,reverse=1)
print(Lb)
- 閉包
- 注意到返回的函數在其定義內部引用了局部變量args,所以,當一個函數返回了一個函數後,其內部的局部變量還被新函數引用,所以,閉包用起來簡單,實現起來可不容易。
- 另一個需要注意的問題是,返回的函數並沒有立刻執行,而是直到調用了f()才執行。
- 返回閉包時牢記的一點就是:返回函數不要引用任何循環變量,或者後續會發生變化的變量
def count():
def f(j):
def g():
return j*j
return g
fs=[]
for i in range(1,4):
fs.append(f(i))
return fs
- 對於匿名函數lambda 不能有return返回值,基本上都是一個表達式
def add(x,y):
return lambda : x^3+y^3
- python對lambda的支持有限,相反對於C++,js之類的語言反倒是經常使用lambda已經在C++11 規範裏面添加現在是2016年,其使用方法和範圍得到了大大的擴散
- 對於裝飾器函數u,採用了設計模式中的 裝飾模式的影響
- 其本質上裝飾器就是一個返回函數的高階函數。在動態添加功能的時候,又不能修改原有代碼,保持原有兼容性,又要添加新功能,所以就有了裝飾器,在不修改原有的基礎上添加功能
- 在面向對象(OOP)的設計模式中,decorator被稱爲裝飾模式。OOP的裝飾模式需要通過繼承和組合來實現,而Python除了能支持OOP的decorator外,直接從語法層次支持decorator。
- Python的decorator可以用函數實現,也可以用類實現。decorator可以增強函數的功能,定義起來雖然有點複雜,但使用起來非常靈活和方便
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
#對於functool中的偏函數模塊而言,其目的是爲了簡化函數
int2=functools.partial(int,base=2)
numone=int2('1001')
print(numone)
基本上函數的部分就到這裏了