ITPub博客

首页 > 数据库 > 数据库开发技术 > python面向对象编程篇(13):扩展MRO下的super()的一些知识点

python面向对象编程篇(13):扩展MRO下的super()的一些知识点

原创 数据库开发技术 作者:程序员小钟同学 时间:2021-03-17 18:22:04 0 删除 编辑

本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。

个人其他博客地址:

简书:https://www.jianshu.com/u/d6960089b087

掘金:https://juejin.cn/user/2963939079225608

小钟同学 | 文 【原创】| QQ:308711822

1、前言

前面有介绍了关于多继承问题,其实还涉及到一个子类调用父类的,多次调用的问题。再多继承中子类调用父类的多次调用问题。

通常我们的所知的一个子类调用父类的方法的方式就是:super()。有些时候我们可以理解是子类,调用父类(单继承中),但是在多继承,又是不一样。

在每个类声明之后,Python都会自动为创建一个名为“mro”的内置属性,前面也有说到了多继承的MRO的问题,那在,Python中的super()方法是怎么样的呐?

回到之前的MRO的示例上:


class A1:
    def __init__(self):
        print("A1")


class A2:
    def __init__(self):
        print("A1")


class A3:
    def __init__(self):
        print("A3")


class B1(A1, A2):
    def __init__(self):
        print("B1")
        super().__init__()



class B2(A2):
    def __init__(self):
        print("B2")
        super().__init__()



class B3(A2, A3):
    def __init__(self):
        print("B3")
        super().__init__()


class C1(B1):
    def __init__(self):
        print("C1")
        super().__init__()


class C2(B1, B2):
    def __init__(self):
        print("C2")
        super().__init__()


class C3(B2, B3):
    def __init__(self):
        print("C3")
        super().__init__()



class D(C1, C2, C3):
    def __init__(self):
        print("D")
        super().__init__()


for s in D.mro():
    print(s)
d = D()


输出的结果为:

<class '__main__.D'>
<class '__main__.C1'>
<class '__main__.C2'>
<class '__main__.B1'>
<class '__main__.A1'>
<class '__main__.C3'>
<class '__main__.B2'>
<class '__main__.B3'>
<class '__main__.A2'>
<class '__main__.A3'>
<class 'object'>
D
C1
C2
B1
A1

从上面的结果可以看出来。super()的调用顺序也是遵循mro算法。所以如果说是单纯的只是父类方法和属性的调用的说法是不太准确的。

2. super().属性、方法和父类名称.属性/方法的区别

多继承情况- 父类名称.属性/方法

示例:

class A1:
    def __init__(self):
        print("A1")


class A2:
    def __init__(self):
        print("A1")


class A3:
    def __init__(self):
        print("A3")


class B1(A1):

    def __init__(self):
        print("B1")
        A1.__init__(self)



class B2(A2):
    def __init__(self):
        print("B2")
        A2.__init__(self)



class B3(A2, A3):
    def __init__(self):
        print("B3")
        A2.__init__(self)
        A3.__init__(self)


class C1(B1):
    def __init__(self):
        print("C1")
        B1.__init__(self)


class C2(B1, B2):
    def __init__(self):
        print("C2")
        B1.__init__(self)
        B2.__init__(self)


class C3(B2, B3):
    def __init__(self):
        print("C3")
        B2.__init__(self)
        B3.__init__(self)



class D(C1, C2, C3):
    def __init__(self):
        print("D")
        C1.__init__(self)
        C2.__init__(self)
        C3.__init__(self)


# for s in D.mro():
#     print(s)
d = D()

上面的代码,我们的为了调用父类的方法,于是乎,会产生一系列的重复的多次的调用的问题!和上面使用的 super().属性、方法截然不同!

所以我们可以总结的到:super()是一个调用父类的说法是不完全对滴。它也是为了解决多继承问题而出现的。

3. 深入super()内部

探究我们的super()之后,我们的看到其实深入super是一个类:

