首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >什么时候类型(实例)与instance.__class__不同?

什么时候类型(实例)与instance.__class__不同?
EN

Stack Overflow用户
提问于 2017-02-22 07:18:17
回答 2查看 922关注 0票数 11

Python有内置函数type

type(对象) 使用一个参数,返回对象的类型。返回值是一个类型对象,通常与object.__class__返回的对象相同。

Python还有一个特殊的属性__class__

例如.__class__ 类实例所属的类。

我曾经相信他们都是指同一个对象。但是,在方法abc.ABCMeta.__instancecheck__中,需要检查它们是否相同:

代码语言:javascript
运行
复制
    def __instancecheck__(cls, instance):
        """Override for isinstance(instance, cls)."""
        # Inline the cache checking
        subclass = instance.__class__
        # […]
        subtype = type(instance)
        if subtype is subclass:
        # […]

type(instance)instance.__class__什么时候不同?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-12-13 08:13:08

type(instance)instance.__class__可能有所不同,即使新型课程也是如此,就像Guido在佩普3119中提到的那样

而且,isinstance(x, B)等同于issubclass(x.__class__, B) or issubclass(type(x), B)。( type(x)x.__class__可能不是同一个对象,例如,当x是代理对象时。)

例如,标准库的函数weakref.proxy创建代理对象。

代码语言:javascript
运行
复制
>>> 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__槽中(即实例布局中的固定偏移量)。它只能通过数据描述符 vars(object)['__class__'] (其方法__get__允许属性检索,其方法__set__允许属性分配,其方法__delete__禁止属性删除)访问,或者通过内置函数type (其单参数形式允许属性检索)进行等效访问:

代码语言:javascript
运行
复制
>>> 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__

如果数据描述符vars(object)['__class__']object子类中未被重写,则instance.__class__通过数据描述符访问instance的实际类:

代码语言:javascript
运行
复制
>>> 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

但是,如果数据描述符vars(object)['__class__']object子类中被重写,instance.__class__就不会访问真正的instance类。此外,如果重写不是数据描述符,那么它本身可以在instance中被重写。

代码语言:javascript
运行
复制
>>> class A: __class__ = int  # overrides vars(object)['__class__']
... 
>>> a = A()
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class 'int'>
>>> a.__class__ = str  # overrides vars(A)['__class__'] (not a data descriptor)
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class 'str'>
>>> del a.__class__
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class 'int'>
票数 4
EN

Stack Overflow用户

发布于 2017-02-22 07:52:26

旧式对象(从无继承)就是这种情况。这些对象没有__class__属性。我认为他们这样做是为了防止错误。Python 2.7示例:

代码语言:javascript
运行
复制
class A:
    pass

class B(object):
    pass

a = A()
b = B()

print(dir(a)) # ['__doc__', '__module__']
print(dir(b)) # ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

print(b.__class__) # <class '__main__.B'>
print(type(b))     # <class '__main__.B'>

#####################
# The intersting part
print(a.__class__) # __main__.A
print(type(a))     # <type 'instance'>


print(B.__class__) # <type 'type'>
print(type(B))     # <type 'type'>

print(type(A))      # <type 'classobj'>
#print(A.__class__) # AttributeError: class A has no attribute '__class__'

详情见此:

注意:上一次(提交)修改了来自cpython的给定行,所以它看起来确实是一个兼容性问题,或者他们只是忘记了它。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42384991

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档