Что такое и чем отличается old-style от new-style classespython-99

Исторический контекст

В Python 2.x существовало два типа классов:

  1. Old-style (классические) классы - наследники только от object через types.ClassType
  2. New-style (новые) классы - явно наследующие от object или другого new-style класса

В Python 3 все классы являются new-style, и концепция old-style классов полностью удалена.

Ключевые различия

1. Объявление классов

Old-style (Python 2):

class OldClass:  # Не наследует от object
    pass

New-style (Python 2 и 3):

class NewClass(object):  # Явное наследование от object
    pass

# В Python 3 все классы автоматически new-style
class ModernClass:  # Неявно наследует от object
    pass

2. Метод разрешения

Old-style:

  • Использует глубинный поиск (DFS)
  • Может приводить к неинтуитивному порядку разрешения методов

New-style:

  • Использует алгоритм C3 linearization
  • Более предсказуемый и логичный порядок

Пример:

# Для old-style классов
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
# Порядок: D → B → A → C → A (дублирование A)

# Для new-style классов
class A(object): pass
class B(A): pass
class C(A): pass
class D(B, C): pass
# Порядок: D → B → C → A (корректный)

3. Доступ к атрибутам

Old-style:

  • Использует классическую модель поиска атрибутов
  • Нет поддержки __slots__, дескрипторов, свойств

New-style:

  • Единая модель дескрипторов
  • Поддержка property, __slots__, __getattribute__

4. Встроенные функции

New-style добавляет:

  • super() - улучшенная версия для работы с MRO
  • Декораторы методов (@classmethod, @staticmethod)
  • Магические методы (__new__, __prepare__)

5. Тип класса

Old-style:

type(OldClass)  # <type 'classobj'>
type(OldClass())  # <type 'instance'>

New-style:

type(NewClass)  # <type 'type'>
type(NewClass())  # <class '__main__.NewClass'>

Практические различия

  1. Метаклассы работают только с new-style
  2. Дескрипторы (property и др.) полноценно работают только в new-style
  3. super() ведет себя по-разному
  4. Множественное наследование более предсказуемо в new-style

Пример проблем old-style

class A:
    def __init__(self):
        print("A init")

class B(A):
    def __init__(self):
        print("B init")
        A.__init__(self)  # Явный вызов - проблема при множественном наследовании

class C(A):
    def __init__(self):
        print("C init")
        A.__init__(self)

class D(B, C):
    def __init__(self):
        print("D init")
        B.__init__(self)
        C.__init__(self)  # A.__init__ вызывается дважды!

d = D()

Современный подход

class A(object):
    def __init__(self):
        print("A init")

class B(A):
    def __init__(self):
        print("B init")
        super().__init__()  # Автоматически учитывает MRO

class C(A):
    def __init__(self):
        print("C init")
        super().__init__()

class D(B, C):
    def __init__(self):
        print("D init")
        super().__init__()  # Вызовет B, затем C, затем A - каждый по одному разу

d = D()
print(D.__mro__)  # Показывает порядок разрешения методов

Резюмируем

  1. Old-style - устаревший тип классов из Python 2 (до 2.1)
  2. New-style - современные классы (Python 2.2+ и Python 3)
  3. Основные различия:
    • Наследование от object
    • Алгоритм MRO (C3 linearization)
    • Поддержка дескрипторов и super()
    • Единая модель типов
  4. В Python 3 все классы new-style
  5. New-style классы обеспечивают:
    • Более предсказуемое поведение
    • Лучшую поддержку ООП-возможностей
    • Совместимость с современными фичами Python

Если вы работаете с Python 3, вам не нужно беспокоиться об этом различии - все классы автоматически new-style. Знание этих различий важно для:

  • Поддержки legacy-кода на Python 2
  • Понимания эволюции Python
  • Глубокого понимания системы классов