日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python装饰器怎么编程_Python编程:Python装饰器入门

發(fā)布時間:2024/9/27 python 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python装饰器怎么编程_Python编程:Python装饰器入门 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Python允許你,作為程序員,使用函數(shù)完成一些很酷的事情。在Python編程學(xué)習(xí)中,函數(shù)是一等對象(first-class object),這就意味著你可以像使用字符串,整數(shù),或者任何其他對象一樣使用函數(shù)。

例如,你可以將函數(shù)賦值給變量:

>>> def square(n):

... return n * n;

>>> square(4)

16

>>> alias = square

>>> alias(4)

16

然而,一等函數(shù)的真正威力在于你可以把函數(shù)傳給其他函數(shù),或者從其他函數(shù)中返回函數(shù)。Python的內(nèi)置函數(shù)map利用了這種能力:給map傳個函數(shù)以及一個列表,它會依次以列表中每個元素為參數(shù)調(diào)用你傳給它的那個函數(shù),從而生成一個新的列表。如下所示的例子中應(yīng)用了上面的那個square函數(shù):

>>> number = [1, 2, 3, 4, 5]

>>> map(square, numbers)

[1, 4, 9, 16, 25]

如果一個函數(shù)接受其他函數(shù)作為參數(shù),以及/或者返回一個函數(shù),那么它就被稱為高階函數(shù) 。雖然map函數(shù)只是簡單地使用了我們傳給它的函數(shù),而沒有改變這個函數(shù),但我們也可以使用高階函數(shù)去改變其他函數(shù)的行為。

例如,假設(shè)有這樣一個函數(shù),會被調(diào)用很多次,以致運行代價非常昂貴:

>>> def fib(n):

... "Recursively (i.e., dreadfully) calculate the nth Fibonacci number."

... return n if n in [0, 1] else fib(n - 2) + fib(n - 1)

我們一般會保存計算過程中每次遞歸調(diào)用的結(jié)果,這樣,對于函數(shù)調(diào)用樹中經(jīng)常出現(xiàn)某個n,當(dāng)需要計算n對應(yīng)的結(jié)果時,就不需要重復(fù)計算了。有多種方式可以做到這點。例如,我們可以將這些結(jié)果存在一個字典中,當(dāng)以某個值為參數(shù)調(diào)用fib函數(shù)時,就先到這個字典去查一下其結(jié)果是否已經(jīng)計算出來了。

但這樣的話,每次我們想要調(diào)用fib函數(shù),都需要重復(fù)那段相同的字典檢查樣板式代碼。相反,如果讓fib函數(shù)自己在內(nèi)部負(fù)責(zé)存儲其結(jié)果,那么在其他代碼中調(diào)用fib,就非常方便,只要簡單地調(diào)用它就行了。這樣一種技術(shù)被稱為memoization(注意沒有字母r的哦)。

我們可以把這種memoization代碼直接放入fib函數(shù),但是Python為我們提供了另外一種更加優(yōu)雅的選擇。因為可以編寫修改其他函數(shù)的函數(shù),那么我們可以編寫一個通用的memoization函數(shù),以一個函數(shù)作為參數(shù),并返回這個函數(shù)的memoization版本:

def memoize(fn):

stored_results = {}

def memoized(*args):

try:

# try to get the cached result

return stored_results[args]

except KeyError:

# nothing was cached for those args. let's fix that.

result = stored_results[args] = fn(*args)

return result

return memoized

如上, memoize 函數(shù)以另一個函數(shù)作為參數(shù),函數(shù)體中創(chuàng)建了一個字典對象用來存儲函數(shù)調(diào)用的結(jié)果:鍵為被memoized包裝后的函數(shù)的參數(shù),值為以鍵為參數(shù)調(diào)用函數(shù)的返回值。 memoize 函數(shù)返回一個新的函數(shù),這個函數(shù)會首先檢查在 stored_results 字典中是否存在與當(dāng)前參數(shù)對應(yīng)的條目;如果有,對應(yīng)的存儲值會被返回;否則,就調(diào)用經(jīng)過包裝的函數(shù),存儲其返回值,并且返回給調(diào)用者。memoize返回的這種新函數(shù)常被稱為"包裝器"函數(shù),因為它只是另外一個真正起作用的函數(shù)外面的一個薄層。

很好,現(xiàn)在有了一個memoization函數(shù),我們可以把fib函數(shù)傳給它,從而得到一個經(jīng)過包裝的fib,這個版本的fib函數(shù)不需要重復(fù)以前那樣的繁重工作:

def fib(n):

return n if n in [0, 1] else fib(n - 2) + fib(n - 1)

fib = memoize(fib)

