• python 描述符


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

      
  • 相关阅读:
    获取地址栏的key-value形式的值(包括重复的key值)形成对象--重复的变成数组形式
    vue---定时循环setInterval
    动画效果----webkit-animation-----动画背景变化transition:background-color 1s linear;
    background-clip--背景是否填充
    box-sizing盒子的大小,修改文字种类而保持字体大小不变font-size-adjust,----块级和内联display---盒子阴影box-shadow---对盒子中容纳不下的内容的显示overflow
    地图api学习第一天
    文字添加阴影
    css循环样式: nth-child(n)
    es6语法
    将中国标准时间--转换为yyyy-MM-dd 时分秒
  • 原文地址:https://www.cnblogs.com/ltyc/p/16388530.html
Copyright © 2020-2023  润新知