首页 文章

super()返回的超级对象的类型是什么?

提问于
浏览
5

来自here

super([type [,object-or-type]])
返回将方法调用委托给父类或兄弟类类型的代理对象 . 这对于访问已在类中重写的继承方法很有用 . 搜索顺序与getattr()使用的搜索顺序相同,只是跳过了类型本身 . 如果省略第二个参数,则返回的超级对象是未绑定的 . 如果第二个参数是一个对象,则isinstance(obj,type)必须为true . 如果第二个参数是一个类型,则issubclass(type2,type)必须为true(这对于classmethods很有用) .

  • 如果我是正确的,则类型是类,类是类型 . 类是一个对象,因此类型也是一个对象 . 当第二个参数是一个类型的对象时,为什么引用会区分这两种情况呢?

  • 当第二个参数是一个类型时,为什么 issubclass(type2, type) 必须为真?

  • super 分别在三种情况下返回的超级对象的类型是什么?或者如何确定 super 返回的超级对象的类型?

当第二个参数是一个对象时,因为“搜索顺序与 getattr() 使用的搜索顺序相同,只是跳过 type 本身”,我猜测 super 函数返回的超级项目的类型应该是任何祖先类的子类 . 第一个参数 type ,但我发现它实际上不是通过 issubclass 进行测试 . 所以我误解了什么?

2 回答

  • 4

    您似乎将 type 这个词与内置的type()混淆了 . 在这里,他们只是引用传递给 super() 的第一个参数 .

    文档告诉你的是,如果你传入两个参数,那么第二个参数必须是第一个参数的实例,或者它必须是一个子类 . 换句话说, isinstance(first_argument, second_argument)issubclass(first_argument, second_argument) 必须为真 . 这里没有其他意义 .

    就像 int()str() 或任何其他内置类型一样,通过调用 super() 返回的对象类型就是该类型 . 对于不同的参数,没有返回单独的类型 . 见C source code defining the object .

    super() 对象实现了一个实现特定属性行为的getattribute hook . 文档告诉您属性查找的规则与 getattr() 相同(但是记录的MRO跳过),但这并不意味着 super() 返回祖先类 .

    实际发生的是 super().__getattribute__ 获取第二个参数的MRO( type(instance).__mro__cls.__mro__ ,取决于是 isinstance()issubclass() 是真的),找到该序列中的第一个参数并在此之后开始测试属性 . 因为MRO首先被扫描为第二个参数的类型,所以它必须是可查找的,这就是为什么约束是它们的原因 .

    在纯Python中,这就是 super() 所做的(简化为仅关注两个参数行为):

    def _supercheck(type_, obj):
        try:
            if issubclass(obj, type_):
                return obj
        except TypeError:
            # obj is not a type so issubclass throws a TypeError
            pass
        if isinstance(obj, type_):
            return type(obj)
        raise TypeError(
            "super(type, obj): obj must be an instance or subtype of type")
    
    
    class super_:
        def __init__(self, type_, obj):
            # simplified for the two-argument case
            self.type_ = type_
            self.obj = obj
            self.obj_type = _supercheck(type_, obj)
    
        def __getattribute__(self, name):
            if name == '__class__':
                # __class__ should always come from this object, not
                # the represented MRO.
                return super().__getattribute__(name)
    
            # avoid infinite recursion issues
            sd = super().__getattribute__('__dict__')
            starttype = sd['obj_type']
            type_ = sd['type_']
            obj = sd['obj']
    
            mro = iter(starttype.__mro__)
    
            # skip past the start type in the MRO
            for tp in mro:
                if tp == type_:
                    break
    
            # Search for the attribute on the remainder of the MRO
            for tp in mro:
                attrs = vars(tp)
                if name in attrs:
                    res = attrs[name]
                    # if it is a descriptor object, bind it
                    descr = getattr(type(res), '__get__', None)
                    if descr is not None:
                        res = descr(
                            res,
                            None if obj is starttype else obj,
                            starttype)
                    return res
    
            return super().__getattribute__(name)
    
  • 2

    关于3个案例中关于超类型的第3点(2个首先是相似的):

    class A(object):
        def sup(self):
            return (super(A, self))
    
    class A1(object):
        def sup(self):
            return (super())
    
    
    class B(object):      
        def sup(self):
            return (super(B))  
    
    class C(A):
        def sup(self):
            return (super(A,C))      
    
    a = A()
    a_sup = a.sup()
    print(type(a_sup))  #<class 'super'>
    print(a_sup.__doc__)  #The most base type
    print(a_sup.__self__)  #<__main__.A object at 0x7f9d0d2d8668>
    print(a_sup.__self_class__) #<class '__main__.A'>
    print(a_sup.__thisclass__)  #<class '__main__.A'>
    
    print()  
    a1 = A1()
    a_sup = a1.sup()
    print(type(a_sup))  #<class 'super'>
    print(a_sup.__doc__)  #The most base type
    print(a_sup.__self__)  #<__main__.A1 object at 0x7f9d0d2d86d8>
    print(a_sup.__self_class__) #<class '__main__.A1'>
    print(a_sup.__thisclass__) #<class '__main__.A1'>
    
    print()    
    b = B()
    b_sup = b.sup()
    print(type(b_sup))  #<class 'super'>
    print(b_sup.__doc__) 
    '''
    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)
    '''        
    
    print(b_sup.__self__)  #None
    print(b_sup.__self_class__)  #None
    print(b_sup.__thisclass__)  #<class '__main__.B'>
    
    print()
    c=C()
    c_sup = c.sup()
    print(type(c_sup))  #<class 'super'>
    print(c_sup.__doc__) #The most base type
    print(c_sup.__self__) #<class '__main__.C'>
    print(c_sup.__self_class__) #<class '__main__.C'>
    print(c_sup.__thisclass__) #<class '__main__.A'>
    

相关问题