2015-11-27 4 views
3

Я изучаю методы определения типа переменной (list vs string) внутри python (2.5+) и натолкнулся на некоторые другие ответы, которые казались чрезмерно запутанными.Обнаружение переменного типа в python

Я нашел, что можно сделать

x.__class__.__name__ 

, чтобы получить строку, содержащую имя класса. Что, если что-то, не так с этим? Разве это не переносимо? Когда это провалится?

+2

AFAIK это прекрасно, но что случилось с использованием 'isinstance()'? – doublep

+1

Как насчет 'type()' метода? –

+0

@doublep Абсолютно ничего - это просто подчеркивает мое недоразумение :) – user5611603

ответ

2

Проблема в том, что разные классы могут иметь одно и то же имя.

Простой пример для классов, определенных в разных модулях (например, для общих имен общих имен, таких как Node или Connection).

Однако, это легко продемонстрировать эту проблему даже в одном модуле:

class A(object): pass 
B = A 
class A(object): pass 
C = A 

b = B() 
c = C() 
b.__class__.__name__ == c.__class__.__name__ 
=> True 
type(b) == type(c) 
=> False 

Если вы не должны иметь строковое представление класса, просто используйте type объект, возвращаемый вызовом type(obj).

Конечно, в зависимости от того, для чего вы его используете, лучше всего использовать isinstance вместо того, чтобы иметь дело с type объектами напрямую.

+1

Спасибо, типы объектов были частичным источником путаницы для меня здесь. – user5611603

3

Это не удастся для классов старого стиля; isinstance() работает просто отлично:

>>> class OldStyle: pass 
... 
>>> OldStyle.__class__.__name__ 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: class OldStyle has no attribute '__class__' 
>>> isinstance(OldStyle(), OldStyle) 
True 

Обратите внимание, что лучше использовать isinstance() и принимать подклассов, в том числе виртуальных подклассов (через abstract base classes). Не привязывайте свой код к определенному типу.

Например, вы не хотели бы тестировать obj.__class__.__name__ in ('int', 'float', 'complex'), когда вы могли бы просто использовать isinstance(obj, numbers.Number); таким образом ваш код примет decimal.Decimal объектов тоже.

1

Один общий пит-код для обнаружения строк в Python 2.x будет смешивать str и unicode типов.

assert isinstance("", str) is True 
assert isinstance(u"", str) is True # AssertionError! 
assert isinstance(u"", unicode) is True 
assert isinstance(u"", unicode) is True 
assert isinstance("", unicode) is True # AssertionError! 
# Both lines below are always correct 
assert isinstance("", basestring) is True 
assert isinstance(u"", basestring) is True 

Как вы можете видеть, вся строка выводится из одного базового класса - это то, что позволяет проводить проверку однородного типа. Невозможно, чтобы строка имени класса выглядела вверху.

>>> "".__class__.__name__ 
'str' 
>>> u"".__class__.__name__ 
'unicode' 
1

Вы на самом деле не должен вызывать магические функции, вы могли бы просто использовать type() или isinstance(). Основное различие между ними состоит в том, что isinstance() поддерживает наследование, поэтому, если ваши классы наследуются от других классов, вы можете использовать isinstance().

Смежные вопросы