python之路(11)描述符
阿新 • • 發佈:2018-12-01
前言
描述符是用於代理另一個類的屬性,一般用於大型的框架中,在實際的開發專案中較少使用,本質是一個實現了__get__(),__set__(),__delete__()其中一個方法的新式類
__get__():呼叫一個屬性時執行
__set__():屬性賦值時執行
__delete__():採用del刪除屬性時觸發
示例
#描述符 class test: def __get__(self, instance, owner): print('---get方法') def __set__(self, instance, value): print('---set方法') def __delete__(self, instance): print('---delete方法') class test2: name = test()#描述符代理了test2類裡的name屬性 t1 = test2() #呼叫了被描述符代理的屬性,執行__get__()方法 t1.name #---get方法 #賦值了被描述符代理的屬性,執行__set__()方法 t1.name = 1 #---set方法 #賦值了被描述符代理的屬性,執行__delete__()方法 del t1.name #---delete方法
屬性查詢的優先順序
1.類屬性
2.資料描述符(同時實現了__get__()和__set__()方法)
3.例項屬性
4.非資料描述符(沒有實現__set__()方法)
5.找不到的屬性執行__getattr__()
#非資料描述符 class test: def __get__(self, instance, owner): print('get方法') class test2: name = test()#描述符代理了test2類裡的name屬性 t1 = test2() #在例項物件裡中建立了name屬性,並賦值chen t1.name= 'chen' print(t1.__dict__) #{'name': 'chen'}
利用描述符實現賦值型別限制(一)
#資料描述符 class Typed: def __init__(self,key,value_type): self.key = key self.value_type = value_type def __get__(self, instance, owner): print('get方法') return instance.__dict__[self.key] def __set__(self, instance, value): print('set方法') if not isinstance(value,self.value_type): #判斷型別 raise TypeError('傳入的型別不是',self.value_type) instance.__dict__[self.key] = value def __delete__(self, instance): print('delete方法') instance.__dict__.pop(self.key) class People: name = Typed('name',str) #資料描述符代理屬性 age = Typed('age',int) #資料描述符代理屬性 def __init__(self,name,age): self.name = name #賦值操作,執行__set__方法 self.age = age #測試 p1 = People('chen',21) print(p1.__dict__) #{'name': 'chen', 'age': 21} p1 = People('chen','21') #報錯:TypeError: ('傳入的型別不是', <class 'int'>)
利用描述符和裝飾器實現賦值型別限制(二)
#資料描述符 class Typed: def __init__(self,key,value_type): self.key = key self.value_type = value_type def __get__(self, instance, owner): print('get方法') return instance.__dict__[self.key] def __set__(self, instance, value): print('set方法') if not isinstance(value,self.value_type): #判斷型別 raise TypeError('傳入的型別不是',self.value_type) instance.__dict__[self.key] = value def __delete__(self, instance): print('delete方法') instance.__dict__.pop(self.key) #限制賦值型別的裝飾器 def deco(**kwargs): def warapper(obj): for key,val in kwargs.items(): setattr(obj,key,Typed(key,val)) #在裝飾器中給類屬性實現描述符代理 return obj return warapper @deco(name=str,age=int) #@wrapper ===>People=wrapper(People) class People: #使用裝飾器取代了以下兩步 # name = Typed('name',str) #資料描述符代理屬性 # age = Typed('age',int) #資料描述符代理屬性 def __init__(self,name,age): self.name = name #賦值操作,執行__set__方法 self.age = age #測試 p1 = People('chen',21) ''' 輸出: set方法 set方法 ''' print(p1.__dict__) #{'name': 'chen', 'age': 21}
描述符實現@property
class Demoproperty: def __init__(self,func): print('----+') self.func = func class People: def __init__(self,name,age): self.name = name #賦值操作,執行__set__方法 self.age = age @Demoproperty #eat=Demoproperty(eat) def eat(self): print("%s在吃飯"%self.name) p1 =People('chen',21) p1.eat.func(p1) #chen在吃飯瞎搞
#非資料描述符
class Demoproperty:
def __init__(self,func):
self.func = func
def __get__(self, instance, owner):
print('get')
res = self.func(instance)
return res
class People:
def __init__(self,name,age):
self.name = name #賦值操作,執行__set__方法
self.age = age
#實現了新增描述符的操作
@Demoproperty #eat=Demoproperty(eat)
def eat(self):
print("%s在吃飯"%self.name)
p1 =People('chen',21)
p1.eat #chen在吃飯
描述符實現@calssmethod
classmethod 修飾符對應的函式不需要例項化,不需要 self 引數,但第一個引數需要是表示自身類的 cls 引數,可以來呼叫類的屬性,類的方法,例項化物件等
class ClassMethod: def __init__(self,func): self.func=func def __get__(self, instance, owner): #owner是類 def feedback(*args,**kwargs): return self.func(owner,*args,**kwargs) return feedback #返回一個可以傳參的方法 class People: @ClassMethod # say_hi=ClassMethod(say_hi) def say_hi(cls,name,age): print('我是%s,年齡%s' %(name,age)) People.say_hi('chen',21) #我是chen,年齡21
描述符實現@staticmethod
class StaticMethod: def __init__(self,func): self.func=func def __get__(self, instance, owner): #owner是類 def feedback(*args,**kwargs): return self.func(*args,**kwargs) return feedback #返回一個可以傳參的方法 class People: @StaticMethod # say_hi=ClassMethod(say_hi) def say_hi(name,age): print('我是%s,年齡%s' %(name,age)) People.say_hi('chen',21) #我是chen,年齡21