Python 學習總結(二):理解函數式編程,豐富開發

        回顧上一節,咱們已經將python的基礎知識瞭解掌握,如今能夠開始進一步的學習了。函數,不管在Java、C仍是其餘語言,都不可避免,這也從側面反映了函數的重要性。因此,也就產生了函數式編程這一律念,到底什麼是函數式編程?下面讓咱們一步一步來揭開它:html

     (1)函數是什麼?

        提及函數,相信你們必定不會陌生,其實從很早就已經接觸了,像數學課堂上計算數列的和:1+2+3+4+5+...+10,函數就是最基本的一種代碼抽象的方式,以便更加快速的計算和處理。python

     (2)調用函數和定義函數

        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

     (3)函數的參數

        定義函數的時候,咱們把參數的名字和位置肯定下來,函數的接口定義就完成了。對於函數的調用者來講,只須要知道如何傳遞正確的參數,以及函數將返回什麼樣的值就夠了,函數內部的複雜邏輯被封裝起來,調用者無需瞭解。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函數定義時,各類參數均可以組合使用,注意,參數定義的順序必須是:必選參數、默認參數、可變參數、命名關鍵字參數和關鍵字參數。如非必要,不要使用過多的參數組合,這大大下降了參數接口的理解性。函數式編程

     (4)函數式編程

        函數式編程就是一種抽象程度很高的編程範式,函數式編程的一個特色就是,容許把函數自己做爲參數傳入另外一個函數,還容許返回一個函數!下面來經過幾個高階函數(把函數做爲參數傳入)來理解函數式編程,以及函數式編程中常見的名詞。函數

# 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

        以上介紹的就是一些函數式編程中須要掌握的,很少,但須要反覆練習和理解,固然理解是第一前提,懵懂狀態下,練習再多也是徒勞。

相關文章
相關標籤/搜索