24

我在阅读有关关键字的python文档时遇到了这个问题:super

如果省略第二个参数,则返回的超级对象是未绑定的。如果第二个参数是对象,则 isinstance(obj, type) 必须为真。如果第二个参数是一个类型,issubclass(type2, type) 必须为真(这对类方法很有用)。

有人可以给我一个例子来说明传递类型作为第二个参数与传递对象之间的区别吗?

文档是否在谈论对象的实例?

谢谢你。

4

3 回答 3

10

Python 的super函数根据它的参数做不同的事情。以下是使用它的不同方式的演示:

class Base(object):
    def __init__(self, val):
        self.val = val

    @classmethod
    def make_obj(cls, val):
        return cls(val+1)

class Derived(Base):
    def __init__(self, val):
        # In this super call, the second argument "self" is an object.
        # The result acts like an object of the Base class.
        super(Derived, self).__init__(val+2)

    @classmethod
    def make_obj(cls, val):
        # In this super call, the second argument "cls" is a type.
        # The result acts like the Base class itself.
        return super(Derived, cls).make_obj(val)

测试输出:

>>> b1 = Base(0)
>>> b1.val
0
>>> b2 = Base.make_obj(0)
>>> b2.val
1
>>> d1 = Derived(0)
>>> d1.val
2
>>> d2 = Derived.make_obj(0)
>>> d2.val
3

结果3是前面的修饰符的组合:1 (from Base.make_obj) 加上 2 (from Derived.__init__)。

请注意,可以super只使用一个参数调用来获取“未绑定”的超级对象,这显然没有多大用处。除非您想弄乱 Python 内部结构并且您真的知道自己在做什么,否则没有任何理由这样做。

在 Python 3 中,你也可以super不带参数调用(相当于上面函数中的调用,但更神奇)。

于 2013-03-30T21:39:27.777 回答
0

下面对这两个函数做一个简单的探索。通过这个练习,我发现它很有启发性。我经常会创建一个简单的程序来探索简单函数的来龙去脉并保存以供参考:

#
# Testing isinstance and issubclass
#

class C1(object):
    def __init__(self):
        object.__init__(self)

class B1(object):
    def __init__(self):
        object.__init__(self)

class B2(B1):
    def __init__(self):
        B1.__init__(self)

class CB1(C1,B1):
    def __init__(self):
        # not sure about this for multiple inheritance
        C1.__init__(self)
        B1.__init__(self)

c1 = C1()
b1 = B1()
cb1 = CB1()

def checkInstanceType(c, t):
    if isinstance(c, t):
        print c, "is of type", t
    else:
        print c, "is NOT of type", t

def checkSubclassType(c, t):
    if issubclass(c, t):
        print c, "is a subclass of type", t
    else:
        print c, "is NOT a subclass of type", t

print "comparing isinstance and issubclass"
print ""

# checking isinstance
print "checking isinstance"

# can check instance against type
checkInstanceType(c1, C1)
checkInstanceType(c1, B1)
checkInstanceType(c1, object)

# can check type against type
checkInstanceType(C1, object)
checkInstanceType(B1, object)

# cannot check instance against instance
try:
    checkInstanceType(c1, b1)
except Exception, e:
    print "failed to check instance against instance", e

print ""

# checking issubclass
print "checking issubclass"

# cannot check instance against type
try:
    checkSubclassType(c1, C1)
except Exception, e:
    print "failed to check instance against type", e

# can check type against type
checkSubclassType(C1, C1)
checkSubclassType(B1, C1)
checkSubclassType(CB1, C1)
checkSubclassType(CB1, B1)

# cannot check type against instance
try:
    checkSubclassType(C1, c1)
except Exception, e:
    print "failed to check type against instance", e

编辑: 还要考虑以下内容,因为 isinstance 可能会破坏 API 实现。一个例子是一个像字典一样的对象,但不是从 dict 派生的。isinstance 可能会检查对象是否为字典,即使该对象支持字典样式访问: isinstance 被认为是有害的

编辑2:

有人可以给我一个例子来说明传递类型作为第二个参数与传递对象之间的区别吗?

在测试了上面的代码后,它告诉我第二个参数必须是一个类型。所以在以下情况下:

checkInstanceType(c1, b1)

调用将失败。可以写成:

checkInstanceType(c1, type(b1))

因此,如果您想检查一个实例与另一个实例的类型,您必须使用 type() 内置调用。

于 2013-03-30T20:46:34.467 回答
0

对象可以是任何 Python 类实例,它可能是用户定义的,也可能不是用户定义的。但是,当您谈论type时,它​​指的是默认对象/集合,例如 list/tuple/dict/int/str 等。

于 2013-03-30T07:09:16.097 回答