日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

我叫駱駝

會點兒代碼,會點兒讀書

這世上的書浩如煙海

我能做的就是盡量整理分享給你

在上一節Flask項目實戰第一彈中我們講到了路由,先看下面代碼回顧一下:

from flask import Flask

App = Flask(__name__)


@app.route("/hello")
def hello():
    return "<p>Hello World ...</p>"


if __name__ == '__main__':
    app.run(load_dotenv=True)

@app.route("/hello") 就是裝飾器。交流群里小伙伴問我,Python/ target=_blank class=infotextkey>Python里的裝飾器該怎么理解,今天我們好好嘮嘮這個東西。

說到裝飾器,我們不得不談一個知識點:閉包。我們從代碼入手,一點一點來說閉包。

Python 有一個好玩的地兒,就是 def 函數(exterior)內部可以嵌套另一個 def 函數(interior)。調用 exterior 時,若遇到 interior , 僅僅完成對于 interior 的定義,而不去運行 interior。如果 exterior return interior,那么我們可以使用 interior () 去調用 內部函數 interior 函數。

 var = 0


def exterior():
    var = 1

    def interior():
        print(var)
    return interior()  # 這里返回 interior 函數調用結果


exterior() # 打印 1

從上面代碼和結果中可以看到,interior 打印的 var 值 并非 第一行的 var。這說明,exterior 中的嵌套變量 var 覆蓋了全局變量var=0,然后 interior 中的本地變量按照引用規則,就引用了var = 1。

接下來,我們仔細想想下面這句話:

interior 作用域在函數結束后就立即失效,而exterior嵌套作用域在 interior 的函數返回后卻仍然有效。

var = 0


def exterior():
    var = 1

    def interior():
        print(var)
    return interior  # 這里返回 interior 函數對象


inter = exterior() 
inter()  # 打印 1

看完上面代碼,再思考一下剛剛的話。如果還不清楚,看下圖:

圖解

創建一個閉包必須滿足以下幾點:

  • 必須有一個內嵌函數
  • 內嵌函數必須引用外部函數中的變量
  • 外部函數的返回值必須是內嵌函數

現在有了閉包的知識點,我們再聊聊裝飾器(decorator)。我要掰開了揉碎了來說說裝飾器。

剛剛接觸裝飾器的同學會對這個概念感到迷茫,然后你在網上(尤其 csdn)找例子或者教程,基本千篇一律,或者講解的“點到為止”,你在看完之后,或許更迷茫了。

函數是什么

在說裝飾器前,我們聊聊 Python 的函數。眾所周知:在 Python 中,一切皆對象,函數是一等對象。

編程語言理論家把“一等對象”定義為滿足下述條件的程序實體:

  • 在運行時創建①
  • 能賦值給變量或者數據結構中的元素②
  • 能作為參數傳遞給函數③
  • 能作為函數的返回結果④

我們看這么一段程序:

def double(x: int) -> int:
    return x * 2

這段代碼很簡單,計算了一個整數的2倍。那么我么用 dis 模塊進行反編譯,看看他是怎么運行的。

>>>from my_test import double
>>>from dis import dis

>>>dis(double)  # 結果如下

源碼行號

指令在函數中的偏移

指令符號

指令參數

實際參數值

2

0

LOAD_FAST

0

x

 

2

LOAD_CONST

1

2

 

4

BINARY_MULTIRLY

 

 

 

6

RETURN_VALUE

 

 

指令符號解釋:

  • LOAD_FAST :一般加載局部變量的值,也就是讀取值,用于計算或者函數調用傳參等;
  • LOAD_CONST :加載 const 變量,比如數值、字符串等等;
  • BINARY_MULTIRLY:見名知意,二進制乘法
  • RETURN_VALUE:返回值

結合反編譯的結果,仔細理解一下代碼的運行流程。下面我們看另外一個例子:

def double(x: int) -> int:
    return x * 2


def triple(x: int) -> int:
    return x * 3


def call_func(func, x: int) -> int:
    return func(x)


result = call_func(triple, 2)
print(result)
dis(call_func)

源碼行號

指令在函數中的偏移

指令符號

指令參數

實際參數值

10

0

LOAD_FAST

0

func

 

2

LOAD_FAST

1

x

 

4

CALL_FUNCTION

1

 

 

6

RETURN_VALUE

 

 

在運行過程中:出現了 CALL_FUNCTION 。結合第13行代碼,仔細體會一下這句話:函數能作為參數傳遞給另外一個函數。

我們現在看一下閉包的執行流程

def call_func():
    def double(x: int) -> int:
        return x * 2

    return double

dis(call_func)

里邊出現了一個關鍵詞:MAKE_FUNCTION,見名知意,創建函數。此時再回想“一等對象”所滿足的條件。

說了這么多,無非是想告訴大家一個重要的東西,函數就是對象,可以被另一個函數返回,可以被賦值,也可以被調用。

其實到這里,才真是說完閉包這個東西。裝飾器和閉包大同小異,下面我們接著來。

裝飾器

有這種一種等價語法:

def callfunc(func):
    return 1


@callfunc
def triple(x: int) -> int:
    return x * 3

等價于

def callfunc(func):
    return 1


def triple(x: int) -> int:
    return x * 3


triple = callfunc(triple)

無論上面那種方式,我們輸出的 tripre 這個對象的值都是 1

>>> print(triple)
>>> 1

所以,閉包可以寫成@這種形式呢?其實,裝飾器可以理解為閉包的一種,我們可以這樣認為:閉包傳遞的是變量,而裝飾器傳遞的是函數,除此之外沒有任何區別。

我們看一個打印時間的裝飾器:

import time


def timeit(func):
    def wrapper(x):
        start = time.time()
        ret = func(x)
        print(time.time() - start)
        return ret

    return wrapper


@timeit
def my_func(x):
    time.sleep(x)


my_func(1)

timeit 裝飾器就打印 my_func 函數的運行時間。是不是在了解完閉包之后很簡單了。

裝飾器的作用就是:在不改變原函數的情況下,對已有函數進行額外的功能擴展。

恭喜你,Python 技能又進一步。

回到 Flask 我們看看路由裝飾器

Flask 中路由的裝飾器很簡單,我們以 route 為例,以下是 route 函數源碼(抽離版):

import typing as t


def add_url_rule(rule, endpoint, f, param):
    pass


def route(rule: str, **options: t.Any) -> t.Callable:

    def decorator(f: t.Callable) -> t.Callable:
        endpoint = options.pop("endpoint", None)
        add_url_rule(rule, endpoint, f, **options)
        return f

    return decorator

route 函數就是一個裝飾器,內部嗲用 add_url_rule 實現真正的路由添加。再回過頭看看裝飾器的作用和定義以及使用,是不是明白了許多!加油,慢就快,快就是慢。

分享到:
標簽:Python
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定