python closures and decorators

來源:互聯網
上載者:User

標籤:

Functions as objects and closures

python中的函數是first-class objects,即它們可以作為參數傳遞到其他函數中,可以儲存到資料結構中,也可以作為函數的傳回值

一個簡單例子

# foo.pydef callf(func):    return func()
>>> import foo>>> def hello():...     return ‘hello‘...    >>> f = foo.callf(hello) # function as an arg>>> f‘hello‘

對上面代碼做一點修改:

# foo.pyx = 42def callf(func):    return func()
>>> import foo>>> x = 37>>> def hello():...     return ‘hello. x is %d‘ % x...>>> foo.callf(hello)‘hello. x is 37‘

這裡我們調用foo.callf(),但是x的值卻不是foo.py中定義的變數值,而是調用函數前上文的值。因此我們應該關注一個函數與周邊變數的關係,也就有了closure閉包的概念

 

closure: 當一個函數的語句和它們所執行的環境一起打包的時候,就成為了所謂的closure 我們可以查看一個函數的__globals__屬性,如:

>>> hello.__globals__{‘__builtins__‘: <module ‘__builtin__‘ (built-in)>,‘helloworld‘: <function helloworld at 0x7bb30>,‘x‘: 37, ‘__name__‘: ‘__main__‘, ‘__doc__‘: None‘foo‘: <module ‘foo‘ from ‘foo.py‘>}

可以看到hello裡面已經綁定了x=37

當使用嵌套函數時,閉包會給inner function捕獲執行需要的環境,如

import foodef bar():    x = 13    def helloworld():        return "Hello World. x is %d" % x    foo.callf(helloworld) # returns ‘Hello World, x is 13‘

這裡內建函式helloworld與x=13已經組成一個閉包

閉包可以怎樣使用?我們看一個延時賦值的例子:

from urllib import urlopendef page(url):    def get():        return urlopen(url).read()    return get
>>> python = page("http://www.python.org")>>> python<function get at 0x95d5f0>>>> pydata = python() # fetch http://www.python.org>>> pydata.__closure__(<cell at 0x67f50: str object at 0x69230>,)>>> python._ _closure_ _[0].cell_contents‘http://www.python.org‘

pydata對象在賦值的時候已經綁定了參數url的值,可以留到以後進行調用

Decorators

decorator裝飾器的作用是在裡面封裝其他函數或者類,用@號來表示,eg:

@tracedef square(x):    return x*x

等同於

def square(x):    return x*xsquare = trace(square)

這個例子中定義了一個square()函數,但馬上將它作為參數傳遞到trace()中,並將返回的對象替代原來的square。裝飾器顧名思義就是給原來函數增加一些裝飾,比如我們這裡trace函數可以做一些額外的事情,最後返回的對象可以是一個包含square的函數,即對我們的square函數做了“裝飾”

再看一個平常使用的例子:

enable_tracing = Trueif enable_tracing:    debug_log = open("debug.log","w")def trace(func):    if enable_tracing:        def callf(*args,**kwargs):            debug_log.write("Calling %s: %s, %s\n" % (func._ _name_ _, args, kwargs))            r = func(*args,**kwargs)            debug_log.write("%s returned %s\n" % (func._ _name, r))            return r        return callf    else:        return func

這個代碼就可以追蹤上面square函數的調用,如果enable_tracing,則用函數callf將func封裝起來,在裡面增加記錄日誌功能,並且callf最後還是返回func函數,也就是說如果允許追蹤的時候我們就將原來的函數對象裝飾成一個有追蹤功能的callf函數對象返回,如果不允許追蹤,就簡單返回func本身,這是非常精妙的一種設計

python closures and decorators

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.