一、裝飾器 裝飾器本質就是一個python函數,它可以讓其他函數在不需要做任何代碼變動的前提下,增加額外的功能,裝飾器的返回值也是一個函數對象。裝飾器的應用場景:插入日誌,性能測試,事務處理,緩存等場景 二、裝飾器的形成過程 現在有個需求,想讓你測試這個函數的執行時間,在不改變這個函數的情況下。 1 ...
一、裝飾器
裝飾器本質就是一個python函數,它可以讓其他函數在不需要做任何代碼變動的前提下,增加額外的功能,裝飾器的返回值也是一個函數對象。裝飾器的應用場景:插入日誌,性能測試,事務處理,緩存等場景
二、裝飾器的形成過程
現在有個需求,想讓你測試這個函數的執行時間,在不改變這個函數的情況下。
1,簡單版裝飾器
import time def fun(): time.sleep(2) print('你好啊') def test(f): def inner(): start_time=time.time() f() end_time=time.time() print(end_time-start_time) return inner fun=test(fun) #這個版本的雖然可以實現任何功能的測試,但每次函數執行前都得寫上這一句很是麻煩 fun()
2,語法糖
import time def fun(): time.sleep(2) print('你好啊') def test(f): def inner(): start_time=time.time() f() end_time=time.time() print(end_time-start_time) return inner @test #相當於fun=test(fun),只是裡面封裝好了的,以後測試函數就不用寫fun=test(fun),只需要在定義函數上面寫上@test就行 fun()
上面的裝飾器裝飾的函數都沒有參數,下麵裝飾一個帶參數的裝飾器。
3,裝飾帶參數的函數
import time def test(f): def inner(*args,**kwargs): start_time=time.time() f(*args,**kwargs) end_time=time.time() print(end_time-start_time) return inner @test def fun(): time.sleep(2) print('你好啊')
4,裝飾帶參數和有返回值的函數
import time def test(f): def inner(*args,**kwargs): start_time=time.time() res=f(*args,**kwargs) end_time=time.time() print(end_time-start_time) return res return inner @test def fun1(a,s,d,f): return a+s+d+f
對於上面的裝飾器來說,如果我要看函數的信息,比如fun.__doc__查看函數註釋的方法,fun.__name__查看函數名,由於加上裝飾器後fun=inner,所以結果會有錯誤。下麵解決
5,可以查看函數信息的裝飾器
import time from functools import wraps def test(f): @wraps(f) def inner(*args,**kwargs): start_time=time.time() res=f(*args,**kwargs) end_time=time.time() print(end_time-start_time) return res return inner @test def fun1(a,s,d,f): return a+s+d+f
三、裝飾器主要功能和固定結構
1,固定寫法
def timer(func): def inner(*args,**kwargs): '''執行函數之前要做的''' re = func(*args,**kwargs) '''執行函數之後要做的''' return re return inner
2,可以查看函數信息的
from functools import wraps def deco(func): @wraps(func) #加在最內層函數正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper
四、帶參數的裝飾器(是裝飾器袋參數)
比如說之前要求你為10個函數加上裝飾,你得在每個函數上面寫上@;一個月之後,不需要裝飾器了,你又要把每個函數上的@給去掉;沒過多久又讓你加上裝飾器;反覆添加,反覆刪除,這可是10萬個函數,很龐大的工程。其實現在給裝飾器加一個參數,很輕鬆就解決問題。
import time def outer(flg): def test(f): def inner(*args,**kwargs): if flg: start_time=time.time() res=f(*args,**kwargs) if flg: end_time=time.time() print(end_time-start_time) return res return inner return test flg=True #flg為True時加上裝飾器,為False時不加裝飾器 @outer(flg) def fun1(a,s,d,f): return a+s+d+f r=fun1(2,3,4,5) print(r)
五、多個裝飾器裝飾一個函數
def wrapper1(func): func=f def inner1(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return inner1 def wrapper2(func): func=inner1 def inner2(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner2 @wrapper2 #f=wrapper2(f),現在後面的f已經變為inner1,f=inner2 @wrapper1 #f=wrapper1(f),f=inner1 def f(): print('in f') f() #此時f為inner2
所以結果為:
wrapper2,before func
wrapper1,before func
in f
wrapper1,after func
wrapper2,after func
六、單例模式
單例模式就是一個類只能產生一個對象,就算產生多個對象,多個對象都是指向同一地址
方法一:用__new__
class Person: __status=None def __new__(cls, *args, **kwargs): if not Person.__status: Person.__status=object.__new__(Person) return Person.__status ob1=Person() ob2=Person() print(ob1) print(ob2)
方法二:使用模塊
python的模塊就是天然的單例模式,因為模塊在第一次導入時,會生成.pyc文件,當第二次導入時,就會直接載入.pyc文件,而不會再次執行模塊代碼。因此,我們只需要把相關的函數和數據定義在一個模塊中,就可以獲得一個單例對象了。如果我們真的想要一個單例類,可以如下:
mysingleton.py
class Singleton(object): def foo(self): pass singleton = Singleton()
要使用時,直接在其他文件中導入此文件中的對象,這個對象就是一個單例模式的對象
from mysingleton.py import singleton
方法三:使用裝飾器
def Singleton(cls): _instance = {} def _singleton(*args, **kargs): if cls not in _instance: _instance[cls] = cls(*args, **kargs) return _instance[cls] return _singleton @Singleton class A(object): a = 1 def __init__(self, x=0): self.x = x a1 = A(2) a2 = A(3) #後面不管你給的參數是多少,都不會再執行了,只會把a1對象返回給他
方法四:使用類
class Singleton(object): def __init__(self): pass @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance
這種情況下,含有io的多線程就會有問題,當前面的對象還沒創建成功,後面的線程就開始,not hasattr(Singleton,'_instance')也為真,所以,第二個線程也會重新創建一個對象,從而就不是一個對象,就不是單例模式。解決辦法是加鎖。加鎖的部分串列執行,沒加鎖部分併發執行。
import time import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): time.sleep(1) @classmethod def instance(cls, *args, **kwargs): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance def task(arg): obj = Singleton.instance() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start() time.sleep(20) obj = Singleton.instance() print(obj)
方法五:基於metaclass方式實現
相關知識:
""" 1.類由type創建,創建類時,type的__init__方法自動執行,類() 執行type的 __call__方法(類的__new__方法,類的__init__方法) 2.對象由類創建,創建對象時,類的__init__方法自動執行,對象()執行類的 __call__ 方法 """ class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): pass obj = Foo() # 執行type的 __call__ 方法,調用 Foo類(是type的對象)的 __new__方法,用於創建對象,然後調用 Foo類(是type的對象)的 __init__方法,用於對對象初始化。 obj() # 執行Foo的 __call__ 方法
元類的使用:
class SingletonType(type): def __init__(self,*args,**kwargs): super(SingletonType,self).__init__(*args,**kwargs) def __call__(cls, *args, **kwargs): # 這裡的cls,即Foo類 print('cls',cls) obj = cls.__new__(cls,*args, **kwargs) cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj) return obj class Foo(metaclass=SingletonType): # 指定創建Foo的type為SingletonType def __init__(self,name): self.name = name def __new__(cls, *args, **kwargs): return object.__new__(cls) obj = Foo('xx')
實現單例模式:
import threading class SingletonType(type): _instance_lock = threading.Lock() def __call__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): with SingletonType._instance_lock: if not hasattr(cls, "_instance"): cls._instance = super(SingletonType,cls).__call__(*args, **kwargs) return cls._instance class Foo(metaclass=SingletonType): def __init__(self,name): self.name = name obj1 = Foo('name') obj2 = Foo('name') print(obj1,obj2)