裝飾器

裝飾器

 

1、閉包

一、說明

閉包函數必須知足兩個條件:python

  1.函數內部定義的函數閉包

  2.包含對外部做用域而非全局做用域的引用app

閉包的特色:dom

  1.自帶做用域ide

  2.延遲計算函數

二、使用

z = 100
def outer():
    x = 2
    y = 3

    def inner():
        print("x = %s" % x)
        print("y = %s" % y)
        print("z = %s" % z)  # 先查找局部參數,沒有z,再查找全局參數。 print(inner.__closure__)  # 查看使用的函數內部參數
    return inner

ret = outer()
# 一共引用了2個局部參數x、y,下面是結果。z是全局參數。
# (<cell at 0x052A0FF0: int object at 0x569ED730>, <cell at 0x052AC090: int object at 0x569ED740>)
ret()  # 延遲執行
# x = 1
# y = 2
# z = 100
from urllib.request import urlopen

def index(url)
    def get()
        return urlopen(url).read()
    return get

python = index("http://www.python.org") # 返回的是get函數的地址
print(python()) # 執行get函數《而且將返回的結果打印出來
baidu = index("http://www.baidu.com")
print(baidu())
示例

 

2、裝飾器

裝飾器:外部函數傳入被裝飾函數名,內部函數返回裝飾函數名。url

特色:1.不修改被裝飾函數的調用方式 2.不修改被裝飾函數的源代碼spa

一、函數相關的裝飾器

(1)無參裝飾器

在不修改主邏輯函數的狀況下,增長額外的功能 code

原函數orm

def index():  # 主邏輯函數
    time.sleep(random.randrange(1, 3))
    print("welcome to index page")

index()
# welcome to index page

方法1.定義額外的函數,在函數內部引用原函數。但函數的使用方法改變了,不可取。

import time, random

def index2(x):  # 主邏輯函數
    time.sleep(random.randrange(1, 3))
    print("welcome to index2 page")
    return "index2的返回值x:%s" % x

def timer(*args, **kwargs):
    start = time.time()
    my_func = index2(*args, **kwargs)
    end = time.time()
    print("主邏輯耗時:%s 秒" % (end - start))
    return my_func

ret = timer(10)  # 使用方法改變了
print(ret)
# welcome to index2 page
# 主邏輯耗時:1.0005226135253906 秒
# index2的返回值x:10

方法2.裝飾器,函數的使用方法不變

import time, random

def timer(func):
    def wrapper(*args,**kwargs):
        start = time.time()
        my_func = func(*args,**kwargs)
        end = time.time()
        print("主邏輯耗時:%s 秒" % (end-start))
        return my_func
    return wrapper

@timer
def index1(x):  # 主邏輯函數
    time.sleep(random.randrange(1, 3))
    print("welcome to index1 page")
    return "index1的返回值x:%s" % x

def index2(x):  # 主邏輯函數
    time.sleep(random.randrange(1, 3))
    print("welcome to index2 page")
    return "index2的返回值x:%s" % x

ret = index1(10)  # 使用裝飾器
print(ret)
# welcome to index1 page
# 主邏輯耗時:2.0000548362731934 秒
# index1的返回值x:10

ret = timer(index2)(10)  # 等價於上面index1
print(ret)
# welcome to index2 page
# 主邏輯耗時:1.0003700256347656 秒
# index2的返回值x:10

(2)有參裝飾器

 裝飾器裏增長參數,其實就是再無參裝飾器外層再套一層函數。

import time,random

def timer(*args_timer,**kwargs_timer):  # 在無參裝飾器外層增長一層有參函數
    def outer(func):  # 與上面無參裝飾器同樣的使用
        def inner(*args_inner,**kwargs_inner):
            start = time.time()
            ret = func(*args_inner,**kwargs_inner)
            end = time.time()
            print("裝飾器的參數0:%s" % args_timer[0])  # 增長的裝飾器參數,根據實際狀況使用
            print("主邏輯耗時:%s 秒" % (end - start))
            return ret
        print("裝飾器的參數1:%s" % args_timer[1])  # 增長的裝飾器參數,根據實際狀況使用
        return inner
    print("裝飾器的參數2:%s" % args_timer[2])  # 增長的裝飾器參數,根據實際狀況使用
    return outer

@timer(
"timer0","timer1","timer2") def index3(x): # 主邏輯函數 time.sleep(random.randrange(1, 3)) print("welcome to index3 page") return "index3的返回值x:%s" % x
ret
= index3(100) print(ret) # 裝飾器的參數2:timer2 # 裝飾器的參數1:timer1 # welcome to index3 page # 裝飾器的參數0:timer0 # 主邏輯耗時:2.000260829925537 秒 # index3的返回值x:100 ################################################################################## def index4(x): # 主邏輯函數 time.sleep(random.randrange(1, 3)) print("welcome to index4 page") return "index4的返回值x:%s" % x ret = timer("timer0","timer1","timer2")(index4)(100) # 至關於上面使用了有參裝飾器的index3 print(ret) # 裝飾器的參數2:timer2 # 裝飾器的參數1:timer1 # welcome to index4 page # 裝飾器的參數0:timer0 # 主邏輯耗時:2.000366449356079 秒 # index4的返回值x:100

二、類相關的裝飾器

