職業:python裝飾器

http://blog.csdn.net/ablo_zhou/article/details/5471952

Python 2.4以后,增加了@符號修飾函數對函數進行修飾,python3.0/2.6又增加了對類的修飾。

我現在使用的python版本,支持對class的修飾:

zhouhh@zhouhh-home:~$ python

Python 2.6.4 (r264:75706, Dec? 7 2009, 18:45:15)

[GCC 4.4.1] on linux2

Type "help", "copyright", "credits" or "license" for more information.

@修飾符挺像是處理函數或類之前進行預處理。

語法示例:

@dec1

@dec2

def test(arg):

? ? pass

其效果類似于

dec1(dec2(test(arg)))

修飾函數還可以帶參數。

@dec1(arg1,arg2)

def test(testarg)

效果類似于

dec1(arg1,arg2)(test(arg))

[]

http://blog.csdn.net/guang11cheng/article/details/51179410

示例1

def minus(f):

? ? print 'minus'

? ? f()

def plus(f):

? ? print 'plus'

? ? f()

def test(a):

? ? if a > 3 :

? ? ? ? return plus

? ? else :

? ? ? ? return minus

@test(5)

def xxx():

? ? print 'ok'

解釋器首先會解釋@符號后面的代碼,如果如上面的代碼類似,那么test(5)將被執行,因為test參數5大于3,所以會返回函數指針plus(可以用C的這個名字來理解),plus將下一行的函數指針xxx當作參數傳入,直到執行完成。最后結果將輸出‘plus’和‘ok’。 有時候可能是下面這種形式:

示例2

def minus(f):

? ? print 'minus'

? ? f()

@minus

def xxx():

? ? print 'ok'

minus因為本身已經是一個函數指針,所以會直接以xxx作為參數傳入,結果會輸出‘minus’和‘ok’。

--wjt:是不是說,如果一個函數的入參是另一個函數(實例2),或者一個函數的返回值是另一個帶函數參數的函數(實例1),那么這個函數就可以被@。?

即被@的函數,其需要有能力接收的起下一行的函數進入自己的函數體中。?

果真如此。那么裝飾器其實并沒有什么神秘的,無非就是一個語法:

語法示例:

@dec1

@dec2

def test(arg):

? ? pass

其效果類似于

dec1(dec2(test(arg)))

只需要遵守其語法。實質按上面藍色字體講的理解即可。

即裝飾器:(1)形式上要求即被@的函數,其需要有能力接收的起下一行的函數進入自己的函數體中;(2)實質執行上效果類似于dec1(dec2(test(arg)))。

下面的例子我分析出的結果正確,說明我的理解到位:

def f1(arg):

? ? print "f1"

? ? rl = arg()

? ? print rl

? ? return rl + "f1"

@f1

def f2(s = ""):

? ? print "f2"

? ? return s + "f2r"

print "start"

D:\Users\wangjiangtao517>python D:\wangjt\zsq.py

f1

f2

f2r

start

--------------------------------------------------------------------

《一步一步詳解裝飾器》

http://python.jobbole.com/81683/

6. 嵌套函數

Python允許創建嵌套函數。這意味著我們可以在函數里面定義函數而且現有的作用域和變量生存周期依舊適用。

def outer():

? ? x = 1

? ? def inner():

? ? ? ? print x # 1

? ? inner() # 2

outer()

1

這個例子有一點兒復雜,但是看起來也還行。想一想在#1發生了什么:python解釋器需找一個叫x的本地變量,查找失敗之后會繼續在上層的作用域里面尋找,這個上層的作用域定義在另外一個函數里面。對函數outer來說,變量x是一個本地變量,但是如先前提到的一樣,函數inner可以訪問封閉的作用域(至少可以讀和修改)。在#2處,我們調用函數inner,非常重要的一點是,inner也僅僅是一個遵循python變量解析規則的變量名,python解釋器會優先在outer的作用域里面對變量名inner查找匹配的變量.

7. 函數是python世界里的一級類對象

顯而易見,在python里函數和其他東西一樣都是對象。

issubclass(int, object) # all objects in Python inherit from a common baseclass

True

def foo():

? ? pass

foo.__class__ # 1

<type 'function'>

issubclass(foo.__class__, object)

True

函數在python里面就是對象,和其他的東西一樣,也許這樣描述會太學院派太官方了點:在python里,函數只是一些普通的值而已和其他的值一毛一樣。這就是說你可以把函數像參數一樣傳遞給其他的函數或者說從函數了里面返回函數!如果你從來沒有這么想過,那看看下面這個例子:

