欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python裝飾器詳細(xì)介紹

 更新時(shí)間:2022年03月25日 11:50:00   作者:~淚小白~  
這篇文章主要介紹了Python裝飾器詳細(xì)講解,包括裝飾器的功能及實(shí)現(xiàn)方法,通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下

裝飾器

一、介紹

  • :代表函數(shù)的意思。裝飾器本質(zhì)就是是函數(shù)
  • 功能:裝飾其他函數(shù),就是為其他函數(shù)添加附加功能 
  • 被裝飾函數(shù)感受不到裝飾器的存在
  • 原則: 

    不能修改被裝飾的函數(shù)的源代碼(比如線上環(huán)境)

    不能修改被裝飾的函數(shù)的調(diào)用方式 

  • 實(shí)現(xiàn)裝飾器知識(shí)儲(chǔ)備: 

    函數(shù)即是“變量”

    高階函數(shù)

    嵌套函數(shù)

高階函數(shù)+嵌套函數(shù)=>裝飾器

二、通過(guò)高階函數(shù)+嵌套函數(shù)==>實(shí)現(xiàn)裝飾器

先分析以下兩段代碼能不能運(yùn)行?

def foo():
    print("in the foo")
    bar()
def bar():
    print("in the bar")

foo()
def foo():
    print("in the foo")
    bar()
foo()
def bar():
    print("in the bar")

第二段代碼報(bào)錯(cuò):

NameError: name 'bar' is not defined

1、變量知識(shí)回顧

定義變量: 
如:定義變量:x=1,會(huì)在內(nèi)存中找塊內(nèi)存空間把“1”存進(jìn)去,把“1”的內(nèi)存地址給x  

前面提到:函數(shù)即變量

# 定義函數(shù)
def test():
    pass
# 就相當(dāng)于把函數(shù)體賦值給test變量
test = '函數(shù)體'  # 函數(shù)體就是一堆字符串而已
# 只不過(guò)函數(shù)調(diào)用要加上小括號(hào)調(diào)用
test()

python內(nèi)存回收機(jī)制,是解釋器做的。解釋器到底怎么去回收這個(gè)變量? 
python解釋器當(dāng)中有種概念叫做引用計(jì)數(shù)。什么叫引用計(jì)數(shù)呢? 
比如:定義x=1,之后又定義了y=1或y=x,實(shí)際上又把內(nèi)存空間“1”的內(nèi)存地址賦值給y 
這里x代表一次引用,y代表一次引用。加起來(lái)兩次引用。 
python什么時(shí)候會(huì)把“1”這個(gè)內(nèi)存空間清空呢?會(huì)回收內(nèi)存呢? 
當(dāng)x這個(gè)變量沒(méi)有了,y這個(gè)變量也沒(méi)有了,便會(huì)把“1”這個(gè)內(nèi)存空間清掉

del x  # 刪的只是變量名,內(nèi)存中的值是解釋器回收

匿名函數(shù)

lambda x:x*x

匿名函數(shù)沒(méi)有函數(shù)名,沒(méi)有引用,所以會(huì)被垃圾回收機(jī)制立馬回收掉。 
所以匿名函數(shù)要賦值給變量,把函數(shù)體賦值給變量名

calc = lambda x:x*x
print(calc(4))

現(xiàn)在可以再理解下最開(kāi)始兩段代碼能不能運(yùn)行的原因。 

2、高階函數(shù)(裝飾器前奏)

什么叫高階函數(shù)呢:

  • 把一個(gè)函數(shù)名當(dāng)做形實(shí)傳給另外一個(gè)函數(shù)
  • 返回值中包含函數(shù)名
def f1():
    print("in the func1")
def test1(func):
    print(func)
test1(f1)

運(yùn)行結(jié)果(打印內(nèi)存地址)

<function func1 at 0x000002805DE12378>

如下代碼,能不能運(yùn)行:

def f1():
    print("in the func1")
def test1(func):
    print(func)
    func()
test1(f1)

函數(shù)即變量,像“x=1,y=x”,同樣f是一個(gè)是一個(gè)函數(shù),可不可以像一個(gè)變量一樣來(lái)回賦值呢?

import time
def func1():
    print("in the func1")
    time.sleep(1)
def test1(func):
    start_time = time.time()
    func()
    stop_time = time.time()
    print("the func run time is %s" %(stop_time-start_time))
