Ответы:
Из новых и классических классов :
До 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.
super()
не работают на классах старого стиля. Не говоря уже о том, что, как говорится в этой статье, существуют фундаментальные исправления, такие как MRO, и специальные методы, что является более чем веским основанием для его использования.
Декларация-накрест:
Классы нового стиля наследуются от объекта или другого класса нового стиля.
class NewStyleClass(object):
pass
class AnotherNewStyleClass(NewStyleClass):
pass
Классы старого стиля не делают.
class OldStyleClass():
pass
Python 3 Примечание:
Python 3 не поддерживает классы старого стиля, поэтому любая из указанных выше форм приводит к классу нового стиля.
object
.
class AnotherOldStyleClass: pass
class A: pass
и class A(): pass
строго эквивалентны. Первый означает «А не наследует ни один родительский класс», а второй означает «А не наследует ни один родительский класс» . Это очень похоже на not is
иis not
Важные изменения поведения между старыми и новыми классами стиля
Exception
(пример ниже)__slots__
добавленнойЭто было упомянуто в других ответах, но здесь приведен конкретный пример различия между классическим 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:
В [3]: класс А: ...: def __init __ (self): ...: self.a = "привет" ...: В [4]: класс B (объект): ...: 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 нс на цикл
%timeit aobj.a
10000000 loops, best of 3: 66.1 ns per loop
%timeit bobj.a
10000000 loops, best of 3: 53.9 ns per loop
Гвидо написал «Внутреннюю историю о классах нового стиля» , действительно отличную статью о классах нового и старого стиля в Python.
Python 3 имеет только новый класс стиля. Даже если вы пишете «класс старого стиля», он неявно наследуется от object
.
У классов нового стиля есть некоторые расширенные функции, которых нет в классах старого стиля, такие как super
новый C3 mro , некоторые магические методы и т. Д.
Вот очень практичная, истинная / ложная разница. Единственная разница между двумя версиями следующего кода заключается в том, что во второй версии Person наследуется от объекта . Кроме этого, две версии идентичны, но с разными результатами:
Уроки старого стиля
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>
>>>
Уроки нового стиля
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>
>>>
_names_cache
это словарь, который кэширует (сохраняет для будущего поиска) каждое передаваемое вами имя Person.__new__
. Метод setdefault (определенный в любом словаре) принимает два аргумента: ключ и значение. Если ключ находится в dict, он вернет свое значение. Если его нет в dict, он сначала установит для него значение, переданное в качестве второго аргумента, а затем вернет его.
__new__()
он всегда вызывается, и он всегда создает новый объект, а затем выбрасывает его. В этом случае if
предпочтительнее, чем .setdefault()
.
__new__
на самом деле это не вещь для классов старого стиля, она не используется в конструкции экземпляра (это просто случайное имя, которое выглядит особенным, как определение __spam__
). Таким образом, создание класса старого стиля только вызывает __init__
, в то время как конструкция нового стиля вызывает __new__
(объединение с единичным экземпляром по имени), чтобы создать и __init__
инициализировать его.
Классы нового стиля наследуются object
и должны быть написаны как таковые в Python 2.2 и более поздних версиях (т.е. class Classname(object):
вместо class Classname:
). Основное изменение заключается в унификации типов и классов, и приятным побочным эффектом этого является то, что он позволяет вам наследовать от встроенных типов.
Читать descrintro для более подробной информации.
Новые классы стилей могут использовать super(Foo, self)
где Foo
класс и self
экземпляр.
super(type[, object-or-type])
Возвратите прокси-объект, который делегирует вызовы метода родительскому или родственному классу типа. Это полезно для доступа к унаследованным методам, которые были переопределены в классе. Порядок поиска такой же, как в getattr (), за исключением того, что сам тип пропускается.
А в Python 3.x вы можете просто использовать super()
внутри класса без каких-либо параметров.
type(x)
. Если я не делю на подклассы встроенный тип, то, похоже, я не вижу никакого преимущества в классах нового стиля. Есть недостаток, который заключается в дополнительном наборе текста(object)
.