python進階-- 01 函數式編程

來源:互聯網
上載者:User

標籤:bsp   參數   完成   file   預設參數   自動產生   對象   nsa   此刻   

1.概念

函數:function,是編程裡面的方法

函數式:functional,是一種編程範式

2.特點

把計算視為函數,而非指令

純函數式編程:不需要變數,沒有副作用,測試簡單

支援高階函數,代碼簡潔

3.python支援的函數式編程

不是純函數式編程:允許有變數

支援高階函數:函數可以作為變數傳入

支援閉包:有了閉包就能返回函數

有限度的支援匿名函數

4.高階函數4.1概念

能接收函數作為變數的函數,稱為高階函數

4.2原理

python中函數名其實是一個變數。

>>> abs(-10)

10

>>> abs=len

>>> abs(-10)

 

Traceback (most recent call last):

  File "<pyshell#2>", line 1, in <module>

    abs(-10)

TypeError: object of type ‘int‘ has no len()

>>> abs([1,2,3])

3

4.3舉例

>>> def add_ab(x,y,f):

         return f(x)+f(y)

 

>>> add_ab(-5,9,abs)

14

5.返回函數

>>> def f():

    print ‘call f()...‘

    # 定義函數g:

    def g():

        print ‘call g()...‘

    # 返回函數g:

    return g

 

>>> x=f()

call f()...

>>> x

<function g at 0x0000000002F05A58>

>>> x()

call g()...

6.閉包6.1概念

內層函數引用了外層函數的變數(外層函數的參數也算變數),然後返回內層函數的情況,稱為閉包(Closure)

6.2特點

返回的函數還引用了外層函數的局部變數;

另外,閉包在定義時,裡面的代碼未運行,只會在真正被調用時去運行代碼,所以運行時取的變數的值為運行時刻(非定義時刻)該變數的值!!!

所以,要正確使用閉包,就要確保引用的局部變數在函數返回後不能變。

重要:預設參數值的擷取是在定義時刻!!!

# 希望一次返回3個函數,分別計算1x1,2x2,3x3:

>>>def count():

    fs = []

    for i in range(1, 4):

        def f():

             return i*i

        fs.append(f)

    return fs

 

f1, f2, f3 = count()

>>> f1()

9

 

7.匿名函數7.1舉例

lambda x: x * x

等效於

def f(x):
    return x * x
7.2特點:

關鍵字lambda表示匿名函數,冒號前面的一個(多個)變數表示函數參數;

只能有一個運算式,不寫return,傳回值就是該運算式的結果。

使用匿名函數,可以不必定義函數名

返回函數的時候,也可以返回匿名函數

8.裝飾器decorator8.1背景

已經定義了一個函數,想在運行時動態增加函數功能,又不必去改變函數本身的代碼

8.1.1改變原始碼

>>> def f1(x):

...    print ‘call f1()‘

...    return x*2

...

>>> def f2(x):

...    print ‘call f2()‘

...    return x*x

...

>>> def f3(x):

...    print ‘call f3()‘

...    return x*x*x

8.1.2使用高階函數返回新函數

>>> def new_fn(f):

...    def fn(*args,**kw):

...             print ‘call %s()‘ % f.__name__

...             return f(*args,**kw)

...    return fn

調用方法有兩種:

 

8.1.3通過內建@自動產生新函數

 

列印日誌:@log

檢測效能:@performance

資料庫事務:@transaction

URL路由:@post(‘/register‘)

8.1.4裝飾器概念

Python的 decorator 本質上就是一個高階函數,它接收一個函數作為參數,然後,返回一個新函數。

8.2無參數裝飾器8.2.1格式

# 定義無參裝飾器

def deco_performance(f):

    # 定義裝飾器中臨時函數

    def tmp(*args,**kw):

           

        # 執行被裝飾函數,可使用有參裝飾器所帶參數

        # xxx

           

        # 返回被裝飾函數執行結果

        return result

        #return f(*args,**kw)

    # 返回裝飾器中臨時函數名

    return tmp

8.2.2舉例

# 請編寫一個@performance,它可以列印出函數調用的時間

