国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

python奇遇記:深入理解裝飾器

lemon / 2311人閱讀

摘要:可見裝飾器改變了函數的功能。裝飾器除了改變函數功能之外還有一個特性是,函數裝飾器在導入模塊時立即執行,而被裝飾的函數只在明確調用時運行。

什么是裝飾器

裝飾器是什么,簡單來說,裝飾器可以改變一個函數的行為,比如原本有一個函數用來計算菲波那切數列,我們給這個函數加個計算執行時間的裝飾器,這樣原來的函數不僅能夠計算菲波那切數列,而且還可以輸出計算花費了多少時間。

在Python中,有幾個很常見的內置裝飾器:比如@staticmethod, 它可以將一個類的方法聲明為靜態的。@property, 為類中的變量設置get和set方法,保證了封裝性。

如果你使用過python的web框架(比如flask)開發過網站,你應該經常會見到裝飾器,像下面這樣:

@app.route("/")
def hello():
    return "Hello World!"

這段代碼把路由綁定到hello函數上,這樣你輸入網址之后就可以看到Hello World

先來看個很簡單的例子:

# 定義了一個裝飾器
def deco(func):
  def hah():
      print("hahha")
  return hah

上面我們定義了一個裝飾器,打印hahah,接下來使用:

# 使用這個裝飾器
@deco
def lal():
    pritn("lalalala")

lal()

執行lal()會輸出hahha。 可見deco裝飾器改變了lal函數的功能。上面的代碼中,我們實際上是把lal函數放入了deco函數,像這樣:

lal = deco(lal)

只不過,直接使用@標志把裝飾器放在某個函數上更方便一點而已。

裝飾器其實就是一個函數嵌套另一個函數(這里涉及到一個概念叫做閉包,下面會講到)。在裝飾器的定義中,需要把內部的函數返回(像hah),內部函數用來真正的改變被裝飾函數的功能。

不過,上面定義的裝飾器好像沒什么用,我們來真正的寫一個裝飾器,像文章開頭說的那樣,定義一個裝飾器計算函數執行的時間。

實現一個簡單的裝飾器
import time
# 這個裝飾器接收一個函數作為參數
def clock(func):
  # clocked用來改變被裝飾函數功能
  # 接收任意可變參數
    def clocked(*args):
      #先計算時間
        t0 = time.perf_counter()
        # 然后運行被裝飾的函數
        result = func(*args)
        # 計算運行前后的時間差
        elapsed = time.perf_counter()-t0
        # 函數的名字
        name = func.__name__
        # 被裝飾函數的所有變量
        arg_str = ",".join(repr(arg) for arg in args)
        # 輸出
        print("[%0.8fs] %s(%s) -> %r" % (elapsed, name, arg_str, result))
        # 返回被裝飾函數執行結果
        # 可見裝飾器是在原來的函數上增加了某些功能
        # 而不是完全改變被裝飾函數
        return result
     # 把clocked函數返回
    return clocked

來使用一下上面定義的裝飾器:

@clock
def factorial(n):
    return 1 if n<2 else n*factorial(n-1)
  
result = factorial(6)
print(result)

執行結果:

[0.00000030s] factorial(1) -> 1
[0.00004588s] factorial(2) -> 2
[0.00007184s] factorial(3) -> 6
[0.00060794s] factorial(4) -> 24
[0.00064205s] factorial(5) -> 120
[0.00066801s] factorial(6) -> 720
720

可以看到,在輸出計算結果的同時,輸出了每一步的執行時間。

裝飾器除了改變函數功能之外還有一個特性是,函數裝飾器在導入模塊時立即執行,而被裝飾的函數只在明確調用時運行。這點需要注意。

當然了,裝飾器之上還可以放一個裝飾器,不過是多了一層嵌套而已。

python中還有一個內置的模塊functools,這里面定義了一些常用的裝飾器函數,幫助你更好地定義自己的裝飾器。這里就不講了。

閉包

說到閉包,在上面的代碼中我們已經見識到了,函數中嵌套函數就是閉包。嚴格來說,閉包是指延伸了作用域的函數,怎么理解?不如來看個例子:

我們定義一個函數不斷計算平均值,它會記住上一次計算的值進行累計。

# 先看一些效果
avg = make_averager()
print(avg(10))
print(avg(11))
print(avg(12))

