【问题标题】:What is the type of the super object returned by super()?super() 返回的超级对象的类型是什么?
【发布时间】:2017-07-08 23:13:50
【问题描述】:

来自here

super( [ type [ , object-or-type ]] )

返回一个代理对象,它将方法调用委托给type 的父类或兄弟类。这对于访问已在类中重写的继承方法很有用。搜索顺序与getattr() 使用的顺序相同,只是跳过了type 本身。

如果省略第二个参数,则返回的超级对象是 未绑定。

如果第二个参数是一个对象,isinstance(obj, type) 必须是 真的。

如果第二个参数是类型issubclass(type2, type) 必须是 true(这对类方法很有用)。

  1. 如果我是对的,类型是类,类是类型。一类 是一个对象,所以类型也是一个对象。为什么报价 当第二个参数是一个对象时区分这两种情况 什么时候是类型?

  2. 当第二个参数是类型时,为什么是issubclass(type2, type) 必须是真的吗?

  3. super在这三种情况下分别返回的超级对象的类型是什么?或者如何判断super返回的超级对象的类型?

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

【问题讨论】:

  • type 在这里引用 参数名称,而不是 type() 内置。
  • “如果第二个参数是类型”中的“类型”是指特定类型吗?
  • 它的文档范围是你已经找到的。
  • 就在您的链接中。您的链接内容构成了super 类型的整个文档。没有进一步的文档。
  • @Tim:文档将其列为函数,但它是一种类型。我并没有说这是特别令人满意的文档。

标签: python python-3.x


【解决方案1】:

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

文档告诉你的是 if 你传入了两个参数,那么第二个参数 either 必须是第一个参数的实例,或者 它必须是一个子类。换句话说,isinstance(first_argument, second_argument)issubclass(first_argument, second_argument) 必须为真。 这里没有别的意思

就像int()str() 或任何其他内置类型一样,调用super() 返回的对象的类型就是那个类型。没有为不同的参数返回单独的类型。请参阅C source code defining the object

super() 对象实现了一个实现特定属性行为的__getattribute__ hook。文档告诉您属性查找的 规则getattr() 相同(但有文档记录的 MRO 跳过),但 not 是否意味着 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)

【讨论】:

  • 很好的实现。两点说明: 1. 如Python文档herehere中所述,当槽__self__是槽@987654349的实例时,槽__self_class__等于__self__.__class__,而不是type(__self__) @。所以你应该用return obj.__class__ 替换return type(obj)(尽管它们大部分时间是相等的)。
  • 2.不查找object 之前的超类的方法__getattribute__(您可以继承super 自定义类重新定义__getattribute__ 来检查这一点)。所以你应该用return object.__getattribute__(self, name)替换return super().__getattribute__(name)
  • @Maggyero:这是一个可读的 Python 表示 super() 所做的事情,而不是在子类化时表现得完全相同。如果使用super().__getattribute__(name)object.__getattribute__(self, name) 真的那么重要吗?对于代码阅读理解,我宁愿保留前者。
  • @Maggyero __self__.__class__type(__self__) 完全相同;两者都给你一个参考Py_TYPE(self)。我正在使用惯用的 API。不只是“大部分时间”相等。是的,我忽略了重新分配名称type,这绝对超出了这里的范围。覆盖__class___ 插槽也是如此。
  • 2.我同意它并不那么重要,但在子类化时它的行为方式不同:class A: def __getattribute__(self, name): return 'foo'; class B(super, A): pass; print(B(int).x)。使用object.__getattribute__(self, name)(内置super),您将获得AttributeError: 'B' object has no attribute 'x',而使用super,您将获得foo
【解决方案2】:

仅针对 3 种情况下关于 super 类型的第 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'>

【讨论】:

  • 谢谢。我对supertypeobject 类型之间的关系感兴趣。很明显super一定是type的实例,是object的子类。他们之间有没有更多的关系?
  • isinstance(a_sup, object) ==> 对,isinstance(a_sup, type) ==> 错,issubclass(type(a_sup), type) ==> 错
  • @Tim: 不,super() 不是第一个参数的实例。为什么会这样?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-28
  • 1970-01-01
  • 1970-01-01
  • 2013-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多