11、描述符基礎

描述符

描述符本質就是一個新式類,在這個新式類中,至少實現了__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__)


分享到:


相關文章: