回顧上一節,咱們已經將python的基礎知識瞭解掌握,如今能夠開始進一步的學習了。函數,不管在Java、C仍是其餘語言,都不可避免,這也從側面反映了函數的重要性。因此,也就產生了函數式編程這一律念,到底什麼是函數式編程?下面讓咱們一步一步來揭開它:html
提及函數,相信你們必定不會陌生,其實從很早就已經接觸了,像數學課堂上計算數列的和:1+2+3+4+5+...+10,函數就是最基本的一種代碼抽象的方式,以便更加快速的計算和處理。python
python內置了不少函數,肯定參數就能夠直接調用,方便使用,能夠直接從Python的官方網站查看文檔:http://docs.python.org/3/library/functions.html。在Python中,定義一個函數要使用def語句,依次寫出函數名、括號、括號中的參數和冒號,而後,在縮進塊中編寫函數體,函數的返回值用return語句返回,加入參數檢查,可以完善函數定義,數據類型檢查能夠用內置函數isinstance()實現。定義函數時,注意函數書寫的格式,避免出錯,儘快熟悉這種書寫風格:編程
# 定義求整數和浮點數類型的絕對值的函數 # 加入了參數檢查,傳入錯誤參數時會拋出對應錯誤 def my_abs(x): if not isinstance(x, (int, float)): raise TypeError('bad operand type') if x >= 0: return x else: return -x
定義函數的時候,咱們把參數的名字和位置肯定下來,函數的接口定義就完成了。對於函數的調用者來講,只須要知道如何傳遞正確的參數,以及函數將返回什麼樣的值就夠了,函數內部的複雜邏輯被封裝起來,調用者無需瞭解。Python的函數定義很是簡單,但靈活度卻很是大。除了正常定義的必選參數外,還可使用默認參數、可變參數和關鍵字參數,使得函數定義出來的接口,不但能處理複雜的參數,還能夠簡化調用者的代碼。設計模式
# 初始函數-計算x2的值 def power(x): return x * x # 位置參數-計算x3,x4,x5...的值(初始函數不可用) def power(x, n): s = 1 while n > 0: n = n - 1 s = s * x return s # 默認參數-計算x3,x4,x5...的值(初始函數可用) def power(x, n=2): s = 1 while n > 0: n = n - 1 s = s * x return s
定義默認參數要牢記一點:默認參數必須指向不變對象。在Python函數中,還能夠定義可變參數,顧名思義,可變參數就是傳入的參數個數是可變的。在參數前加上*號,即把list或tuple的元素變成可變參數傳進去:數組
# 給定一組數字a,b,c...,請計算a2 + b2 + c2 +... def calc_old(numbers): sum = 0 for n in numbers: sum = sum + n * n return sum def calc_new(*numbers): sum = 0 for n in numbers: sum = sum + n * n return sum nums = [1, 2, 3] calc_old(nums[0],nums[1],nums[2]) calc_old([1,2,3]) calc_new(*nums)
下面說下可變參數和關鍵字參數的區別:可變參數容許你傳入0個或任意個參數,這些可變參數在函數調用時自動組裝爲一個tuple;關鍵字參數容許你傳入0個或任意個含參數名的參數,這些關鍵字參數在函數內部自動組裝爲一個dict,它的做用就是擴展函數,換種說法,就是在接收必須的參數外,能夠接收其餘的非必須的參數,固然,既然是非必須的,那就能夠不填,如關鍵字參數kw(習慣性寫法,也能夠用其餘參數名),注意書寫格式:閉包
# 關鍵字參數 def person(name, age, **kw): print('name:', name, 'age:', age, 'other:', kw) >>> person('Ada',30) >>> name:Ada age:30 other:{} >>> person('Bob',25,sex='M', job='Engineer') >>> name:Bob age:25 kw:{'sex':'M','job':'Engineer'} >>> extra = {'city': 'Beijing', 'job': 'Engineer'} >>> person('Jack', 24, **extra) >>> name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
而命名關鍵字參數就是爲了限制關鍵字參數的名字,書寫格式爲特殊分隔符 *,*號後面的參數被視爲命名關鍵字參數:app
# 只接收city和job做爲關鍵字參數 def person(name, age, *, city, job): print(name, age, city, job) >>> person('Jack', 24, city='Beijing', job='Engineer') >>> Jack 24 Beijing Engineer
在Python函數定義時,各類參數均可以組合使用,注意,參數定義的順序必須是:必選參數、默認參數、可變參數、命名關鍵字參數和關鍵字參數。如非必要,不要使用過多的參數組合,這大大下降了參數接口的理解性。函數式編程
函數式編程就是一種抽象程度很高的編程範式,函數式編程的一個特色就是,容許把函數自己做爲參數傳入另外一個函數,還容許返回一個函數!下面來經過幾個高階函數(把函數做爲參數傳入)來理解函數式編程,以及函數式編程中常見的名詞。函數
# Python內建的函數map() # map()函數接收兩個參數,一個是函數,一個是Iterable # map將傳入的函數依次做用到序列的每一個元素,並把結果做爲新的Iterator返回 def f(x): return x*x >>> r = map(f,[1,2,3,4,5,6,7,8,9]) >>> list(r) >>> [1,4,9,16,25,36,49,64,81]
其餘高階函數的好比:reduce()、filter()、sorted(),再也不一一舉例了,自行查看。學習
返回函數,一個函數能夠返回一個計算結果,也能夠返回一個函數,注意:返回一個函數時,牢記該函數並未執行,返回函數中不要引用任何可能會變化的變量。
# 函數做爲返回值 # 閉包 def lazy_sum(*args): def sum(): ax = 0 for n in args: ax = ax + n return ax return sum >>> f = lazy_sum(1, 3, 5, 7, 9) >>> f >>> <function lazy_sum.<locals>.sum at 0x101c6ed90> >>> f() >>> 25
匿名函數,在傳入函數時,有些時候,不須要顯式地定義函數,直接傳入匿名函數更方便,python對匿名函數支持有限,好處是沒必要擔憂函數名衝突,如:lambda x : x*x,即關鍵字lambda表示匿名函數,冒號前面的x表示函數參數,不用寫return,返回值就是表達式的結果:
# 匿名函數 # 關鍵字lambda >>> f = lambda x: x*x >>> f(5) >>> 25 # 匿名函數做爲返回值 def fa(x,y): return lambda: x*x+y*y
裝飾器,在面向對象(OOP)的設計模式中,decorator被稱爲裝飾模式。OOP的裝飾模式須要經過繼承和組合來實現,而Python除了能支持OOP的decorator外,直接從語法層次支持decorator。Python的decorator能夠用函數實現,也能夠用類實現。decorator能夠加強函數的功能,定義起來雖然有點複雜,但使用起來很是靈活和方便:
# 裝飾器decorator:在代碼運行期間動態增長功能的方式 # decorator就是一個返回函數的高階函數 def log(func): def wrapper(*args, **kw): print('call %s():' % func.__name__) return func(*args, **kw) return wrapper @log def now(): print('2018-01-22') >>> now() call now(): 2018-01-22
解釋下實現過程:因爲log()是一個decorator,返回一個函數,因此,原來的now()函數仍然存在,只是如今同名的now變量指向了新的函數,因而調用now()將執行新函數,即在log()函數中返回的wrapper()函數。wrapper()函數的參數定義是(*args,**kw),所以,wrapper()函數能夠接受任意參數的調用。在wrapper()函數內,首先打印日誌,再緊接着調用原始函數。
偏函數,當函數的參數個數太多,須要簡化時,使用functools.partial能夠建立一個新的函數,這個新函數能夠固定住原函數的部分參數,從而在調用時更簡單:
# 偏函數 # functools.partial就是幫助咱們建立一個偏函數的,不須要咱們本身定義int2() # int()函數把字符串轉換爲整數 import functools int2 = functools.partial(int, base=2) >>> int2('1000000') >>> 64 >>> int2('1000000', base=10) >>> 1000000
以上介紹的就是一些函數式編程中須要掌握的,很少,但須要反覆練習和理解,固然理解是第一前提,懵懂狀態下,練習再多也是徒勞。