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

StackOverflow https://stackoverflow.com/questions/54867

Вопрос

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

Это было полезно?

Решение

От http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes :

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

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

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

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

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

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

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

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

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

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

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

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

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

Другие советы

По декларации:

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

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

Классы старого образца этого не делают.

class OldStyleClass():
    pass

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

  • супер добавлен
  • MRO изменено (поясняется ниже)
  • дескрипторы добавлен
  • объекты класса нового стиля не могут быть созданы, если они не получены из Exception (пример ниже)
  • __slots__ добавлен

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

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

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

Классические занятия выполните поиск в глубину слева направо.Остановитесь на первом матче.У них нет __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

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

In [3]: class A:
   ...:     def __init__(self):
   ...:         self.a = 'hi there'
   ...: 

In [4]: class B(object):
   ...:     def __init__(self):
   ...:         self.a = 'hi there'
   ...: 

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

In [8]: %timeit aobj.a
10000000 loops, best of 3: 78.7 ns per loop

In [10]: %timeit bobj.a
10000000 loops, best of 3: 86.9 ns per loop

Гвидо написал Внутренняя история классов нового стиля, действительно отличная статья о классах нового и старого стиля в Python.

В Python 3 есть только класс нового стиля, даже если вы пишете «класс старого стиля», он неявно наследуется от object.

Классы нового стиля имеют некоторые расширенные функции, отсутствующие в классах старого стиля, такие как super и новый С3 ТО, какие-то магические методы и т.д.

Вот очень практичная разница между Истиной и Ложью.Единственная разница между двумя версиями следующего кода заключается в том, что во второй версии Person наследует объект.В остальном эти две версии идентичны, но с разными результатами:

1) классы по старому стилю

class Person():
    _names_cache = {}
    def __init__(self,name):
        self.name = name
    def __new__(cls,name):
        return cls._names_cache.setdefault(name,object.__new__(cls,name))

ahmed1 = Person("Ahmed")
ahmed2 = Person("Ahmed")
print ahmed1 is ahmed2
print ahmed1
print ahmed2


>>> False
<__main__.Person instance at 0xb74acf8c>
<__main__.Person instance at 0xb74ac6cc>
>>>

2) классы нового стиля

class Person(object):
    _names_cache = {}
    def __init__(self,name):
        self.name = name
    def __new__(cls,name):
        return cls._names_cache.setdefault(name,object.__new__(cls,name))

ahmed1 = Person("Ahmed")
ahmed2 = Person("Ahmed")
print ahmed2 is ahmed1
print ahmed1
print ahmed2

>>> True
<__main__.Person object at 0xb74ac66c>
<__main__.Person object at 0xb74ac66c>
>>>

Классы нового стиля наследуются от object и должен быть написан как таковой на Python 2.2 и выше (т. class Classname(object): вместо class Classname:).Основное изменение заключается в унификации типов и классов, а приятным побочным эффектом этого является то, что оно позволяет наследовать встроенные типы.

Читать описание Больше подробностей.

Классы нового стиля могут использовать super(Foo, self) где Foo это класс и self это экземпляр.

super(type[, object-or-type])

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

А в Python 3.x вы можете просто использовать super() внутри класса без параметров.

Или, скорее, вы всегда должны использовать классы нового стиля, пока не у вас есть код, который должен работать с версиями Python старше 2.2.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top