輸出如下:

10.0
10.5
11.0

第一次輸出10,第二次輸出10加11的平均值,第三次輸出10加11加12的平均值。

怎么實現的?

def make_averager():
  # 局部變量series
  # 用來保存每次輸入的值
    series = []
    def averager(new_value):
        series.append(new_value)
        total = sum(series)
        return total/len(series)
    return averager

上面的函數中,series是局部變量。當我們調用avg(10)的時候,函數已經返回了,按理說它的本地作用域已經不存在了,但是我們還是可以繼續使用。這是因為series其實是自由變量,它不受本地作用域的限制。需要注意的是,對于不可變類型,需要顯示用關鍵字nonlocal 聲明自由變量,如果不聲明的話,會隱式的創建局部變量,這樣自由變量就會失效。而可變類型則不需要。比如,我們來更改一下上面的代碼:

# 改一下求平均值的函數
# 用另一種方法
def make_averager():
   count = 0
   total = 0
   def averager(new_value):
      # count、total是不可變類型
      # 需要聲明為自由變量
     nonlocal count, total
     count += 1
     total += new_value
     return total / count
   return averager

除了上面說的裝飾器的用法之外,我們還可以為裝飾器添加參數,像app.route("/") 這樣,限于篇幅,下一篇文章再介紹。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/41224.html

相關文章

  • python奇遇:隱藏的python功能

    摘要:先不講數據結構了,這次來說說中一些不被注意的功能。直接交換第二個功能。對的長度使用生成一個序列,然后遍歷或者這樣第三個功能。其實還接受第二個參數,它的作用是在迭代的過程中如果碰到第二個參數則停止。 先不講數據結構了,這次來說說python中一些不被注意的功能。 在python的設計哲學中,有這么一條內容:Simple is better than complex,簡單的代碼比復雜的要好...

    APICloud 評論0 收藏0
  • python奇遇:迭代和生成

    摘要:來說說迭代器和生成器,還有可迭代對象和生成器表達式。有點繞是不是,其實,一般只要知道可迭代對象以及它是如何實現的就行了,中常常用生成器來代替迭代器,可以說,生成器就是迭代器。 來說說迭代器和生成器,還有可迭代對象和生成器表達式。 之前簡單的提到過,一個對象是可迭代的可以理解為能夠使用for循環。這樣說其實不太準確,某個對象可迭代是因為它內部實現了$__iter__$這個特殊方法。比如在...

    atinosun 評論0 收藏0
  • Python奇遇:數據結構窺探2

    摘要:找出列表中小于的數據除了列表推導式,還有字典推導式,集合推導式,用法都一樣。如果你的數據量很大的話,考慮使用生成器表達式。切片不僅對列表有用,同樣適用于元組和字符串。切片命名使用方法,內部參數與切片一樣。對剩余的的數據,使用星號代替即可。 上次我們講了幾個不常見的數據類型,每個都有自己特殊的用途,雖然不經常用到,了解一下也好。比如我們提到的數組類型,如果在數據量很大的時候同時要效率,就...

    Ocean 評論0 收藏0
  • python奇遇:數據結構窺探3

    摘要:字典和集合都是基于散列表實現的,散列表也就是表,了解過數據結構的應該知道。而使用另一種辦法,任何鍵在找不到的情況下都會用中的值數據類型比如替換。在設計時就可以使用創建你的數據接口。 這次主要說說字典和集合這兩種數據類型。 字典和集合都是基于散列表實現的,散列表也就是hash表,了解過數據結構的應該知道。與散列表相關的一個概念叫做可散列,什么是可散列?在python官方定義中是這樣說的:...

    toddmark 評論0 收藏0
  • Python奇遇:特殊方法窺探

    摘要:在中,特殊方法以雙下劃線開始,以雙下劃線結束。真假值,如果向量模為,返回實現向量加法實現向量乘法,例如返回向量的模返回歐幾里德范數找個例子運行下。怎么辦中有個特殊方法,可以修改控制臺輸出的樣式。 什么是特殊方法?當我們在設計一個類的時候,python中有一個用于初始化的方法$__init__$,類似于java中的構造器,這個就是特殊方法,也叫作魔術方法。簡單來說,特殊方法可以給你設計的...

    niceforbear 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<