描述符
描述符本質就是一個新式類,在這個新式類中,至少實現了__get__(),__set__(),__delete__()中的一個,也被稱為描述符協議,主要用戶描述類屬性,用在一個新式類調用的一個類的時候;
__get__():調用一個屬性時觸發;
__set__():為一個屬性賦值時觸發;
__delete__():採用del刪除屬性時觸發;
作用
描述符的作用是用來代理另一個類的屬性的(必須把描述符定義成這個類的類屬性,不能定義到構造函數中)
示例(自己在調用的時候是不會執行的,只有在別的類調用的時候才會觸發)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo:
def __get__(self, instance, owner):
print('get')
def __set__(self, instance, value):
print('set')
def __delete__(self, instance):
print('delete')
f1=Foo()
f1.name='cce'
print(f1.name)
del f1.name
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo:
def __get__(self, instance, owner):
print('get')
def __set__(self, instance, value):
print('set')
def __delete__(self, instance):
print('delete')
class Bar:
x=Foo()
y=1
b1=Bar()
b1.x
del b1.x
b1.x=2
# 結果 只有別的類在調用我們的類的時候才會觸發描述符
# get
# delete
# set
描述符分為兩種
1、數據描述符:至少實現了__get__()和__set__()
class Foo:
def __get__(self, instance, owner):
print('get')
def __set__(self, instance, value):
print('set')
2、非數據描述符:沒有實現__set__()
class Foo:
def __get__(self, instance, owner):
print('get')
注意
1、描述符本身應該定義成新式類,被代理的類也應該是新式類;
2、必須把描述符定義成這個類的類屬性,不能定義到構造函數中__init__;
3、嚴格遵守該優先級,優先級由高到低;
1、類屬性
2、數據描述符
3、實例屬性
4、非數據描述符
5、找不到的屬性觸發__getattr__()
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo:
def __get__(self, instance, owner):
print('get')
def __set__(self, instance, value):
print('set')
instance.__dict__['x']=value
def __delete__(self, instance):
print('delete')
class Bar:
x=Foo()
def __init__(self,name):
self.x=name
b1=Bar('cce')
print(b1.__dict__)
# 此處用文件描述符去處理x,一旦有關x的操作都由Foo代理
# set
# {'x': 'cce'}
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo:
def __get__(self, instance, owner):
print('====>get')
def __set__(self, instance, value):
print('====>set')
# instance.__dict__['x']=value
def __delete__(self, instance):
print('====>delete')
class Bar:
x=Foo()
Bar.x=1
print(Bar.x) # 此處打印的是1,說明當執行Bar.x=1的時候就給x重新賦值,此處也驗證的類屬性高於描述符的優先級,實際上就是底層字典的一個覆蓋操作
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo:
def __get__(self, instance, owner):
print('====>get')
def __set__(self, instance, value):
print('====>set')
# instance.__dict__['x']=value
def __delete__(self, instance):
print('====>delete')
class Bar:
x=Foo()
b1=Bar()
b1.x=2 #此處觸發的是====>set,由此可以看出實例屬性的優先級低於描述符的優先級
print(b1.x) #此處觸發的是====>get,由此可以看出實例屬性的優先級低於描述符的優先級
實例屬性和非數據描述符
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo:
def __get__(self, instance, owner):
print('====>get')
class Bar:
x=Foo()
b1=Bar()
b1.x =1
print(b1.__dict__) # 此處說明實例屬性和非數據描述符實例屬性的優先級更高
利用描述符限定用戶輸入的類型為字符串
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 利用描述符添加類型檢測
class Typed:
def __init__(self,key):
self.key=key
def __get__(self, instance, owner):
print(instance.__dict__[self.key])
return '獲取成功'
def __set__(self, instance, value):
if not isinstance(value,str):
print('輸入錯誤,賦值不成功,僅接受字符串類型')
return
instance.__dict__[self.key]=value
print('賦值成功')
def __delete__(self, instance):
del instance.__dict__[self.key]
return '刪除成功'
class People():
name=Typed('name')
def __init__(self,name,age):
self.name=name
self.age=age
p1=People('cce',18)
print(p1.__dict__)
p1.name=18
print(p1.__dict__)
# 執行結果
# 賦值成功
# {'name': 'cce', 'age': 18}
# 輸入錯誤,賦值不成功,僅接受字符串類型
# {'name': 'cce', 'age': 18}
修訂版
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
class Typed:
def __init__(self,key,type):
self.key=key
self.type=type
def __get__(self, instance, owner):
print(instance.__dict__[self.key])
return '獲取成功'
def __set__(self, instance, value):
if not isinstance(value,self.type):
raise TypeError('輸入錯誤,傳入的內容不是【%s】' %self.type)
return
instance.__dict__[self.key]=value
print('賦值成功')
def __delete__(self, instance):
del instance.__dict__[self.key]
return '刪除成功'
class People():
name=Typed('name',str)
age=Typed('age',int)
def __init__(self,name,age):
self.name=name
self.age=age
p1=People('cce',18)
print(p1.__dict__)
p1.name=18
p1.age='18'
print(p1.__dict__)
# 執行結果
# Traceback (most recent call last):
# File "C:/Users/Centos/Desktop/python/func.py", line 30, in <module>
# p1.name=18
# File "C:/Users/Centos/Desktop/python/func.py", line 13, in __set__
# raise TypeError('輸入錯誤,傳入的內容不是【%s】' %self.type)
# TypeError: 輸入錯誤,傳入的內容不是【<class>】/<class>
# 賦值成功
# 賦值成功
# {'name': 'cce', 'age': 18}
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Typed:
def __init__(self,key,type): # key 用來接受字典的key,也就是傳入變量名。type用於接受用戶傳入該變量規定的類型
self.key=key
self.type=type
def __get__(self, instance,owner):
return instance.__dict__[self.key] # 當執行set操作的時候(包括實例化)會將該屬性直接插入實例屬性字典
def __set__(self, instance, value):
if isinstance(value,self.type): # 如果傳入的類型是self.type的類型那麼就插入實例字典
instance.__dict__[self.key]=value
else:
raise TypeError('類型錯誤') # 如果傳入的類型不是self.type的類型那麼就拋出TypeError
def __delete__(self, instance):
return instance.__dict__.pop(self.key) # 當執行del操作的時候,在實例屬性字典中將這個屬性給pop刪除掉
class People:
name=Typed('name',str) # 表示name屬性被描述符類代理
age=Typed('age',int) # 表示age屬性被描述符類代理
def __init__(self,name,age):
self.name=name
self.age=age
p1=People('cce',18)
print(p1.__dict__)
閱讀更多 動漫資深愛好者和IT 的文章