Разница между типом (obj) и obj .__ class__ - PullRequest
39 голосов
/ 30 июня 2009

В чем разница между 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

Ответы [ 3 ]

36 голосов
/ 17 мая 2012

Это старый вопрос, но ни один из ответов, кажется, не упоминает об этом. в общем случае для класса нового стиля 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()

Выход:

<class '__main__.ClassB'>
<class '__main__.ClassA'>
ClassB

Причина в том, что ClassB переопределяет дескриптор __class__, однако поле внутреннего типа в объекте не изменяется. type(instance) читает непосредственно из этого поля типа, поэтому возвращает правильное значение, тогда как instance.__class__ относится к новому дескриптору, заменяющему оригинальный дескриптор, предоставленный Python, который читает внутреннее поле типа. Вместо того, чтобы читать это внутреннее поле типа, он возвращает жестко закодированное значение.

30 голосов
/ 30 июня 2009

Занятия в старом стиле - это проблема, вздох:

>>> class old: pass
... 
>>> x=old()
>>> type(x)
<type 'instance'>
>>> x.__class__
<class __main__.old at 0x6a150>
>>> 

Не проблема в Python 3, так как все классы теперь в новом стиле; -).

В Python 2 класс является новым стилем, только если он наследуется от другого класса нового стиля (включая object и различные встроенные типы, такие как dict, list, set,. ..) или неявно или явно устанавливает __metaclass__ в type.

13 голосов
/ 30 июня 2009

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
...