閉包函數必須知足兩個條件: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())
裝飾器:外部函數傳入被裝飾函數名,內部函數返回裝飾函數名。url
特色:1.不修改被裝飾函數的調用方式 2.不修改被裝飾函數的源代碼spa
在不修改主邏輯函數的狀況下,增長額外的功能 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
裝飾器裏增長參數,其實就是再無參裝飾器外層再套一層函數。
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
裝飾器不只能夠是函數,還能夠是類,相比函數裝飾器,類裝飾器具備靈活度大、高內聚、封裝性等優勢。使用類裝飾器主要依靠類的__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
@property、@staticmethod、@classmethod
待補充
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
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
待補充
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 # 用戶名或密碼錯誤,請從新登陸