1.什么是描述符:
描述符就是一个类中重写了__get__,__set__,__delete__三个方法中任意一个,那么它就是一个描述符类。
1.1 __get__,再调用该描述符实例化的对象时自动运行。
1.2 __set__,再给该描述符实例化对象赋值时自动运行。
1.3 __delete__,删除该描述符实例化对象中的属性时自动运行。
2.如何使用描述符:
写一个A类,描述符实例化对象作为A类的类层级的属性。
3.为什么函数写在类中,变成类方法时,类的实例化对象调用函数时,不需要将本身传进去,而可以直接实现调用?
因为函数本身就是一个描述符,作为类中的方法(类层级的属性),当被调用时,会自动运行Function类(产生函数的类),中的__get__,在__get__中将self自动传入函数中了,所以我们在
使用类实例化对象调用类中方法时,不需要将类的实例化对象传入函数中。
函数写在外面就是一个普通的函数,所以有几个参数要传几个参数,并且不会有描述符的功效(不是类层级的属性)
例子1:用描述符实现一个django创建数据库表模型字段的验证。
# 描述符简单的使用 class Charfield(object): def __init__(self,default=None): self.value = default def __get__(self, instance, owner): """ self : 表示是谁调用的这个__get__,很明显是Charfield的实例化对象 instance: 表示是谁调用Charfield的实例化对象,这里应该是Student类实例化的对象 owner:表示instance实例化的类. """ print('描述符自动运行了get,self:{},instance:{},owner:{}'.format(self, instance, owner)) return self.value def __set__(self, instance, value): print("描述符自动运行了set,self:{},instance:{},value:{}".format(self, instance, value)) if isinstance(value,str): self.value = value return None else: raise Exception('该类型必须为字符串类型') def __delete__(self, instance): RuntimeError('不允许删除') class Student(object): name = Charfield(default='yc') alcise = Charfield() stu1 = Student() print(stu1.name) print(stu1.alcise) stu1.name = 'yc' stu1.alcise = 'zlw' print(stu1.name,stu1.alcise)
例子2 :用描述符实现的三个内置装饰器staticmethod,classmethod,property
class Mystaticmethod(object): # 描述符,用于处理静态方法的类装饰器 def __init__(self,f): self.f=f def __get__(self, instance, owner): def wrapper(*args,**kwargs): res = self.f(*args,**kwargs) # 静态方法,啥都不传 print('调用了Mystaticmethod的') return res return wrapper class Myclassmethod(): def __init__(self,f): self.f = f def __get__(self, instance, owner): def wrapper(*args,**kwargs): print("myclassmethod已经再实行了",*args) res = self.f(owner,*args,**kwargs) # 类方法,传调用实例化的类 return res return wrapper class Myproperty(): def __init__(self,f): self.f=f self.g=None def __get__(self, instance, owner): def wrapper(*args,**kwargs): print('Myproperty已经开始执行') res = self.f(instance,*args,**kwargs) # 传类的实例化对象,和普通类方法不一样的是,普通类方法,返回的是一个函数地址(没有执行),property返回的是函数的执行结果 return res return wrapper def setattr(self,g): print('setter called') self.g=g return self def __set__(self, instance, value): print('__set__执行的是那个f3') return self.g(instance,value) class Student(object): # def f(self): # print('f正在执行') def __init__(self,x,y,z): self.x=x self.y=y self.z = z @Mystaticmethod def f1(x): print('f1正在执行') Student.f2('我是f1再调用f2') return None @Myclassmethod def f2(cls,name): print('f2正在执行,name:{}'.format(name)) print('cls_name:{}'.format(cls.__name__)) # @Myproperty def f3(self): print('f3正在执行') return self.z @f3.setattr def f3(self,m): print('set_f3正在执行,f3的最新值是{}'.format(m)) self.z=m return None stu1 = Student(1,2,3) # stu1.f1(11) a = stu1.f3 print('f3的旧值是:{}'.format(stu1.f3)) stu1.f3=2 print('f3的新值是:{}'.format(stu1.f3))