test1(func1)

到這里,貌似實(shí)現(xiàn)了裝飾函數(shù)的功能。 
看上面裝飾器的原則: 
這里:沒(méi)有修改func1的源代碼,但是調(diào)用方式改變了。現(xiàn)在是test1(func1),之前是func1() 
現(xiàn)在能做到哪一點(diǎn)呢? 
把一個(gè)函數(shù)名當(dāng)做實(shí)參傳給另外一個(gè)函數(shù)(不修改被裝飾的函數(shù)源代碼的情況下為其添加功能)

2) 下面用第二個(gè)條件(返回值中包含函數(shù)名),做另外一個(gè)高階函數(shù)

import time
def func2():
    time.sleep(1)
    print("in the func2")
def test2(func):
    print(func)
    return(func)
print(test2(func2))

運(yùn)行結(jié)果:

<function func2 at 0x00000162F3672378>
<function func2 at 0x00000162F3672378>

把函數(shù)內(nèi)存地址都打印出來(lái)了,看到這么多內(nèi)存地址,有什么想法? 
加上小括號(hào)就能運(yùn)行。 
上面代碼“test2(func2())”和“test2(func2)”有什么區(qū)別?加上小括號(hào)是函數(shù)返回結(jié)果,不加是函數(shù)內(nèi)存地址。所以加上小括號(hào)就不符合高階函數(shù)定義了。 
既然以后有了函數(shù)的內(nèi)存地址,是不是可以賦值給其他變量?下面

import time
def func2():
    print("in the func2")
    time.sleep(1)
def test2(func):
    print(func)
    return(func)
t = test2(func2)
print(t)
t()

好像還沒(méi)什么用,怎么讓他有用呢? 
把test2(func2)賦值給func2

import time
def func2():
    print("in the func2")
    time.sleep(1)
def test2(func):
    print(func)
    return(func)
func2 = (test2(func2))
func2()

這就是高階函數(shù)的第二個(gè)好處:返回值中包含函數(shù)名(不修改函數(shù)的調(diào)用方式)

3、嵌套函數(shù)(裝飾器前戲)

嵌套函數(shù):在一個(gè)函數(shù)體內(nèi),用def去聲明一個(gè)函數(shù)

def foo():
    print("in the foo")
    def bar():
        print("in the bar")
    bar()
foo()

看一下下面的代碼是不是嵌套:

def foo():
    print("in the foo")
def bar():
    foo()
bar()

注意函數(shù)嵌套和函數(shù)調(diào)用區(qū)別  

局部作用域和全局作用域的訪問(wèn)順序:

x = 0
def grandpa():
    # x = 1
    def dad():
        x = 2
        def son():
            x = 3
            print(x)
        son()
    dad()
grandpa()

三、裝飾器

1、裝飾器

前面鋪墊了那么多,現(xiàn)在開(kāi)講正題:裝飾器 
先用高階函數(shù)實(shí)現(xiàn)給函數(shù)不修改源代碼的情況下添加功能

import time
def deco(func):
    start_time = time.time()
    func()
    stop_time = time.time()
    print("the func tun time is %s" %(stop_time-start_time))
def test1():
    time.sleep(1)
    print("in the test1")
def test2():
    time.sleep(1)
    print("in the test2")
deco(test1)
deco(test2)

按照上面說(shuō)的,如何實(shí)現(xiàn)不改變調(diào)用方式?直接“test1 = deco(test1)”和“test2 = deco(test2)”嗎? 
別忘記了,第二種方式,高階函數(shù)要加上return,如下

import time
def deco(func):
    start_time = time.time()
    return func()
    stop_time = time.time()
    print("the func tun time is %s" %(stop_time-start_time))
def test1():
    time.sleep(1)
    print("in the test1")
def test2():
    time.sleep(1)
    print("in the test2")
test1 = deco(test1)
test2 = deco(test2)
deco(test1)
deco(test2)

雖然沒(méi)有修改源代碼和調(diào)用方式,但是函數(shù)加上return,函數(shù)就結(jié)束了,然并卵。怎么實(shí)現(xiàn)呢? 
前面一直在用高階函數(shù),還沒(méi)有用嵌套函數(shù),加上嵌套函數(shù)能不能實(shí)現(xiàn)呢?看一下

