欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

描述符\get/set/delete,init/new/call,元类

程序员文章站 2022-06-27 21:53:42
6.23 自我总结 1.描述符\_\_get\_\_,\_\_set\_\_,\_\_delete\_\_ 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了___\_get\_\_(),\_\_set\_\_(),\_\_delete\_\_()中的一个,这也被称为描述符协议 __ ......

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