type(instance)
和instance.__class__
可能会有所不同,即使使用新式类,正如Guido van Rossum在PEP 3119中提到的:
此外,isinstance(x, B)
等同于issubclass(x.__class__, B) or issubclass(type(x), B)
。(当x
是代理对象时,type(x)
和x.__class__
可能不是同一个对象。)
例如,标准库的weakref.proxy
函数创建代理对象。
>>> import weakref
>>> class A: pass
...
>>> a = A()
>>> type(weakref.proxy(a))
<class 'weakproxy'>
>>> weakref.proxy(a).__class__
<class '__main__.A'>
>>> repr(weakref.proxy(a))
'<weakproxy at 0x10065ab30 to A at 0x1006534c0>'
请注意,代理对象的
__repr__
方法的实现使用
type(instance)
而不是
instance.__class__
,因为
__repr__
方法的主要目的是在调试时提供足够的信息以重新创建对象。
type(instance)
一个
object
实例的真实类存储在实例的
__class__
slot中(即在实例布局中的固定偏移量)。它只能通过
data descriptor vars(object)['__class__']
(其方法
__get__
允许属性检索,其方法
__set__
允许属性赋值,其方法
__delete__
禁止属性删除)或等效地通过内置函数
type
(其一参数形式允许属性检索)来访问:
>>> class A: pass
...
>>> a = A()
>>> type(a)
<class '__main__.A'>
>>> vars(object)['__class__'].__get__(a)
<class '__main__.A'>
>>> class B: pass
...
>>> vars(object)['__class__'].__set__(a, B)
>>> type(a)
<class '__main__.B'>
>>> vars(object)['__class__'].__get__(a)
<class '__main__.B'>
>>> vars(object)['__class__'].__delete__(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't delete __class__ attribute
instance.__class__
如果在
object
的子类中没有覆盖数据描述符
vars(object)['__class__']
,那么
instance.__class__
通过数据描述符访问实例的真实类:
>>> class A: pass
...
>>> a = A()
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class '__main__.A'>
>>> class B: pass
...
>>> a.__class__ = B
>>> type(a)
<class '__main__.B'>
>>> a.__class__
<class '__main__.B'>
>>> del a.__class__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't delete __class__ attribute
但是,如果在一个object
子类中覆盖了数据描述符vars(object)['__class__']
,那么instance.__class__
将无法访问instance
的真实类。此外,如果覆盖不是一个数据描述符,它本身可以在instance
中被覆盖:
>>> class A: __class__ = int
...
>>> a = A()
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class 'int'>
>>> a.__class__ = str
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class 'str'>
>>> del a.__class__
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class 'int'>