import time
def timer(func):  # timer(test1)  func=test1
    def deco():
        start_time = time.time()
        func()
        stop_time = time.time()
        print("the func tun time is %s" %(stop_time-start_time))
    return deco  # 返回deco的內(nèi)存地址
def test1():
    time.sleep(1)
    print("in the test1")
def test2():
    time.sleep(1)
    print("in the test2")
print(timer(test1))  # 可見(jiàn):返回deco的內(nèi)存地址
test1 = timer(test1)
test1()
timer(test2)()

到此,完成實(shí)現(xiàn)了裝飾器的功能。但是還是有點(diǎn)麻煩,如何能不要“test1 = timer(test1)”, 
python解釋器提供了語(yǔ)法糖“@”符合,給哪個(gè)函數(shù)新增功能,就加在哪個(gè)函數(shù)頭部

import time
def timer(func):  # timer(test1)  func=test1
    def deco():
        start_time = time.time()
        func()
        stop_time = time.time()
        print("the func tun time is %s" %(stop_time-start_time))
    return deco  # 返回deco的內(nèi)存地址
@timer
def test1():
    time.sleep(1)
    print("in the test1")
@timer
def test2():
    time.sleep(1)
    print("in the test2")

test1()
test2()

2、有參裝飾器

前面實(shí)現(xiàn)了裝飾器的功能,但是如果函數(shù)有參數(shù),能不能也能運(yùn)行呢

import time
def timer(func):  # timer(test1)  func=test1
    def deco():
        start_time = time.time()
        func()
        stop_time = time.time()
        print("the func tun time is %s" %(stop_time-start_time))
    return deco  # 返回deco的內(nèi)存地址
@timer
def test1():
    time.sleep(1)
    print("in the test1")
@timer
def test2(name):
    time.sleep(1)
    print("in the test2",name)

test1()
test2()

報(bào)錯(cuò):丟失參數(shù)

TypeError: test2() missing 1 required positional argument: 'name'

@timer 相當(dāng)于 test2=timer(test2) =deco 
test2() 相當(dāng)于運(yùn)行deco(),所以沒(méi)指定參數(shù),報(bào)錯(cuò)。 
如何傳參數(shù)呢?為了適應(yīng)各種不同參數(shù)的函數(shù)

import time
def timer(func):  # timer(test1)  func=test1
    def deco(*args,**kwargs):
        start_time = time.time()
        func(*args,**kwargs)
        stop_time = time.time()
        print("the func tun time is %s" %(stop_time-start_time))
    return deco  # 返回deco的內(nèi)存地址
@timer
def test1():
    time.sleep(1)
    print("in the test1")
@timer
def test2(name):
    time.sleep(1)
    print("in the test2",name)

test1()
test2("fgf")

3、終極裝飾器

注意,上面的例子中還沒(méi)有涉及返回值,看下面的例子可以體會(huì)一下 
假設(shè):公司網(wǎng)站需要驗(yàn)證登錄,有不同的驗(yàn)證方式:本地認(rèn)證、LDAP認(rèn)證等

#/usr/bin/env python
# -*- coding: UTF-8 -*-
import time
user,passwd = 'fgf','abc123'
def auth(auth_type):
    print("auth func:",auth_type)
    def outer_wrapper(func):
        def wrapper(*args, **kwargs):
            print("wrapper func args:", *args, **kwargs)
            if auth_type == "local":
                username = input("Username:").strip()
                password = input("Password:").strip()
                if user == username and passwd == password:
                    print("\033[32;1mUser has passed authentication\033[0m")
                    res = func(*args, **kwargs)  # from home
                    print("---after authenticaion ")
                    return res
                else:
                    exit("\033[31;1mInvalid username or password\033[0m")
            elif auth_type == "ldap":
                print("搞毛線ldap,不會(huì)。。。。")

        return wrapper
    return outer_wrapper
def index():
    print("welcome to index page")
@auth(auth_type="local") # home = wrapper()
def home():
    print("welcome to home  page")
    return "from home"

@auth(auth_type="ldap")
def bbs():
    print("welcome to bbs  page")
index()
print(home()) #wrapper()
bbs()

到此這篇關(guān)于Python裝飾器詳細(xì)講解的文章就介紹到這了,更多相關(guān)Python裝飾器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論