Разница между типом (obj) и obj.__class__
-
21-08-2019 - |
Вопрос
В чем разница между 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
Решение
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
Другие советы
Это старый вопрос, но ни в одном из ответов, похоже, об этом не упоминается.в общем случае это ЯВЛЯЕТСЯ возможно, что класс нового стиля будет иметь разные значения для 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, который считывает внутреннее поле типа.Вместо того чтобы считывать это внутреннее поле типа, оно возвращает жестко закодированное значение.
Проблема в классах старого стиля, вздыхаю:
>>> 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
.