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__)


分享到:


相關文章: