Python3中的类型子类化与对象子类化

9
我一直在阅读关于元类的内容,但当涉及到typeobject类时,我就迷失了。
我知道它们处于层次结构的顶部,并且它们是用C代码实现的。我也明白type继承自object,并且objecttype的一个实例。
在SO上我找到了答案之一,其中有人提到关于object-type关系的问题:
“这种相互继承通常是不可能的,但对于Python中的这些基本类型而言,它们打破了规则。”
我的问题是为什么要这样实现,这种实现的目的是什么?它解决了什么问题/设计的好处是什么?它不能只使用type或只使用object类作为层次结构的顶部,让每个类都继承它吗?

最后,从object继承和从type继承有什么区别?我应该在什么情况下使用其中之一?

class Foo(object):
    pass

对比

class Foo(type):
    pass

那个答案非常误导人。没有相互继承的情况发生;该答案没有很好地传达实例和子类关系之间的区别。 - user2357112
5
type 是 Python 中的基元类。 (每个类都是一个对象,而类的类是其元类。)除非您有意尝试创建元类,否则不应该对 type 进行子类化。 - kindall
2个回答

13

objecttype之间不存在交叉继承。实际上,交叉继承是不可能的。

# A type is an object
isinstance(int, object) # True

# But an object is not necessarily a type
isinstance(object(), type) # False

在Python中的真实情况是...

一切都是对象

绝对所有的东西,object 是唯一的基础类型。

isinstance(1, object) # True
isinstance('Hello World', object) # True
isinstance(int, object) # True
isinstance(object, object) # True
isinstance(type, object) # True

每个东西都有一种类型

每个东西都有一个类型,可以是内置的或用户定义的,并且可以使用 type 获取该类型。

type(1) # int
type('Hello World') # str
type(object) # type

并非所有东西都是类型

这一点相当明显

isinstance(1, type) # False
isinstance(isinstance, type) # False
isinstance(int, type) # True

type是它自己的类型

这是type特有的行为,其他类无法复制。

type(type) # type

换句话说,type 是 Python 中唯一的对象 X,使得 type(X) is X 成立。

type(type) is type # True

# While...
type(object) is object # False

这是因为type是唯一的内置元类。元类只是一个类,但它的实例本身也是类。所以在你的示例中...

# This defines a class
class Foo(object):
    pass

# Its instances are not types
isinstance(Foo(), type) # False

# While this defines a metaclass
class Bar(type):
    pass

# Its instances are types
MyClass = Bar('MyClass', (), {})

isinstance(MyClass, type) # True

# And it is a class
x = MyClass()

isinstance(x, MyClass) # True

注意:这里的一些“总是”声明仅适用于Python 3;在Python 2中,旧风格类具有完全不同的类型层次结构(并且type(x),其中x是旧风格类的实例,在类型上告诉您是instance,而不是它是实例的类)。 - ShadowRanger
1
以上所有内容都是真实的,我仔细措辞,以便在Python2和3中都适用。陷阱在于说type(Foo()) is Foo始终为真。您的示例正确地表明它并不是这样,尽管isinstance(Foo(), Foo)为真。其余部分仍然是真实的,一切都是对象,一切都有类型,而type是唯一的自身类型的对象。但如果我错了,请纠正我! - Olivier Melançon
2
啊,是的。重新检查后,即使是旧式类的实例也声称是object的实例,尽管从object继承是创建新式类的方式。不知何故,isinstance(Foo(), object)为真,即使issubclass(Foo, object)为假,因为instance本身是object的子类。在Py2类型系统中的技巧有时是微妙而神奇的。 :-) - ShadowRanger
我可能还要在“一切都是对象”下添加这个:isinstance(type, object) # True - John

3
在Python中,一切都是对象。每个对象都有一个类型,事实上,对象的类型也是一个对象,因此必须具有自己的类型。类型有一个特殊的类型称为type。像任何其他类型一样,这个类型也是一个对象,因此它也是object的一个实例。
每个对象都是object的一个实例,包括任何对象的类型。因此,int是一个对象,str也是一个对象,以及1'asd'等更明显的示例。在Python中,您可以引用或分配给变量的任何内容都是object的一个实例。
由于object是一种类型,因此它是type的一个实例。这意味着objecttype都是彼此的实例。无论您链接的其他答案说什么,这都不是“继承”。这种关系与int1之间的关系相同:从1得到的对象是int的一个实例。这里的奇怪之处在于objecttype都是彼此的实例。
从Python的角度来看,这两个意味着不同的事情。object类型具有本体论角色:一切都是对象(没有其他内容存在)。因此,说type是一个对象只是意味着它在Python的模型中“存在”。另一方面,object是所有对象的基本类型,因此它是一种类型。作为一种类型,它必须是type的一个实例,就像任何其他对象一样,它也是object的一个实例。
就解释器的实现而言,typeobject的一个实例这一事实很方便,因为它维护了“一切都是对象”,这对于例如在关闭时释放对象非常有用。objecttype的一个实例这一事实很有用,因为它使得确保它的行为类似于其他类型对象变得简单明了。

1
这是很好的信息,是否有更一般、官方的知识体系相关内容? - shayaan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接