Разница между старыми и новыми классами в Python?
Какова разница между старыми и новыми стилями классов в Python? Когда следует использовать один из них, а когда - другой?
4 ответ(ов)
С точки зрения объявления:
Новые классы (new-style classes) наследуются от object или от другого нового класса.
class NewStyleClass(object):
pass
class AnotherNewStyleClass(NewStyleClass):
pass
Старые классы (old-style classes) этого не делают.
class OldStyleClass():
pass
Примечание для Python 3:
Python 3 не поддерживает старые классы, поэтому любая форма, указанная выше, приводит к созданию нового класса (new-style class).
В старых классах немного быстрее происходит поиск атрибутов. Это, как правило, не имеет большого значения, но может быть полезно в производительном коде на 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
Как видно из результатов тестирования, доступ к атрибуту объекта класса A
(старый стиль) происходит быстрее, чем у объекта класса B
(новый стиль). Для большинства случаев это несущественно, однако в скоростных критичных приложениях на Python 2.x стоит иметь это в виду.
Вопрос: Как влияет наследование от объекта на поведение классов в Python?
Ответ: Вот очень практическое различие между старыми и новыми классами в Python. Единственное различие между двумя версиями приведенного ниже кода заключается в том, что во второй версии класс Person наследуется от object. В остальном обе версии идентичны, но дают разные результаты:
Старые классы (Old-style classes)
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>
Новые классы (New-style classes)
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(ahmed1 is ahmed2) print(ahmed1) print(ahmed2) >>> True <__main__.Person object at 0xb74ac66c>
Как видно из вывода, в старых классах экземпляры с одинаковыми именами не являются одним и тем же объектом (результат False), в то время как в новых классах экземпляры с одинаковыми именами — это тот же объект (результат True). Это связано с тем, что новые классы (New-style classes), наследуемые от object, изменяют поведение механизма создания объектов в Python.
В новых классах стилей можно использовать super(Foo, self)
, где Foo
— это класс, а self
— это экземпляр.
Функция super(type[, object-or-type])
возвращает прокси-объект, который перенаправляет вызовы методов к родительскому или смежному классу типа. Это полезно для доступа к унаследованным методам, которые были переопределены в классе. Порядок поиска такой же, как и в getattr()
, за исключением того, что сам тип пропускается.
В Python 3.x вы можете просто использовать super()
внутри класса без каких-либо параметров.
Понимание Python super() с методами __init__()
Почему классы в Python наследуют от object?
Изменение типа столбца в pandas
Что делают __init__ и self в Python?
Как красиво и "питонично" реализовать несколько конструкторов?