zoukankan      html  css  js  c++  java
  • 描述符get/set/delete,init/new/call,元类

    6.23 自我总结

    1.描述符__get__,__set__,__delete__

    描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了____get__(),__set__(),__delete__()中的一个,这也被称为描述符协议

    • __get__():调用一个属性时,触发
    • __set__():为一个属性赋值时,触发
    • __delete__():采用del删除属性时,触发

    这三者来对于类的属性生成一个类,然后对一个新类立面的特征进行调用方法

    使用方法

    class FooSet:
    
        def __get__(self, instance, owner):
            print('你调用了该方法')
    
        def __set__(self, instance, value):
            print('你修改了')
    
        def __delete__(self, instance):
            print('你删除了')
    
    
    class Foo:
        name = FooSet()
        
    foo = Foo()
    
    #调用生成对象的属性
    print(foo.name)
    
    #修改生成对象的属性
    foo.name = 123
    
    
    #删除生成对象的属性
    del foo.name
    
    • 包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法

    2.__init__,__new_,__call__

    __new__方法的第一个参数是这个类,而其余的参数会在调用成功后全部传递给

    __init__方法初始化,这一下子就看出了谁是老子谁是小子的关系。

    __call__方法,该方法会在调用对象主要是在定义元类的时候使用时自动触发

    class A:
        pass
    
    
    class B(A):
        def __new__(cls):           #如果没写这一步其实他在init时候默认会进行着一步先
            print("__new__方法被执行")
            return super().__new__(cls)
    
        def __init__(self):
            print("__init__方法被执行")
    
    
    b = B()
    '''
    __new__方法被执行
    __init__方法被执行
    '''
    

    我们比较两个方法的参数,可以发现__new__方法是传入类(cls),而__init__方法传入类的实例化对象(self),而有意思的是,__new__方法返回的值就是一个实例化对象(ps:如果__new__方法返回None,则__init__方法不会被执行,并且返回值只能调用父类中的__new__方法,而不能调用毫无关系的类的__new__方法)。我们可以这么理解它们之间的关系,__new__是开辟疆域的大将军,而__init__是在这片疆域上辛勤劳作的小老百姓,只有__new__执行完后,开辟好疆域后,__init__才能工作。

    绝大多数情况下,我们都不需要自己重写__new__方法,但在当继承一个不可变的类型(例如str类,int类等)时,它的特性就尤显重要了。我们举下面这个例子:

    class CapStr(str):
        def __init__(self, string):
            #他在这一步已经传string进去了后面没有意义了
            string = string.upper()
    a = CapStr("I love China!")
    print(a)
    #I love China!
    
    class CapStr(str):
        def __new__(cls, string):
            string = string.upper()
            return super().__new__(cls, string)
    a = CapStr("I love China!")
    print(a)
    #I LOVE CHINA!
    
    

    3.元类

    1.元类的模板

    元类定义 class 元类名(type)

    class Mymeta(type):
        def __init__(self, class_name, class_bases, class_dic):
            # 加上逻辑,控制类Foo的创建
            super(Mymeta, self).__init__(class_name, class_bases, class_dic)
    
        def __call__(self, *args, **kwargs):
            # 加上逻辑,控制Foo的调用过程,即Foo对象的产生过程
            obj = self.__new__(self)
            self.__init__(obj, *args, **kwargs)
            # 修改属性为隐藏属性
            obj.__dict__ = {
                '_%s__%s' % (self.__name__, k): v
                for k, v in obj.__dict__.items()
            }
    
            return obj
    

    2.元类调用

    class Foo(object, metaclass=Mymeta):  # Foo = Mymeta(...)
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
    
    obj = Foo('nick', 18, 'male')
    
  • 相关阅读:
    拷贝构造函数 转型构造函数
    构造函数对const成员的初始化
    拷贝构造函数
    类数据成员和类成员函数
    顶层函数进行操作符重载与操作符重载直接作为类的构造函数
    构造函数和new 与new【】 析构函数
    Openfire+XIFF实时通信&一个特殊的GP
    客户端数据动态渲染
    数据处理:由面得点,构造其边界
    从GISALL博客搬家而来
  • 原文地址:https://www.cnblogs.com/pythonywy/p/11074638.html
Copyright © 2011-2022 走看看