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

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

861
10 сент. '08 в 21:01
источник поделиться
9 ответов

Из 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.

489
10 сент. '08 в 21:02
источник

Декларация-накрест:

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

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

В классах старого стиля нет.

class OldStyleClass():
    pass
283
30 июля '09 в 4:21
источник

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

  • super добавлен
  • 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
195
13 нояб. '13 в 12:36
источник

Классы старого стиля все еще немного быстрее для поиска атрибутов. Обычно это не важно, но может быть полезно для высокопроизводительного кода 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
35
12 июля '10 в 14:26
источник

Guido написал Inside Story on New-Style Classes, действительно отличную статью о классе нового стиля и старого стиля в Python.

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

В классах нового стиля есть некоторые дополнительные функции, отсутствующие в классах старого стиля, например super и новый C3 mro, некоторые магические методы и т.д.

30
24 апр. '13 в 16:41
источник

Здесь очень практичная, истинная/ложная разница. Единственная разница между двумя версиями следующего кода заключается в том, что во второй версии 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>
>>>
17
09 окт. '13 в 16:40
источник

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

Подробнее читайте descrintro.

7
28 окт. '08 в 12:54
источник

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

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

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

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

4
30 апр. '13 в 11:28
источник

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

3
11 сент. '08 в 0:23
источник

Посмотрите другие вопросы по меткам или Задайте вопрос