閉包,裝飾器

#閉包python

內層函數對外層函數非全局變量的引用就叫閉包。閉包

判斷是否是閉包app

函數名.__closur__函數

返回NONE就不是閉包,返回cell就是閉包測試

閉包的做用spa

當執行一個函數時,若是解釋器判斷此韓式內部存在閉包,這樣python就有一個機制,閉包所在的臨時名稱空間不會隨着函數的執行完畢而關閉設計

def func1():
    name = '老男孩'

    def inner():
        print(name)
    inner()
    print(inner.__closure__)  0x0000000002856E10>

func1()


# <cell at 0x000000000282A768: str object at   閉包

#裝飾器blog

第一個版本class

 import  time效率

'''初版本,測試函數low'''
# def login():
#     time.sleep(0.3)
#     print('洗洗更健康...')
#
# def timmer():
#     start_time = time.time()
#     login()
#     end_time = time.time()
#     print('此函數的執行時間%s' % (end_time - start_time))
# timmer()

 

改變了我原來執行函數的執行方式,很差

 def login():
    time.sleep(0.3)
    print('洗洗更健康...')
# login()

def register():
    time.sleep(0.4)
    print('洗洗更健康22222...')
# register()
def timmer(f):
    start_time = time.time()
    f()
    end_time = time.time()
    print('此函數的執行時間%s' % (end_time - start_time))

timmer(login)
timmer(register)

 

雖然執行函數的方式已經無限接近於原方式,可是更麻煩了,增長了二步代碼,改

 

def login():
    time.sleep(0.3)
    print('洗洗更健康...')
# login()

def timmer(f):
    start_time = time.time()
    f()
    end_time = time.time()
    print('此函數的執行時間%s' % (end_time - start_time))

f1 = login  # 將login函數名給了f1
login = timmer  # 將timmer函數名給了login
login(f1)  # timmer(login)

 

#初級裝飾器

 

def login():
    time.sleep(0.3)
    print('洗洗更健康...')
# login()

def timmer(f):  # f = login函數名

    def inner():
        start_time = time.time()
        f()  # login()
        end_time = time.time()
        print('此函數的執行時間%s' % (end_time - start_time))
    return inner

login = timmer(login)  # inner 此login是新變量
login()  # inner()

 

  

 

#簡單版裝飾器,語法糖

 

def timmer(f):  # f = login函數名
    def inner():
        start_time = time.time()
        f()  # login()
        end_time = time.time()
        print('此函數的執行時間%s' % (end_time - start_time))
    return inner

@timmer  # login = timmer(login)  # inner 此login是新變量   @timmer就是語法糖
def login():
    time.sleep(0.3)
    print('洗洗更健康...')
login()

@timmer  # register = timmer(register)
def register():
    time.sleep(0.2)
    print('洗洗更健康22...')

login()  # inner()

 

 

#被裝飾的函數帶參數的裝飾器

 

def timmer(f):  # f = login函數名
    def inner(*args,**kwargs):  # args (2, 3)
        start_time = time.time()
        f(*args,**kwargs)  # login() *(2, 3) 2,3
        end_time = time.time()
        print('此函數的執行時間%s' % (end_time - start_time))
    return inner

@timmer  # login = timmer(login)  # inner 此login是新變量
def login(a,b):
    print(a,b)
    time.sleep(0.3)
    print('洗洗更健康...')

login(2,3)  # inner(2,3)

 

  

 

#函數帶返回值的裝飾器(萬能裝飾器)

 

def timmer(f):  # f = login函數名
    def inner(*args,**kwargs):  # args (2, 3)
        start_time = time.time()
        ret = f(*args,**kwargs)  # login() *(2, 3) 2,3
        end_time = time.time()
        print('此函數的執行時間%s' % (end_time - start_time))
        return ret
    return inner

@timmer  # login = timmer(login)  # inner 此login是新變量
def login(a,b):
    print(a,b)
    time.sleep(0.3)
    print('洗洗更健康...')
    return 666

print(login(2,3))  # inner(2,3)

 

  

 

 

 

def wrapper(f):
def inner(*args,**kwargs):
'''執行被裝飾函數以前的操做'''
ret = f(*args,**kwargs)
"""執行被裝飾函數以後的操做"""
return ret
return inner

