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

 

 

 

 

 

 

 


  
posted on 2022-06-18 16:03  輪滑少年  阅读(43)  评论(0编辑  收藏  举报