Вопрос-Ответ

What is the difference between old style and new style classes in Python?

В чем разница между классами старого стиля и классами нового стиля в Python?

В чем разница между классами старого стиля и классами нового стиля в Python? Когда я должен использовать тот или иной?

Переведено автоматически
Ответ 1

Из классов нового стиля и классических классов:


До Python 2.1 классы старого стиля были единственной версией, доступной пользователю.


Концепция класса (старого стиля) не связана с концепцией типа: если x является экземпляром класса старого стиля, то x.__class__ обозначает класс x, но type(x) всегда <type
'instance'>
.


Это отражает тот факт, что все экземпляры старого стиля, независимо от их класса, реализуются с помощью одного встроенного типа, называемого instance .


Классы нового стиля были введены в Python 2.2 для унификации понятий класса и типа. Класс нового стиля - это просто пользовательский тип, ни больше, ни меньше.


Если x является экземпляром класса нового стиля, то type(x) обычно это то же самое, что и x.__class__ (хотя это не гарантируется - экземпляру класса нового стиля разрешено переопределять значение, возвращаемое для x.__class__).


Основной мотивацией для внедрения классов нового стиля является предоставление унифицированной объектной модели с полной метамоделью.


У него также есть ряд непосредственных преимуществ, таких как возможность подкласса большинства встроенных типов или введение "дескрипторов", которые позволяют вычислять свойства.


По соображениям совместимости классы по умолчанию по-прежнему в старом стиле.


Классы нового стиля создаются путем указания другого класса нового стиля (т. Е. Типа) в качестве родительского класса или объекта "тип верхнего уровня", если другой родительский класс не требуется.


Поведение классов нового стиля отличается от поведения классов старого стиля рядом важных деталей в дополнение к тому, какой тип возвращается.


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


В Python 3 есть только классы нового стиля.


Независимо от того, являетесь ли вы подклассом из object или нет, классы в Python 3 созданы в новом стиле.


Ответ 2

С точки зрения объявления:

Классы нового стиля наследуются от object или от другого класса нового стиля.

class NewStyleClass(object):
pass

class AnotherNewStyleClass(NewStyleClass):
pass

Классы старого стиля этого не делают.

class OldStyleClass():
pass

Примечание к Python 3:

Python 3 не поддерживает классы старого стиля, поэтому любая из указанных выше форм приводит к классу нового стиля.

Ответ 3

Важные изменения в поведении между классами старого и нового стилей

Изменен порядок разрешения методов (MRO)

Это упоминалось в других ответах, но здесь приводится конкретный пример разницы между классическим MRO и MRO C3 (используется в классах нового стиля).

Вопрос заключается в порядке, в котором атрибуты (которые включают методы и переменные-члены) ищутся при множественном наследовании.

Классические классы выполняют поиск в глубину слева направо. Останавливаются на первом совпадении. У них нет __mro__ атрибута.

class C: i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 0
assert C21().i == 2

try:
C12.__mro__
except AttributeError:
pass
else:
assert False

Классы нового стиля MRO сложнее синтезировать в одном английском предложении. Это подробно объясняется здесь. Одно из его свойств заключается в том, что поиск базового класса выполняется только после того, как были выполнены все его производные классы. У них есть __mro__ атрибут, который показывает порядок поиска.

class C(object): i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 2
assert C21().i == 2

assert C12.__mro__ == (C12, C1, C2, C, object)
assert C21.__mro__ == (C21, C2, C1, C, object)

Объекты класса нового стиля не могут быть созданы, если они не являются производными от Exception

В Python 2.5 могло быть создано множество классов, а в Python 2.6 это было удалено. В Python 2.7.3:

# OK, old:
class Old: pass
try:
raise Old()
except Old:
pass
else:
assert False

# TypeError, new not derived from `Exception`.
class New(object): pass
try:
raise New()
except TypeError:
pass
else:
assert False

# OK, derived from `Exception`.
class New(Exception): pass
try:
raise New()
except New:
pass
else:
assert False

# `'str'` is a new style object, so you can't raise it:
try:
raise 'str'
except TypeError:
pass
else:
assert False
Ответ 4

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

В [3]: class A:
...: def __init__(self):
...: self.a = 'привет'
...:

В [4]: class B(object):
...: def __init__(self):
...: self.a = 'привет'
...:

В [6]: aobj = A()
В [7]: bobj = B()

В [8]: %timeit aobj.a
10000000 циклов, лучшее из 3: 78,7 нс на цикл

В [10]: %timeit bobj.a
10000000 циклов, лучшее из 3: 86,9 нс на цикл
python class