
一 有參裝飾器
>帶有參數的函數裝飾器
為被裝飾對象添加認證功能的裝飾器,實現的基本形式如下
def deco(func):def wrapper(*args,**kwargs):編寫基于文件的認證,認證通過則執行res=func(*args,**kwargs),并返回resreturn wrapper
如果想提供多種不同的認證方式以供選擇,單從wrapper函數的實現角度改寫如下
def auth(func,db_type):def wrapper(*args, **kwargs):name=input('your name>>>: ').strip()pwd=input('your password>>>: ').strip()if db_type == 'file':print('基于文件的驗證')if name == 'egon' and pwd == '123':res = func(*args, **kwargs)return reselse:print('user or password error')elif db_type == 'mysql':print('基于mysql的驗證')elif db_type == 'ldap':print('基于ldap的驗證')else:print('不支持該db_type')return wrapper
函數wrapper需要一個driver參數,而函數deco與wrapper的參數都有其特定的功能,不能用來接受其他類別的參數,可以在deco的外部再包一層函數auth,用來專門接受額外的參數,這樣便保證了在auth函數內無論多少層都可以引用到
def auth(db_type):def deco(func):def wrapper(*args, **kwargs):name = input('your name>>>: ').strip()pwd = input('your password>>>: ').strip()if db_type == 'file':print('基于文件的驗證')if name == 'egon' and pwd == '123':res = func(*args, **kwargs) # index(1,2)return reselse:print('user or password error')elif db_type == 'mysql':print('基于mysql的驗證')elif db_type == 'ldap':print('基于ldap的驗證')else:print('不支持該db_type')return wrapperreturn deco
想要保留原函數的文檔和函數名屬性,需要修正裝飾器
def timer(func):def wrapper(*args,**kwargs):start_time=time.time()res=func(*args,**kwargs)stop_time=time.time()print('run time is %s' %(stop_time-start_time))return reswrapper.__doc__=func.__doc__wrapper.__name__=func.__name__return wrapper
上述方式來實現保留原函數屬性過于麻煩,functools模塊下提供一個裝飾器wraps專門用來
from functools import wrapsdef timer(func):@wraps(func)def wrapper(*args,**kwargs):start_time=time.time()res=func(*args,**kwargs)stop_time=time.time()print('run time is %s' %(stop_time-start_time))return resreturn wrapper
>帶有參數的類裝飾器
#參數1 : 給修飾的類添加成員屬性和方法
#參數2 : 給類中的run方法變成屬性class Kuozhan():ad = "我是屬性"def char(self):print("我是方法")def __init__(self,num):self.num = numdef __call__(self,cls):print(cls)if self.num == 1:return self.kuozhan1(cls)elif self.num == 2:return self.kuozhan2(cls)#參數1的情況:添加成員屬性和方法def kuozhan1(self,cls):def newfunc():cls.ad = Kuozhan.adcls.money = Kuozhan.moneyreturn cls()return newfunc#參數2的情況:把方法變成屬性def kuozhan2(self,cls):def newfunc():if "run" in cls.__dict__:cls.run = cls.run()return cls()return newfunc
#
@Kuozhan(1)
class MyClass():def run():return "運動"
obj = MyClass()
print(obj.ad)
obj.money()#
@Kuozhan(2)
class MyClass():def run():return "運動"
obj = MyClass()
print(obj.run)
>property
可以把方法變成屬性 : 可以動態的控制屬性的獲取,設置,刪除相關操作
@property 獲取屬性
@方法名.setter 設置屬性
@方法名.deleter 刪除屬性
class MyClass():def __init__(self,name):self.name = name@propertydef username(self):return self.name@username.setterdef username(self,val):self.name = valpass@username.delsterdef username(self):def self.namepass
obj = MyClass("小紅")
獲取指的時候自動觸發@property 裝飾器下的方法
res = obj.username
print(res)#設置值的時候自動觸發@username.setter裝飾器下的方法
obj.username = "小白"
print(obj.username)
class Myclass():def __init__(self,name):self.name = name #獲取數據def get_username(self):return self.name#設置數據def set_username(self,val):self.name = val#刪除數據def del_username(self):del self.name#參數的順序:獲取,設置,刪除username = property(get_username, set_username, del_username)obj = MyClass("小白")
#獲取值的時候,執行get_username下的相關操作
print(obj.username)
#設置值的時候,執行set_username下的相關操作
print(obj.username)
#刪除值的時候,執行del_username下的相關操作
del obj.username
print(obj.username)
二 迭代器
1、什么是迭代器
迭代器指的是迭代取值的工具,迭代是一個重復的過程,每次重復
都是基于上一次的結果而繼續的,單純的重復并不是迭代
2、為何要有迭代器
迭代器是用來迭代取值的工具,而涉及到把多個值循環取出來的類型
有:列表、字符串、元組、字典、集合、打開文件
l=['egon','liu','alex']i=0while i < len(l):print(l[i])i+=1
上述迭代取值的方式只適用于有索引的數據類型:列表、字符串、元組
為了解決基于索引迭代器取值的局限性
python必須提供一種能夠不依賴于索引的取值方式,這就是迭代器
3、如何用迭代器
1、可迭代的對象
從語法形式上講,內置有__iter__方法的對象都是可迭代對象,字符串、列表、元組、字典、集合、打開的文件都是可迭代對象
2、調用可迭代對象下的__iter__方法會將其轉換成迭代器對象
3、可迭代對象與迭代器對象詳解
可迭代對象("可以轉換成迭代器的對象"):內置有__iter__方法對象
可迭代對象.__iter__(): 得到迭代器對象
迭代器對象:內置有__next__方法并且內置有__iter__方法的對象
迭代器對象.__next__():得到迭代器的下一個值
迭代器對象.__iter__():得到迭代器的本身
4、可迭代對象:字符串、列表、元組、字典、集合、文件對象
迭代器對象:文件對象
5、for循環的工作原理:for循環可以稱之為叫迭代器循環,in后可以跟任意可迭代對象
1、d.__iter__()得到一個迭代器對象
2、迭代器對象.__next__()拿到一個返回值,然后將該返回值賦值給k
3、循環往復步驟2,直到拋出StopIteration異常for循環會捕捉異常然后結束循環
6、迭代器優缺點總結
6.1 優點:
I、為序列和非序列類型提供了一種統一的迭代取值方式。
II、惰性計算:迭代器對象表示的是一個數據流,可以只在需要時才去調用next來計算出一個值,就迭代器本身來說,同一時刻在內存中只有一個值,因而可以存放無限大的數據流,而對于其他容器類型,如列表,需要把所有的元素都存放于內存中,受內存大小的限制,可以存放的值的個數是有限的。
6.2 缺點:
I、除非取盡,否則無法獲取迭代器的長度
II、只能取下一個值,不能回到開始,更像是‘一次性的’,迭代器產生后的唯一目標就是重復執行next方法直到值取盡,否則就會停留在某個位置,等待下一次調用next;若是要再次迭代同個對象,你只能重新調用iter方法去創建一個新的迭代器對象,如果有兩個或者多個循環使用同一個迭代器,必然只會有一個循環能取到值。
三 生成器
如何得到自定義的迭代器:
在函數內一旦存在yield關鍵字,調用函數并不會執行函數體代碼
會返回一個生成器對象,生成器即自定義的迭代器
def func():print('第一次')yield 1print('第二次')yield 2print('第三次')yield 3print('第四次')觸發函數體代碼的運行,然后遇到yield停下來,將yield后的值
當做本次調用的結果返回
res1=g.__next__()
print(res1)