【二十四】Python中super()详解及应用场景举例(1)

【二十四】Python中super()详解及应用场景举例(1)

【1】作用

  • super也是一个类,是的。他不是一个方法也不是一个内置的关键字。
class A:
    pass

print(type(super(A)))

# <class '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
    """

【2】纠正(super就是用来调用父类方法的,这是一个错误的观点!

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


class B(A):
    def __init__(self):
        print("B")
        super().__init__()


class C(A):
    def __init__(self):
        print("C")
        super().__init__()


class D(B, C):
    def __init__(self):
        print("D")
        super().__init__()


D()

# D
# B
# C
# A
  • 如果按照“super就是用来调用父类的方法的”这样的理解来看,那上述代码的执行的过程应该为:

    • print("D")
    • 【调用super会先后执行B和C】
    • 先执行B:print("B")
    • 【调用super执行A】
    • print("A")
    • 【调用super会先后执行B和C】
    • 后执行C:print("C")
    • 【调用super执行A】
    • print("A")
  • 执行结果理论应该为:D B A C A

  • 但实际情况却是:D B C A

  • 所以说“super就是用来调用父类的方法的”这个说法是错误的!

  • 实际上super的调用是遵循Python的【MRO(方法解析顺序)】来执行的,在Python3中,MRO是基于C3算法来实现的。

【3】使用场景

  • 1.假如我们继承的多个父类有同名的方法
    • 可以使用super来指定使用哪个父类的方法
class A:
    def test(self):
        print('A')

class B:
    def test(self):
        print('B')

class C(A, B):
    def __init__(self):
        super().test()  # 调用A类中的test方法
        super(C, self).test()  # 调用A类中的test方法
        super(A, self).test()  # 调用B类中的test方法    
        
C()

# A
# A
# B
  • 2.当我们在子类中使用父类的一个方法并且想对其做一定扩展又不想完全重写,那么使用super()就可以实现方法的增量修改:
    • 举一个例子,如果我们想把list中的append的方法改为中文添加应该怎么做呢?
    • 并且python中list调用append方法是没有返回值的,我们想在添加元素操作成功后加一个返回值返回成功又该如何操作呢?
  • 首先看通过调用原来的list的执行结果
a=list()
res=a.append(1)
print(res)

# None
  • 可以看到调用append方法后返回的值为None
  • 现在我们通过super进行重写
    • 让其具有返回值并可以直接通过中文来调用append:
class 列表(list):
    def 添加(self, *args, **kwargs):
        super().append(*args, **kwargs)
        return "添加成功"

x = 列表()
res = x.添加(1)
print(res)
print(x)

# 添加成功
# [1]

【4】总结

  • super实际上还是很常用的
    • 比如在restfremework中
      • 需要重写其响应结果的Response信息的时候
      • 除了通过django的中间件实现
      • 也可以使用super重写其dispatch来实现。
posted @ 2023-06-01 20:37  Chimengmeng  阅读(31)  评论(0编辑  收藏  举报