裝飾器功能:在不改變原函數的基礎上,爲原函數增長一些額外的功能,log,登陸註冊等

 

#函數的有用信息

def login(username, password):
    """
    此函數須要用戶名,密碼兩個參數,完成的是登陸的功能。
    :return: True 登陸成功。 False登陸失敗。
    """
    # print(login.__name__)
    # print(login.__doc__)
    print('登陸成功...')
    return True

print(login.__name__)
print(login.__doc__)

#輸出:login

    此函數須要用戶名,密碼兩個參數,完成的是登陸的功能。
    :return: True 登陸成功。 False登陸失敗。

  

def wrapper(f):
    def inner(*args, **kwargs):
        print(f.__name__)
        print(f.__doc__)
        """執行函數以前的操做"""
        ret = f(*args, **kwargs)
        """執行函數以後的操做"""
        return ret
    return inner

@wrapper
def login(username, password):
    """
    此函數須要用戶名,密碼兩個參數,完成的是登陸的功能。
    :return: True 登陸成功。 False登陸失敗。
    """
    print('登陸成功...')
    return True
login(1, 2)

  引入一個模塊

from functools import wraps

def wrapper(f):
    @wraps(f)
    def inner(*args, **kwargs):
        """執行函數以前的操做"""
        ret = f(*args, **kwargs)
        """執行函數以後的操做"""
        return ret
    return inner

@wrapper
def login(username, password):
    """
    此函數須要用戶名,密碼兩個參數,完成的是登陸的功能。
    :return: True 登陸成功。 False登陸失敗。
    """
    a = 2
    c = 4
    print('登陸成功...')
    return True

print(login.__name__)
print(login.__doc__)

帶參數的裝飾器

 

import time


def timer_out(flag1):  #falg1 = flag
    def timer(f):
        def inner(*args, **kwargs):
            if flag1:
                start_time = time.time()
                time.sleep(0.3)
                ret = f(*args, **kwargs)
                end_time = time.time()
                print('執行效率%s' % (end_time-start_time))
                return ret
            else:
                ret = f(*args, **kwargs)
                return ret
        return inner
    return timer

flag = True        #若是不想裝飾,把TURE改爲False

@timer_out(flag)  # 1,步 timer_out(flag) == timer 2,@與timer結合,變成你熟悉的裝飾器 @timer
def func1():
    print(111)


@timer_out(flag)
def func2():
    print(222)


@timer_out(flag)
def func3():
    print(333)

func1()
func2()
func3()

#

111
執行效率0.3004300594329834
222
執行效率0.30065345764160156
333
執行效率0.3003878593444824

 

 局部只能引用全局的變量,不能修改,若是要修改,global。

count = 1

def func4():
    count = count + 1
    print(count)

func4()


#報錯,coun在局部沒有定義
# 子函數只能引用父函數的變量,不能修改,若是要修改,nonlocal。
def func4():

    count = 3
    def inner():
        nonlocal count
        count = count + 1
        print(count)
func4()

多個裝飾器裝飾一個函數

def wrapper1(func): # func = f函數名
    def inner1():
        print('wrapper1 ,before func')  # 2
        func()
        print('wrapper1 ,after func')  # 4
    return inner1


def wrapper2(func):  # func = inner1
    def inner2():
        print('wrapper2 ,before func')  # 1
        func()  # inner1()
        print('wrapper2 ,after func')  # 5
    return inner2

@wrapper2  # f = wrapper2(f) 裏面的f新變量 = inner1 外面的f最新變量 = inner2
@wrapper1  # f = wrapper1(f) 裏面的f函數名  外面的f新變量=inner1
def f():
    print('in f')  # 3

f()  # inner2()
'''
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
'''

開放封閉原則:

 

1.對擴展是開放的

 

    爲何要對擴展開放呢?

 

    咱們說,任何一個程序,不可能在設計之初就已經想好了全部的功能而且將來不作任何更新和修改。因此咱們必須容許代碼擴展、添加新功能。

 

  2.對修改是封閉的

 

    爲何要對修改封閉呢?

 

    就像咱們剛剛提到的,由於咱們寫的一個函數,頗有可能已經交付給其餘人使用了,若是這個時候咱們對其進行了修改,頗有可能影響其餘已經在使用該函數的用戶。

 

裝飾器完美的遵循了這個開放封閉原則。

相關文章
相關標籤/搜索