type(obj)和obj .__ class__之间的区别

44 python new-style-class

type(obj)和之间有什么区别obj.__class__?有可能type(obj) is not obj.__class__吗?

我想编写一个在提供的对象上一般工作的函数,使用与另一个参数相同类型的默认值1.下面的#1或#2哪个变体会做正确的事情?

def f(a, b=None):
  if b is None:
    b = type(a)(1) # #1
    b = a.__class__(1) # #2
Run Code Online (Sandbox Code Playgroud)

Fla*_*ien 41

这是一个老问题,但没有一个答案似乎提到这一点.在一般情况下,IS可能一个新式类有不同的值type(instance)instance.__class__:

class ClassA(object):
    def display(self):
        print("ClassA")

class ClassB(object):
    __class__ = ClassA

    def display(self):
        print("ClassB")

instance = ClassB()

print(type(instance))
print(instance.__class__)
instance.display()
Run Code Online (Sandbox Code Playgroud)

输出:

<class '__main__.ClassB'>
<class '__main__.ClassA'>
ClassB
Run Code Online (Sandbox Code Playgroud)

原因是ClassB覆盖了__class__描述符,但是对象中的内部类型字段没有改变.type(instance)直接从该类型字段读取,因此它返回正确的值,而instance.__class__引用新的描述符替换Python提供的原始描述符,后者读取内部类型字段.它不是读取内部类型字段,而是返回硬编码值.

  • _Caveat lector_:这应该作为为什么你应该避免覆盖`__class__`的一个例子!您可能会导致使用`__class__`的行中的代码中断. (14认同)
  • 也受到`__getattribute__`的影响,它拦截了对'OBJ .__ class__`的请求,但没有拦截`type(OBJ)`的请求. (4认同)
  • 这里需要注意的重要一点是:在 _instance_ 中分配 `__class__` 属性**将**有效地更改其类型和“真实”类(包括事后更改“type”和“isinstance”响应) (4认同)
  • 一些代码故意这样做是为了掩盖对象的类型,例如`weakref.proxy`。有些人认为obj .__ class__应该是首选,因为它相信谎言,而有些人则认为type(obj)应该是首选,因为它忽略了谎言。如果对象的真实类或其谎言类是第二个参数的实例,则“ isinstance”将返回true。 (2认同)

Ale*_*lli 30

老式的课是问题,感叹:

>>> class old: pass
... 
>>> x=old()
>>> type(x)
<type 'instance'>
>>> x.__class__
<class __main__.old at 0x6a150>
>>> 
Run Code Online (Sandbox Code Playgroud)

在Python 3中不是问题,因为现在所有的类都是新式的;-).

在Python 2,一类是仅当它从另一个新式类(包括继承的新风格object和各种内置的类型,如dict,list,set,...),或含蓄或明确设置__metaclass__type.

  • 这是Python 3时间,*我们应该使用*? (3认同)
  • @Alex Martelli @AaronHall 内置函数 `type(instance)` 和属性 `instance.__class__` 可以不同,即使使用 [new-style classes](https://docs.python.org/2/reference /datamodel.html#new-style-and-classic-classes),正如 Guido 在 [PEP 3119](https://www.python.org/dev/peps/pep-3119/#the-abc-module- an-abc-support-framework):“此外,`isinstance(x, B)` 等价于 `issubclass(x.__class__, B) 或 issubclass(type(x), B)`。(也可能是 `type (x)` 和 `x.__class__` 不是同一个对象,例如当 `x` 是代理对象时。)”和@Flavien 的回答所示。 (3认同)
  • 如果你的代码遵循Alex描述的最佳实践,那么`type()`会更好.在Python 3中,它始终遵循最佳实践,因此在Python 3中使用type(). (2认同)

Mar*_*ddy 14

type(obj)并且type.__class__对于旧样式类的行为不同:

>>> class a(object):
...     pass
...
>>> class b(a):
...     pass
...
>>> class c:
...     pass
...
>>> ai=a()
>>> bi=b()
>>> ci=c()
>>> type(ai) is ai.__class__
True
>>> type(bi) is bi.__class__
True
>>> type(ci) is ci.__class__
False
Run Code Online (Sandbox Code Playgroud)

  • 如果*他们的表现不同,也许*为什么*会不会有害.只是说*当*表现不同时,即使是正确的,也会发出懒惰的回答. (11认同)
  • 最大的讽刺是yairchu的评论现在有同样的问题,因为他们切换格式..:P (7认同)
  • 值得一提的是,这只是Python 2中的问题。在Python 3中,所有三个表达式均为True。 (5认同)

leo*_*ama 6

代理对象(使用弱引用)有一个有趣的边缘情况:

>>> import weakref
>>> class MyClass:
...     x = 42
... 
>>> obj = MyClass()
>>> obj_proxy = weakref.proxy(obj)
>>> obj_proxy.x  # proxies attribute lookup to the referenced object
42
>>> type(obj_proxy)  # returns type of the proxy 
weakproxy
>>> obj_proxy.__class__  # returns type of the referenced object
__main__.MyClass
>>> del obj  # breaks the proxy's weak reference
>>> type(obj_proxy)  # still works
weakproxy
>>> obj_proxy.__class__  # fails
ReferenceError: weakly-referenced object no longer exists
Run Code Online (Sandbox Code Playgroud)