当type(instance)与instance.__class__不同时是什么情况?

11 浏览
0 Comments

当type(instance)与instance.__class__不同时是什么情况?

Python内置了一个名为`type`的函数:

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

Python还有一个特殊的属性`__class__`:

instance.__class__
类实例所属的类。

我曾经认为它们都指向同一个对象。然而,在方法`abc.ABCMeta.__instancecheck__`中有一个检查它们是否相同的语句:

    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__`不同?

0
0 Comments

在Python中,当我们使用type(instance)和instance.__class__来获取一个对象的类型时,有时候会发现这两者的结果不同。这种情况通常出现在旧式对象(不继承任何类)中。这些对象没有__class__属性,我认为他们这样做是为了防止错误发生。

下面是一个Python 2.7的示例:

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__) # 
print(type(b))     # 
# The interesting part
print(a.__class__) # __main__.A
print(type(a))     # 
print(B.__class__) # 
print(type(B))     # 
print(type(A))      # 
#print(A.__class__) # AttributeError: class A has no attribute '__class__'

从上面的例子中可以看出,当我们使用type(instance)和instance.__class__时,对于旧式类来说,结果是不同的。type(instance)返回的是,而instance.__class__返回的是类本身。

这种现象可以通过以下链接进一步了解:

- [Python type() or __class__, == or is](https://stackoverflow.com/questions/9610993)

- [NewClassVsClassicClass](https://wiki.python.org/moin/NewClassVsClassicClass)

- [Why does `type(myField)` return `` and not ``?](https://stackoverflow.com/questions/6666856)

需要注意的是,这种行为在CPython中最后一次更改是在2008年(commit),所以这似乎是一个兼容性问题,或者他们只是忘记了这个问题。

值得一提的是,Python 3.x中已经没有旧式类了,因此这个问题在Python 3.x中不会出现。

0
0 Comments

在上述内容中,"When is type(instance) different from instance.__class__?"这个问题的出现原因是因为在某些情况下,type(instance)和instance.__class__可能会不同。例如,当对象是代理对象时,这两者可能不同。同时,解决这个问题的方法是使用isinstance(x, B)等价于issubclass(x.__class__, B) or issubclass(type(x), B)。此外,还可以使用vars(object)['__class__']来访问实例的真实类。

在上述内容中,type(instance)表示实例的真实类,存储在实例的__class__槽中。可以通过data descriptor vars(object)['__class__']或内置函数type来访问这个真实类。

instance.__class__表示实例的类。如果在object子类中没有重写data descriptor vars(object)['__class__'],那么instance.__class__会通过data descriptor访问实例的真实类。但是,如果在object子类中重写了data descriptor vars(object)['__class__'],那么instance.__class__将不会访问实例的真实类。此外,如果重写的data descriptor不是一个data descriptor,那么它可以被实例中的属性所重写。

type(instance)和instance.__class__之间可能不同的原因是实例的__class__槽被重写或实例是代理对象。解决这个问题的方法是使用isinstance(x, B)等价于issubclass(x.__class__, B) or issubclass(type(x), B)来判断实例的类。另外,可以使用vars(object)['__class__']来访问实例的真实类。

0