def performance(f):

    # 要讓 @performance 自適應任何參數定義的函數,可以利用Python的

         # *args 和 **kw,保證任意個數的參數總是能正常調用

    def tmp(*args,**kw):

        print "before call--> %s" % (time.time())

        # 此刻調用被裝飾的函數

        result = f(*args,**kw)

        print "after call--> %s" % (time.time())

        # 只需要返回函數結果,不一定必須要return f(*args,**kw)

        return result

         # 只是返回函數名

    return tmp

   

# @performance使用

@performance

def factorial(n):

    return reduce(lambda x,y: x*y, range(1, n+1))

 

# 使用@performance裝飾過的函數的調用

print factorial(10)

8.3有參數裝飾器8.3.1格式

# 定義有參裝飾器

def performance(unit):

    # 定義無參裝飾器

    def deco_performance(f):

        # 定義裝飾器中臨時函數

        def tmp(*args,**kw):

           

            # 執行被裝飾函數,可使用有參裝飾器所帶參數

            # xxx

           

            # 返回被裝飾函數執行結果

            return result

        # 返回裝飾器中臨時函數名

        return tmp

    # 返回無參裝飾器名

    return deco_performance

8.3.2舉例

# 定義有參裝飾器

def performance(unit):

    # 定義無參裝飾器

    def deco_performance(f):

        # 定義裝飾器中臨時函數

        def tmp(*args,**kw):

           

            # 執行被裝飾函數,可使用有參裝飾器所帶參數

            print "before call time --> %f" % (time.time() if unit==‘s‘ else time.time()*1000)

            result=f(*args,**kw)

            print "after call time --> %f" % (time.time() if unit==‘s‘ else time.time()*1000)

            print "call %s()" % (f.__name__)

           

            # 返回被裝飾函數執行結果

            return result

        # 返回裝飾器中臨時函數名

        return tmp

    # 返回無參裝飾器名

    return deco_performance

 

# 使用有(無)參裝飾器

@performance(‘s‘)

def factorial(n):

    return reduce(lambda x,y: x*y, range(1, n+1))

 

# 調用使用有(無)參裝飾器的函數

print factorial(10)

8.4裝飾器完善8.4.1問題

經過@decorator“改造”後的函數,返回的新函數函數名已經被改變,不是‘f2‘,而是@log內部定義的‘wrapper‘。這對於那些依賴函數名的代碼就會失效。decorator還改變了函數的__doc__等其它屬性。如果要讓調用者看不出一個函數經過了@decorator的“改造”,就需要把原函數的一些屬性複製到新函數中。

8.4.2完善方法

1.手動在裝飾器的臨時函數中手動添加屬性

def log(f):

    def wrapper(*args, **kw):

        print ‘call...‘

        return f(*args, **kw)

    wrapper.__name__ = f.__name__

    wrapper.__doc__ = f.__doc__

    return wrapper

2.使用python內建的functools裝飾器自動完成複製動作

import functools

def log(f):

    @functools.wraps(f)

    def wrapper(*args, **kw):

        print ‘call...‘

        return f(*args, **kw)

    return wrapper

8.4.3無法避免的問題

最後需要指出,由於我們把原函數簽名改成了(*args, **kw),因此,無法獲得原函數的原始參數資訊。

9偏函數9.1概念

已經定義了一個函數,函數的參數個數太多,想在運行時動態減少函數必須輸入的參數,從而在調用時更簡單,實現與預設參數相同的功能,但不改變原本函數。

9.2舉例

>>> int(‘12345‘)

12345

>>> int(‘12345‘,8)

5349

>>> int2 = functools.partial(int,base=2)

>>> int2(‘1111‘)

15

9.3注意

建立偏函數時,實際上可以接收函數對象、*args和**kw這3個參數,如果傳入xx=xx類型的參數,代表傳入kw;如果傳入xx類型的參數,會作為args自動加入到參數元組中,需注意是否會影響原本函數應有結果。

>>> max(3,4,5)

5

>>> max2 = functools.partial(max,10)

>>> max2(3,4,5)

10

python進階-- 01 函數式編程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.