通過高階函數(shù)memoize,我們獲得了memoization帶來的好處,并且不需要對fib函數(shù)自己做出任何改變,以免夾雜著memoization的代碼而模糊了函數(shù)的實質(zhì)工作。但是,你也許注意到上面的代碼還算有點別扭,因為我們必須寫3遍fib。由于這種模式-傳遞一個函數(shù)給另一個函數(shù),然后將結(jié)果返回給與原來那個函數(shù)同名的函數(shù)變量-在使用包裝器函數(shù)的代碼中極為常見,Python為其提供了一種特殊的語法:裝飾器:

@memoize

def fib(n):

return n if n in [0, 1] else fib(n - 2) + fib(n -1)

這里,我們說memoize函數(shù)裝飾了fib函數(shù)。需要注意的是這僅是一種語法上的簡便寫法(譯注:就是我們常說的"語法糖")。這段代碼與前面的代碼片段做的是同樣的事情:定義一個名為fib的函數(shù),把它傳給memoize函數(shù),將返回結(jié)果存為名為fib的函數(shù)變量。特殊的(看起來有點奇怪的)@語法只是減少了冗余。

你可以將多個裝飾器堆疊起來使用,它們會自底向上地逐個起作用。例如,假設(shè)我們還有另一個用來幫助調(diào)試的高階函數(shù):

def make_verbose(fn):

def verbose(*args):

# will print (e.g.) fib(5)

print '%s(%s)' % (fb.__name__, ', '.join(repr(arg) for arg in args))

return fn(*args) # actually call the decorated function

return verbose

下面的兩個代碼片段做的是同樣的事情:

@memoize

@make_verbose

def fib(n):

return n if n in [0, 1] else fib(n - 2) + fib(n - 1)

def fib(n):

return n if n in [0, 1] else fib(n - 2) + fib(n - 1)

fib = memoize(make_verbose(fib))

有趣的是,Python并沒有限制你在@符號后只能寫一個函數(shù)名:你也可以調(diào)用一個函數(shù),從而能夠高效地傳遞參數(shù)給裝飾器。假設(shè)我們并不滿足于簡單的memoization,還想將函數(shù)的結(jié)果存儲到memcached中。如果你已經(jīng)寫了一個 memcached 裝飾器函數(shù),那么可以(例如)傳遞一個服務(wù)器地址給它:

@memcached('127.0.0.1:11211')

def fib(n):

return n if n in [0, 1] else fib(n - 2) + fib(n - 1)

非裝飾器語法的寫法會如下展開:

fib = memcached('127.0.0.1:11211')(fib)

Python配備有一些作為裝飾器使用的非常有用的函數(shù)。例如,Python有一個 classmethod 函數(shù),可以創(chuàng)建大致類似于java的靜態(tài)方法:

class Foo(object):

SOME_CLASS_CONSTANT = 42

@classmethod

def add_to_my_constant(cls, value):

# Here, `cls` will just be Foo, buf if you called this method on a

# subclass of Foo, `cls` would be that subclass instead.

return cls.SOME_CLASS_CONSTANT + value

Foo.add_to_my_constant(10) # => 52

# unlike in Java, you can also call a classmethod on an instance

f = Foo()

f.add_to_my_constant(10) # => 52

旁注:文檔字符串

Python函數(shù)可以包含更多的信息,而不僅僅是代碼:它們也包含有用的幫助信息,比如函數(shù)名稱,文檔字符串:

>>> def fib(n):

... "Recursively (i.e., dreadfully) calculate the nth Fibonacci number."

... return n if n in [0, 1] else fib(n - 2) + fib(n - 1)

...

>>> fib.__name__

'fib'

>>> fib.__doc__

'Recursively (i.e., dreadfully) calculate the nth Fibonacci number.'

Python內(nèi)置函數(shù)help輸出的就是這些信息。但是,當(dāng)函數(shù)被包裝之后,我們看到就是包裝器函數(shù)的名稱和文檔字符串了:

>>> fib = memoized(fib)

>>> fib.__name__

'memoized'

>>> fib.__doc__

那樣的信息并沒有什么用處。幸運的是,Python包含一個名為 functools.wraps 的助手函數(shù),能夠把函數(shù)的幫助信息拷貝到其包裝器函數(shù):

import functools

def memoize(fn):

stored_results = {}

@functools.wraps(fn)

def memoized(*args):

# (as before)

return memoized

使用裝飾器幫助你編寫裝飾器會使很多事情令人非常滿意?,F(xiàn)在,如果使用更新過的memoize函數(shù)重試前面的代碼,我們將會看到得到保留的文檔:

>>> fib = memoized(fib)

>>> fib.__name__

'fib'

>>> fib.__doc__

'Recursively (i.e., dreadfully) calculate the nth Fibonacci number.'

更多的Python編程學(xué)習(xí)教程下期繼續(xù)為大家更新!

總結(jié)

以上是生活随笔為你收集整理的python装饰器怎么编程_Python编程:Python装饰器入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。