(1)裝飾器是類

  裝飾器不只能夠是函數,還能夠是類,相比函數裝飾器,類裝飾器具備靈活度大、高內聚、封裝性等優勢。使用類裝飾器主要依靠類的__call__方法,當使用 @ 形式將裝飾器附加到函數上時,就會調用此方法。

class Foo(object):
    def __init__(self, func):
        self._func = func

    def __call__(self):
        print('類裝飾器 runing')
        self._func()
        print('類裝飾器 ending')


@Foo # bar = Foo(bar)
def bar():
    print('bar')


bar() # Foo(bar)()

# 結果
# 類裝飾器 runing
# bar
# 類裝飾器 ending

(2)類自帶的裝飾器

@property、@staticmethod、@classmethod

待補充

 

(3)讓類做爲裝飾器的參數

class MyClass(object):

    @staticmethod
    def clsfunc1():
        print("MyClass的func1使用(是staticmethod,不用實例化對象)")

    @staticmethod
    def clsfunc2():
        print("MyClass的func2使用(是staticmethod,不用實例化對象)")


def deco(cls):
    """使用類的staticmethod,"""
    def outer2(func):
        def outer1(*args,**kwargs):
            cls.clsfunc1()
            ret = func(*args,**kwargs)
            cls.clsfunc2()
            return ret
        return outer1
    return outer2


@deco(MyClass)  # 對函數使用
def myfunc(x):
    print(" myfunc() called.")
    return x

ret = myfunc(100)
print(ret)
# MyClass的func1使用(是staticmethod,不用實例化對象)
#  myfunc() called.
# MyClass的func2使用(是staticmethod,不用實例化對象)
# 100

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

class Foo(object):

    @deco(MyClass)  # 跟函數同樣,可以使用多個裝飾器
    def run(self,x):
        print("Foo is running")
        return x
foo = Foo()
ret = foo.run(999)
print(ret)
# MyClass的func1使用(是staticmethod,不用實例化對象)
# Foo is running
# MyClass的func2使用(是staticmethod,不用實例化對象)
# 999

(4)對整個類進行裝飾(後續再擴展,涉及到__init__,__new__)

def deco(func):
    def wrapper(*args, **kwargs):
        print('before')
        ret = func(*args, **kwargs)
        print('after')
        return ret
    return wrapper


@deco
class Person:
    def __new__(cls, *args, **kwargs):  # 在類__init__先進行__new__
        print('__new__')
        return args,kwargs


ret = Person(123,123,x=2)
print(ret)
# before
# __new__
# after
# ((123, 123), {'x': 2})

 

四、使用多個裝飾器

 多層裝飾器

def outer1(func):
    def wrapper(*args,**kwargs):
        print("無參裝飾器outer1")
        ret = func(*args,**kwargs)
        return ret
    return wrapper

def outer2(func):
    def wrapper(*args,**kwargs):
        print("無參裝飾器outer2")
        ret = func(*args,**kwargs)
        return ret
    return wrapper


def outer3(x,y,z):
    def wrapper2(func):
        def wrapper1(*args, **kwargs):
            print("有參裝飾器outer3")
            print("x:{},y:{},z:{}".format(x,y,z))
            ret = func(*args, **kwargs)
            return ret
        return wrapper1
    return wrapper2

@outer3(1,2,3)  # 3.把outer2套在裏面  tmp3 = outer3(1,2,3)(tmp2)
@outer2  # 2.把outer1套在裏面  tmp2 = outer2(tmp1)
@outer1  # 1.優先把index5套在裏面 tmp1 = outer(index5)
def index5(x):
    print("主邏輯函數index5")
    return "index5的返回值x:%s" % x


ret = index5(100)
print(ret)
# 有參裝飾器outer3
# x:1,y:2,z:3
# 無參裝飾器outer2
# 無參裝飾器outer1
# 主邏輯函數index5
# index5的返回值x:100

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

def index5(x):
    print("主邏輯函數index5")
    return "index5的返回值x:%s" % x

ret = outer3(1,2,3)(outer2(outer1(index5)))(100)
print(ret)
# 有參裝飾器outer3
# x:1,y:2,z:3
# 無參裝飾器outer2
# 無參裝飾器outer1
# 主邏輯函數index5
# index5的返回值x:100

 四、其餘(待補充)

待補充

3、示例

 一、登陸

def index1():
    print("歡迎來到購物系統")
    print("消費100元")
    print("明天到貨")
    return None

index1()
# 歡迎來到購物系統
# 消費100元
# 明天到貨

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

def auth(func):
    def wrapper(*args,**kwargs):
        user = input("用戶名>>:")
        password = input("密碼>>:")
        if user == "abc" and password == "123":
            ret = func(*args,**kwargs)
            return ret
        else:
            print("用戶名或密碼錯誤,請從新登陸")
    return wrapper

@auth
def index2():
    print("歡迎來到購物系統")
    print("消費100元")
    print("明天到貨")
    return None

index2()
# 用戶名>>:abc
# 密碼>>:123
# 歡迎來到購物系統
# 消費100元
# 明天到貨

#
# 用戶名>>:asdfsdf
# 密碼>>:sdfsdf
# 用戶名或密碼錯誤,請從新登陸
相關文章
相關標籤/搜索