在本文中,您將瞭解什麼是函數範型,以及如何在Python中使用函數式編程。python
在Python中,函數式編程中的map和filter能夠作與列表相同的事情。這打破了Python的禪宗規則之一,所以函數式編程的這些部分不被認爲是「Python式的」。程序員
可是因爲函數式編程高階編程的必經之路,因此咱們須要瞭解甚至熟練掌握。編程
咱們先對比一下編程中的命令範式兩個概念:數組
在命令式範式中,您經過給計算機一個任務序列來完成任務,而後它執行這些任務。在執行它們時,它能夠改變狀態。網絡
例如,假設你一開始把A設爲5,而後你改變A的值,你有變量,在這個意義上,變量內部的值是變化的。閉包
在函數範型中,你不告訴計算機要作什麼,而是告訴它是什麼。例如:一個數的最大公約數是多少,從1到n的乘積是多少,等等。app
所以,變量不能改變。一旦你設置了一個變量,它就會一直保持這種狀態(注意,在純函數語言中它們不被稱爲變量)。框架
所謂"反作用"(side effect),指的是函數內部與外部互動(最典型的狀況,就是修改全局變量的值),產生運算之外的其餘結果。less
函數式編程強調沒有"反作用",意味着函數要保持獨立,全部功能就是返回一個新的值,沒有其餘行爲,尤爲是不得修改外部變量的值。機器學習
讓咱們來看一個典型Python代碼的例子:
a = 3 def some_func(): global a a = 5 some_func() print(a)
這段代碼的輸出是5。在函數範型中,改變變量是一個大禁忌,而讓函數影響它們範圍以外的東西也是一個大禁忌。函數惟一能作的就是計算並返回結果。
如今你可能會想:「沒有變量,就沒有反作用?」這有什麼好處呢?
若是一個函數使用相同的參數被調用兩次,那麼它確定會返回相同的結果。由於函數沒有反作用,若是你正在構建一個計算的程序,你能夠加速這個程序。
若是程序知道func(2)等於3,咱們能夠將其存儲在一個表中。這能夠防止程序在咱們已經知道答案的狀況下重複運行相同的函數。
爲了理解map,讓咱們首先看看什麼是iterables。
iterable是任何能夠迭代的東西。一般這些是列表或數組,可是Python有許多不一樣類型的迭代器。您甚至能夠建立本身的對象,這些對象可使用Python中魔法方法進行迭代。
這裏有兩個方法:
class Counter: def __init__(self, low, high): # set class attributes inside the magic method __init__ # for "inistalise" self.current = low self.high = high def __iter__(self): # first magic method to make this object iterable return self def __next__(self): # second magic method if self.current > self.high: raise StopIteration else: self.current += 1 return self.current - 1
「魔法方法是python內置方法,不須要主動調用,存在的目的是爲了給python的解釋器進行調用,幾乎每一個魔法方法都有一個對應的內置函數,或者運算符,當咱們對這個對象使用這些函數或者運算符時就會調用類中的對應魔法方法,能夠理解爲重寫內置函數。」
第一個神奇的方法是用「__ iter__」返回迭代對象,一般在循環開始時使用。
若是咱們運行:
for c in Counter(3, 8): print(c)
那麼將會輸出:
345678
在Python中,迭代器是一個對象,它只有一個簡單的魔法方法。這意味着您能夠訪問對象中的位置,但不能遍歷對象。有些對象將使用方法__next__,如上面代碼中第二個例子。
如今咱們知道了什麼是可迭代對象,讓咱們回到map函數。map函數容許咱們將一個函數應用到iterable中的每一個項。一般,咱們但願對列表中的每一項都應用一個函數,可是要知道對於大多數迭代器來講都是可能的。
Map接受兩個輸入,即要應用的函數和可迭代的對象:
map(function, iterable)
假設咱們有一個列表:
[1, 2, 3, 4, 5]
咱們但願將列表中的每個數字進行平方,那麼能夠這麼寫代碼:
x = [1, 2, 3, 4, 5] def square(num): return num*num print(list(map(square, x)))
Python中的函數是惰性的。若是咱們代碼中不包含「list()」,函數將存儲迭代的定義,而不是一個列表。咱們須要顯式地告訴Python「將這個轉換爲一個列表」,以便咱們使用它。
如今寫一個像「square(num)」這樣的普通函數很好,可是它看起來不太對。咱們必須定義一個完整的函數才能在map中使用一次?咱們可使用lambda(匿名)函數在map中定義一個函數。
lambda表達式是一個單行函數。舉個例子,這個lambda表達式對給定的一個數字求平方:
square = lambda x: x * x
運行程序:
>>> square(3) 9
告訴Python這是一個lambda函數,輸入被稱爲x,冒號後面的內容就是你對輸入的操做,它會自動返回結果。
如今咱們能夠將上面的程序簡化:
x = [1, 2, 3, 4, 5] print(list(map(lambda num: num * num, x)))
Reduce是一個函數,它把一個可迭代的東西變成一個東西。一般,您在一個列表上執行計算以將其縮減爲一個數字。
Reduce是這樣的:
reduce(function, list)
咱們能夠(一般也會)使用lambda表達式做爲函數。
列表的乘積是每個單獨的數字相乘。要作到這一點,你能夠:
product = 1x = [1, 2, 3, 4]for num in x: product = product * num
可是使用reduce你能夠這樣寫:
from functools import reduce product = reduce((lambda x, y: x * y),[1, 2, 3, 4])
filter函數接受一個iterable並過濾掉在該iterable中不須要的全部東西。
filter一般接受一個函數和一個列表。它將函數應用於列表中的每一項,若是該函數返回True,則不執行任何操做。若是返回False,則從列表中刪除該項目。
語法以下:
filter(function, list)
讓咱們看看一個小例子,沒有過濾器,咱們會寫:
x = range(-5, 5) new_list = [] for num in x: if num < 0: new_list.append(num)
有了過濾器,這就變成:
x = range(-5, 5) all_less_than_zero = list(filter(lambda num: num < 0, x))
高階函數能夠將函數做爲參數並返回函數。一個很是簡單的例子以下:
def summation(nums): return sum(nums) def action(func, numbers): return func(numbers) print(action(summation, [1, 2, 3])) partial application
部分應用程序(也稱爲閉包)有點奇怪,可是很是酷。您能夠調用一個函數而不提供它須要的全部參數。咱們來看一個例子。
咱們想要建立一個函數,它有兩個參數,一個底數和一個指數,並返回底數的指數次方,就像這樣:
def power(base, exponent): return base ** exponent
如今咱們想要一個專門的平方函數,用冪函數求出一個數的平方:
def square(base): return power(base, 2)
這是可行的,但若是咱們想要一個立方體函數呢?或者是函數的4次方?咱們能一直寫下去嗎?嗯,你能夠。可是程序員很懶。
若是你一遍又一遍地重複一樣的事情,這是一個信號,代表有一種更快的方法能夠加快速度,讓你再也不重複。咱們能夠在這裏使用部分應用程序。
讓咱們看一個例子的平方函數使用部分應用程序:
from functools import partialsquare = partial(power, exponent=2)print(square(2))
這是否是很酷?咱們能夠調用須要兩個參數的函數,只需使用一個參數就能夠告訴Python第二個參數是什麼。
原文連接:
https://medium.com/hackernoon...
文源網絡,僅供學習之用,侵刪。在學習Python的道路上確定會碰見困難,別慌,我這裏有一套學習資料,包含40+本電子書,800+個教學視頻,涉及Python基礎、爬蟲、框架、數據分析、機器學習等,不怕你學不會!
https://shimo.im/docs/JWCghr8... 《Python學習資料》關注公衆號【Python圈子】,優質文章每日送達。