Идентифицировать, что переменная является классом нового стиля в Python?
Я использую Python 2.x, и мне интересно, есть ли способ узнать, является ли переменная классом нового стиля? Я знаю, что если это класс старого стиля, я могу сделать следующее, чтобы узнать.
import types
class oldclass:
pass
def test():
o = oldclass()
if type(o) is types.InstanceType:
print 'Is old-style'
else:
print 'Is NOT old-style'
Но я не смог найти ничего, что работает для классов нового стиля. Я нашел этот вопрос, но предлагаемые решения, похоже, не работают так, как ожидалось, потому что простые значения, которые идентифицируются как классы.
import inspect
def newclass(object):
pass
def test():
n = newclass()
if inspect.isclass(n):
print 'Is class'
else:
print 'Is NOT class'
if inspect.isclass(type(n)):
print 'Is class'
else:
print 'Is NOT class'
if inspect.isclass(type(1)):
print 'Is class'
else:
print 'Is NOT class'
if isinstance(n, object):
print 'Is class'
else:
print 'Is NOT class'
if isinstance(1, object):
print 'Is class'
else:
print 'Is NOT class'
Так или иначе, чтобы сделать что-то подобное? Или все в Python просто класс, и нет способа обойти это?
Ответы
Ответ 1
Я думаю, что вы спрашиваете: "Могу ли я проверить, был ли класс определен в коде Python как класс нового стиля?". Технически простые типы, такие как int
, являются классами нового стиля, но по-прежнему можно различать классы, написанные на Python, из встроенных типов.
Здесь что-то работает, хотя это немного взломать:
def is_new_style(cls):
return hasattr(cls, '__class__') \
and \
('__dict__' in dir(cls) or hasattr(cls, '__slots__'))
class new_style(object):
pass
class old_style():
pass
print is_new_style(int)
print is_new_style(new_style)
print is_new_style(old_style)
Выход из Python 2.6:
False
True
False
Здесь другой способ сделать это:
def is_new_style(cls):
return str(cls).startswith('<class ')
Ответ 2
Не то, чтобы "все было классом": вы натыкаетесь на то, что "все - объект " (т.е. всякая вещь (новый стиль) опускается от "объекта",).
Но классы нового стиля сами по себе являются "типом" (на самом деле они были введены для объединения классов и типов). Поэтому вы можете попробовать проверить
import types
type(o) == types.TypeType
Решает ли ваша проблема?
Ответ 3
Я считаю, что этого достаточно:
def is_new_style_class(klass):
return issubclass(klass, object)
def is_new_style_class_instance(instance):
return issubclass(instance.__class__, object)
Как правило, вам нужна только функция is_new_style_class
для ваших целей. Все, что не класс, будет бросать TypeError
, поэтому вы можете обновить его до:
def is_new_style_class(klass):
try:
return issubclass(klass, object)
except TypeError:
return False
Примеры:
>>> class New(object): pass
...
>>> is_new_style_class(New)
True
>>> class Old: pass
...
>>> is_new_style_class(Old)
False
>>> is_new_style_class(1)
False
>>> is_new_style_class(int)
True
int
, являясь типом, по определению является классом нового стиля (см. Унификация типов и классов в Python 2.2), или - если вы предпочитаете - классы нового стиля по типу определений.
Ответ 4
Проверка классов в старом стиле очень проста. Просто проверьте type(cls) is types.ClassType
. Проверка классов нового стиля также проста, isinstance(cls, type)
. Обратите внимание, что встроенные типы также являются классами нового стиля.
Кажется, нет тривиального способа отличить встроенные модули от классов, написанных на Python. В классах нового класса с __slots__ также нет __dict__, как и int
или str
. Проверка соответствия str (cls) ожидаемому шаблону, если класс metaclass переопределяет метод __str__. Некоторые другие способы, которые также не работают:
-
cls.__module__ == '__builtin__'
(вы можете переназначить __module__ в классах)
-
not any(value is cls for value in vars(__builtins__).values())
(вы можете добавить материал в модуль __builtin__).
Тот факт, что унификация встроенных и определяемых пользователем типов настолько хороша, что их отличить от нетривиальной проблемы, должно означать вам базовую точку. Вы действительно не должны различать их. Неважно, что это за объект, если он реализует ожидаемый протокол.