【问题标题】:What is the difference between a 'Type' and an 'Object' in Python [duplicate]Python中的“类型”和“对象”有什么区别[重复]
【发布时间】:2013-03-20 21:13:49
【问题描述】:

我在阅读 super 关键字上的 python documentation 时遇到了这个问题:

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

谁能给我一个例子来说明传递一个类型作为第二个参数和传递一个对象之间的区别?

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

谢谢。

【问题讨论】:

  • 这应该会给你一些观点:cafepy.com/article/python_types_and_objects/…
  • @karthikr 同意,很棒的文章
  • 或者看看这个问题stackoverflow.com/questions/100003/… 和很好的答案,虽然它是关于元类的,但它详细说明了类型和对象以建立元类的描述 - 真的很好读。
  • 这么棒的问题。我一直在尝试用 Python(我唯一的语言)自学 OOP,努力使用继承和调用超类方法。我读过关于 super 的解释也有同样的问题。
  • 这不完全是重复的。从技术上讲是这样,但是说,从人体工程学上讲,我不这么认为。我认为这个答案值得关注,而不仅仅是关于元类的解释。例如,它可能会导致讨论为什么 object 评估为 type 的实例,而 type 也评估为 object 的实例。 @MartijnPieters

标签: python object types


【解决方案1】:

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

【讨论】:

  • 我不同意 w.r.t.,它仅限于内置函数。每个人都可以并且确实定义了自己的类型。
  • @smitkpatel,我想您可能正在考虑“内置”类型。
  • 内置 - 默认土豆 - 土豆
【解决方案2】:

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

#
# 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 considered harmful

编辑2:

谁能给我一个例子来说明传递一个类型作为第二个参数和传递一个对象之间的区别?

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

checkInstanceType(c1, b1)

调用将失败。可以写成:

checkInstanceType(c1, type(b1))

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

【讨论】:

    【解决方案3】:

    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(来自 Base.make_obj)加上 2(来自 Derived.__init__)。

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

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

    【讨论】:

    • 是帮助记忆函数调用的超级方法吗?我有一个对象,它通过检查函数是否存在,然后使用直接调用该函数的对象为对象分配一个属性,从而加快对另一个解释器的调用。所以我基本上只查找该函数一次并将其记忆为可调用属性。我必须使用 object.__setattr__(self, "attribute", callableObj) 以防止它循环/调用我对“settr”的重新定义。 super 也做同样的事情吗?
    • @Demolishun:嗯,没有。您使用super 来获取被覆盖方法的继承版本。查看the docs
    • 好的,所以它是相似的,但它允许动态引用基类,但不能通过名称。这是一个用例。 rhettinger.wordpress.com/2011/05/26/super-considered-super感谢参考。
    猜你喜欢
    • 2021-06-04
    • 1970-01-01
    • 2011-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-19
    • 2012-01-22
    • 2021-04-02
    相关资源
    最近更新 更多