def add(x, y):

? ? return x + y

def sub(x, y):

? ? return x - y

def apply(func, x, y): # 1

? ? return func(x, y) # 2

apply(add, 2, 1) # 3

3

apply(sub, 2, 1)

1

把函數當做返回值:

def outer():

? ? def inner():

? ? ? ? print "Inside inner"

? ? return inner # 1

foo = outer() #2

>>> foo

<function inner at 0x03912DF0> --- 顯示變量 foo 的值(是一個函數)

>>> foo()

Inside inner? ---執行了函數inner()

這個例子看起來也許會更加的奇怪。在#1處我把恰好是函數標識符的變量inner作為返回值返回出來。這并沒有什么特殊的語法:”把函數inner返回出來,否則它根本不可能會被外界所調用。“還記得變量的生存周期嗎?每次函數outer被調用的時候,函數inner都會被重新定義,如果它不被當做變量返回的話,每次執行過后它將不復存在。

在#2處我們捕獲返回值 – 函數inner,將它存在一個新的變量foo里。我們能夠看到,當對變量foo進行求值,它確實包含函數inner,而且我們能夠對他進行調用。初次看起來可能會覺得有點奇怪,但是理解起來并不困難是吧。

8. 閉包

def outer(x):

? ? def inner():

? ? ? ? print x # 1

? ? return inner

print1 = outer(1)

print2 = outer(2)

print1()

1

print2()

2

9. 裝飾器

裝飾器其實就是一個閉包,把一個函數當做參數然后返回一個替代版函數.

def outer(some_func):

? ? def inner():

? ? ? ? print "before some_func"

? ? ? ? ret = some_func() # 1

? ? ? ? return ret + 1

? ? return inner

def foo():

? ? return 1

decorated = outer(foo) # 2

decorated()

before some_func

2

仔細看看上面這個裝飾器的例子。我們定義了一個函數outer,它只有一個some_func的參數,在他里面我們定義了一個嵌套的函數inner。inner會打印一串字符串,然后調用some_func,在#1處得到它的返回值。在outer每次調用的時候some_func的值可能會不一樣,但是不管some_func的之如何,我們都會調用它。最后,inner返回some_func() + 1的值 – 我們通過調用在#2處存儲在變量decorated里面的函數能夠看到被打印出來的字符串以及返回值2。

我們可以認為變量decorated是函數foo的一個裝飾版本,一個加強版本。事實上如果打算寫一個有用的裝飾器的話,我們可能會想愿意用裝飾版本完全取代原先的函數foo,這樣我們總是會得到我們的”加強版“foo。想要達到這個效果,完全不需要學習新的語法,簡單地賦值給變量foo就行了:

foo = outer(foo)

foo # doctest: +ELLIPSIS

<function inner at 0x>

現在,任何怎么調用都不會牽扯到原先的函數foo,都會得到新的裝飾版本的foo

--------------------------------

《closure(閉包)》

https://www.cnblogs.com/Pierre-de-Ronsard/archive/2012/08/20/2647812.html

closure概念:在一個內部函數中,對外部作用域的變量進行引用,那么內部函數就被認為是closure(閉包)

自由變量:定義在外部函數內,被內部函數引用或者使用的變量為自由變量

函數func_closure 在函數被調用前和調用后使用,效果是一樣的

https://segmentfault.com/a/1190000007321972

用比較容易懂的人話說,就是當某個函數被當成對象返回時,夾帶了外部變量,就形成了一個閉包。看例子。

def make_printer(msg):

? ? def printer():

? ? ? ? print msg? # 夾帶私貨(外部變量)

? ? return printer? # 返回的是函數,帶私貨的函數

printer = make_printer('Foo!')

printer()

支持將函數當成對象使用的編程語言,一般都支持閉包。比如Python, JavaScript。

我個人認為,閉包存在的意義就是它夾帶了外部變量(私貨),如果它不夾帶私貨,它和普通的函數就沒有任何區別。同一個的函數夾帶了不同的私貨,就實現了不同的功能。其實你也可以這么理解,閉包和面向接口編程的概念很像,可以把閉包理解成輕量級的接口封裝。

ef tag(tag_name):

? ? def add_tag(content):

? ? ? ? return "<{0}>{1}</{0}>".format(tag_name, content)

? ? return add_tag

content = 'Hello'

add_tag = tag('a')

print add_tag(content)

# <a>Hello</a>