class super(object):
    """
    super() -> same as super(__class__, <first argument>)
    super(type) -> unbound super object
    super(type, obj) -> bound super object; requires isinstance(obj, type)
    super(type, type2) -> bound super object; requires issubclass(type2, type)
    Typical use to call a cooperative superclass method:
    class C(B):
        def meth(self, arg):
            super().meth(arg)
    This works for class methods too:
    class C(B):
        @classmethod
        def cmeth(cls, arg):
            super().cmeth(arg)
    "
""
    def __getattribute__(self, *args, **kwargs): # real signature unknown
        """ Return getattr(self, name). """
        pass

    def __get__(self, *args, **kwargs): # real signature unknown
        """ Return an attribute of instance, which is of type owner. """
        pass

    def __init__(self, type1=None, type2=None): # known special case of super.__init__
        """
        super() -> same as super(__class__, <first argument>)
        super(type) -> unbound super object
        super(type, obj) -> bound super object; requires isinstance(obj, type)
        super(type, type2) -> bound super object; requires issubclass(type2, type)
        Typical use to call a cooperative superclass method:
        class C(B):
            def meth(self, arg):
                super().meth(arg)
        This works for class methods too:
        class C(B):
            @classmethod
            def cmeth(cls, arg):
                super().cmeth(arg)
        
        # (copied from class doc)
        "
""
        pass

    @staticmethod # known case of __new__
    def __new__(*args, **kwargs): # real signature unknown
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __repr__(self, *args, **kwargs): # real signature unknown
        """ Return repr(self). """
        pass

    __self_class__ = property(lambda self: type(object))
    """the type of the instance invoking super(); may be None

    :type: type
    "
""

    __self__ = property(lambda self: type(object))
    """the instance invoking super(); may be None

    :type: type
    "
""

    __thisclass__ = property(lambda self: type(object))
    """the class invoking super()

    :type: type
    "
""

super是一个类,它实例化之后得到的是一个代理的对象,而不是得到了我们所说的父类,返回这个代理对象后可以使用它调用父类或者兄弟类的方法。

super()三种调用的方法,使用格式如下:

  • super()   # 指代父类
  • super(type, obj)  # 同样指代父类,super接受两个参数,type类型,obj实例对象。
  • super(type_1 , type_2):super传入的两个参数都是类名是,type_2必须是type_1的子类

super() == super(type, obj)=super(class , obj)

总结:

  • super() 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

4. super()在我们的flask脚手架中示例,自定义全局异常处理器


class ApiAdminJsonResponse(HTTPException):
    code = 500
    api_code = 999
    result = None  # 结果可以是{} 或 []
    message = '成功'
    success = True
    timestamp = get_timestamp13()
    # 默认的支持的跨域处理
    customize_headers = {
        # 'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Headers': '*,School-Teacher-Token,school-teacher-token,T-Access-Token,x-access-token,Referer, Accept, Origin, User-Agent,X-Requested-With, Content-Type, X-File-Name',
        'Access-Control-Request-Headers': 'Content-Type,Access-Token',
        'Content-Type': 'application/json;charset=UTF-8'
    }

    # 还可以自定义响应头信息
    def __init__(self, success=None, code=None, message=None, api_code=None, result=None, headers={}, is_limit_cors=False):

        if code:
            self.code = code
        if message:
            self.message = message
        if api_code or api_code == 0:
            self.api_code = api_code
        if result:
            self.result = result
        if headers:
            self.customize_headers.update(headers)
        if success != None:
            self.success = success
        # self.code = code
        # self.api_code = api_code
        # 是否禁止跨域请求处理
        self.is_limit_cors = is_limit_cors
        super(ApiAdminJsonResponse, self).__init__(message, None)

    def get_body(self, environ=None):

        body = dict(
            message=self.message,
            code=self.api_code,
            success=self.success,
            result=self.result,
            timestamp=self.timestamp,
            # 形如request="POST v1/client/register"
            # request=request.method + ' ' + self.get_url_no_param()
        )
        text = dict_to_json(body)
        return text

    # 重写响应的头部信息----可以自定义返回响应头部信息
    def get_headers(self, environ=None):
        if self.is_limit_cors:
            pass
            # del self.customize_headers['Access-Control-Allow-Origin']
            if 'Access-Control-Allow-Origin' in self.customize_headers.keys():
                del self.customize_headers['Access-Control-Allow-Origin']
        return self.customize_headers

    @staticmethod
    def get_url_no_param():
        full_url = str(request.full_path)
        main_path = full_url.split('?')
        return main_path[0]



原文作者:程序员小钟同学;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2021-02-20

  • 博文量
    224
  • 访问量
    111698