Подтвердить что ты не робот

Идентифицировать, что переменная является классом нового стиля в 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 просто класс, и нет способа обойти это?

4b9b3361

Ответ 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__).

Тот факт, что унификация встроенных и определяемых пользователем типов настолько хороша, что их отличить от нетривиальной проблемы, должно означать вам базовую точку. Вы действительно не должны различать их. Неважно, что это за объект, если он реализует ожидаемый протокол.