В чем разница между старым стилем и новыми классами стилей в Python?
В чем разница между старым и новым стилем классов в Python? Когда я должен использовать один или другой?
Ответы
Ответ 1
Из 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.
Ответ 2
Декларация-накрест:
Классы нового стиля наследуются от объекта или другого класса нового стиля.
class NewStyleClass(object):
pass
class AnotherNewStyleClass(NewStyleClass):
pass
Классы старого стиля не делают.
class OldStyleClass():
pass
Python 3 Примечание:
Python 3 не поддерживает классы старого стиля, поэтому любая из указанных выше форм приводит к классу нового стиля.
Ответ 3
Важные изменения поведения между старыми и новыми классами стиля
- 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
Ответ 4
Классы старого стиля все еще немного быстрее для поиска атрибутов. Обычно это не важно, но может быть полезно для высокопроизводительного кода 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
Ответ 5
Guido написал Inside Story on New-Style Classes, действительно отличную статью о классе нового стиля и старого стиля в Python.
Python 3 имеет только класс нового стиля, даже если вы пишете "класс старого стиля", он неявно выводится из object
.
В классах нового стиля есть некоторые дополнительные функции, отсутствующие в классах старого стиля, например super
и новый C3 mro, некоторые магические методы и т.д.
Ответ 6
Здесь очень практичная, истинная/ложная разница. Единственная разница между двумя версиями следующего кода заключается в том, что во второй версии 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>
>>>
Ответ 7
Классы нового стиля наследуются от object
и должны быть написаны как таковые в Python 2.2 и более поздних версиях (т.е. class Classname(object):
вместо class Classname:
). Основное изменение заключается в унификации типов и классов, и приятным побочным эффектом этого является то, что он позволяет вам наследовать от встроенных типов.
Прочтите descrintro для более подробной информации.
Ответ 8
Новые классы стиля могут использовать super(Foo, self)
, где Foo
- это класс, а self
- это экземпляр.
super(type[, object-or-type])
Возвращает прокси-объект, который делегирует вызовы методов родительскому или родному классу типа. Это полезно для доступа к унаследованным методам, которые были переопределены в классе. Порядок поиска такой же, как и для getattr(), за исключением того, что сам тип пропускается.
И в Python 3.x вы можете просто использовать super()
внутри класса без параметров.
Ответ 9
Вернее, вы всегда должны использовать классы нового стиля, если у вас нет кода, который должен работать с версиями Python старше 2.2.