add_tag = tag('b')

print add_tag(content)

# <b>Hello</b>

在這個例子里,我們想要一個給content加tag的功能,但是具體的tag_name是什么樣子的要根據實際需求來定,對外部調用的接口已經確定,就是add_tag(content)。如果按照面向接口方式實現,我們會先把add_tag寫成接口,指定其參數和返回類型,然后分別去實現a和b的add_tag。

但是在閉包的概念中,add_tag就是一個函數,它需要tag_name和content兩個參數,只不過tag_name這個參數是打包帶走的。所以一開始時就可以告訴我怎么打包,然后帶走就行。

--------------------

《format函數》

https://www.cnblogs.com/chunlaipiupiupiu/p/7978669.html

python中format函數用于字符串的格式化

通過關鍵字

1 print('{名字}今天{動作}'.format(名字='陳某某',動作='拍視頻'))#通過關鍵字

2 grade = {'name' : '陳某某', 'fenshu': '59'}

3 print('{name}電工考了{fenshu}'.format(**grade))#通過關鍵字,可用字典當關鍵字傳入值時,在字典前加**即可

通過位置

1 print('{1}今天{0}'.format('拍視頻','陳某某'))#通過位置

2 print('{0}今天{1}'.format('陳某某','拍視頻'))

填充和對齊^<>分別表示居中、左對齊、右對齊,后面帶寬度

1 print('{:^14}'.format('陳某某'))

2 print('{:>14}'.format('陳某某'))

3 print('{:<14}'.format('陳某某'))

4 print('{:*<14}'.format('陳某某'))

5 print('{:&>14}'.format('陳某某'))#填充和對齊^<>分別表示居中、左對齊、右對齊,后面帶寬度

精度和類型f精度常和f一起使用

1 print('{:.1f}'.format(4.234324525254))

2 print('{:.4f}'.format(4.1))

進制轉化,b o d x 分別表示二、八、十、十六進制

print('{:b}'.format(250))

print('{:o}'.format(250))

print('{:d}'.format(250))

print('{:x}'.format(250))

千分位分隔符,這種情況只針對與數字

print('{:,}'.format(100000000))

print('{:,}'.format(235445.234235))

--------------------

《案例》

[]

http://blog.sina.com.cn/s/blog_6fe87f870101d9cm.html

'@'符號用作函數修飾符必須出現在函數定義前一行,不允許和函數定義在同一行。也就是說@A def f(): 是非法的。 只可以在模塊或類定義層內對函數進行修飾。一個修飾符就是一個函數,它將被修飾的函數做為參數,并返回修飾后的同名函數或其它可調用的東西。

下面不懂:

###################################

def spamrun(fn):

? ? def sayspam(*args):

? ? ? ? print "spam,spam,spam"

? ? return sayspam

@spamrun

def useful(a,b):

? ? print a**2+b**2


useful(3,4)

###################################

D:\Users\wangjiangtao517>python D:\wangjt\zsq.py

spam,spam,spam

###################################

def spamrun(fn):

? ? def sayspam(*args):

? ? ? ? print "spam,spam,spam"

? ? return sayspam

#@spamrun

def useful(a,b):

? ? print a**2+b**2


useful(3,4)

###################################

D:\Users\wangjiangtao517>python D:\wangjt\zsq.py

25

###################################

def spamrun(fn):

? ? def sayspam(*args):

? ? ? ? print "spam,spam,spam"

? ? #return sayspam

#@spamrun

def useful(a,b):

? ? print a**2+b**2


useful(3,4)

###################################

D:\Users\wangjiangtao517>python D:\wangjt\zsq.py

Traceback (most recent call last):

? File "D:\wangjt\zsq.py", line 10, in <module>

? ? useful(3,4)

TypeError: 'NoneType' object is not callable

實例

def decorator(fn):

? ? def test(*args):

? ? ? ? print "My god!"*3

? ? ? ? return fn(*args)

? ? return test

@decorator

def other(a,b):

? ? print a**2+b**2

if __name__=="__main__":

? ? other(4,3)

? ? other(3,4)


結果:

My god!My god!My god!

25

My god!My god!My god!

25

注釋掉//print return fn(*args)

結果是:

My god!My god!My god!

My god!My god!My god!

要想使other函數能正常運行,必須加返回值,@decorator是一個statement,會將other函數當作參數傳入來執行test方法

------------------

《主線程、子線程主線程、子線程》

用裝飾器實現子線程執行10分鐘還沒返回被主線程kill掉?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容