¿Cuál es la diferencia entre las clases de estilo antiguo y nuevo en Python?

¿Cuál es la diferencia entre las clases de estilo antiguo y nuevo en Python? ¿Cuándo debo usar uno o el otro?

De http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes :

Hasta Python 2.1, las clases antiguas eran el único sabor disponible para el usuario.

El concepto de clase (de estilo antiguo) no está relacionado con el concepto de tipo: si x es una instancia de una clase de estilo antiguo, entonces x.__class__ designa la clase de x , pero el type(x) siempre es .

Esto refleja el hecho de que todas las instancias de estilo antiguo, independientemente de su clase, se implementan con un solo tipo integrado, llamado instancia.

Las clases de nuevo estilo se introdujeron en Python 2.2 para unificar los conceptos de clase y tipo . Una clase de nuevo estilo es simplemente un tipo definido por el usuario, ni más ni menos.

Si x es una instancia de una clase de nuevo estilo, entonces el type(x) suele ser el mismo que x.__class__ (aunque esto no está garantizado, se permite una instancia de clase de nuevo estilo para anular el valor devuelto para x.__class__ ) .

La motivación principal para introducir clases de nuevo estilo es proporcionar un modelo de objeto unificado con un metamodelo completo .

También tiene una serie de beneficios inmediatos, como la capacidad de subclasificar la mayoría de los tipos incorporados, o la introducción de “descriptores”, que permiten las propiedades computadas.

Por razones de compatibilidad, las clases siguen siendo de estilo antiguo por defecto .

Las clases de nuevo estilo se crean especificando otra clase de nuevo estilo (es decir, un tipo) como clase principal, o el objeto “tipo de nivel superior” si no se necesita ningún otro padre.

El comportamiento de las clases de nuevo estilo difiere del de las clases de estilo antiguo en una serie de detalles importantes además de qué tipo devuelve.

Algunos de estos cambios son fundamentales para el nuevo modelo de objetos, como la forma en que se invocan los métodos especiales. Otros son “arreglos” que no se pudieron implementar antes por problemas de compatibilidad, como el orden de resolución del método en caso de herencia múltiple.

Python 3 solo tiene clases de nuevo estilo .

No importa si subclasifica de object o no, las clases son de estilo nuevo en Python 3.

Declaración en cuanto a:

Las clases de nuevo estilo se heredan de un objeto o de otra clase de nuevo estilo.

 class NewStyleClass(object): pass class AnotherNewStyleClass(NewStyleClass): pass 

Las clases antiguas no lo hacen.

 class OldStyleClass(): pass 

Cambios importantes de comportamiento entre clases de estilo antiguo y nuevo.

  • super agregado
  • MRO cambiado (explicado abajo)
  • descriptores añadidos
  • los nuevos objetos de clase de estilo no se pueden levantar a menos que se deriven de Exception (ejemplo a continuación)
  • __slots__ agregado

MRO (Orden de resolución de métodos) cambiado

Se mencionó en otras respuestas, pero aquí va un ejemplo concreto de la diferencia entre el MRO clásico y el C3 MRO (usado en las nuevas clases de estilo).

La pregunta es el orden en que se buscan los atributos (que incluyen métodos y variables de miembro) en herencia múltiple.

Las clases clásicas hacen una primera búsqueda profunda de izquierda a derecha. Pare en el primer partido. No tienen el atributo __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 

Las clases de nuevo estilo MRO son más complicadas de sintetizar en una sola oración en inglés. Se explica en detalle aquí . Una de sus propiedades es que una clase Base solo se busca una vez que todas sus clases Derivadas hayan sido buscadas. Tienen el atributo __mro__ que muestra el orden de búsqueda.

 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) 

Los nuevos objetos de clase de estilo no se pueden levantar a menos que se deriven de la Exception

Alrededor de Python 2.5, se podrían elevar muchas clases, alrededor de Python 2.6 esto se eliminó. En 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 

Las clases de estilo antiguo aún son ligeramente más rápidas para la búsqueda de atributos. Esto no suele ser importante, pero puede ser útil en el código de Python 2.x, que es sensible al rendimiento:

 En [3]: clase A:
    ...: def __init __ (self):
    ...: self.a = 'hi there'
    ...: 

 En [4]: ​​clase B (objeto):
    ...: def __init __ (self):
    ...: self.a = 'hi there'
    ...: 

 En [6]: aobj = A ()
 En [7]: bobj = B ()

 En [8]:% timeit aobj.a
 10000000 bucles, lo mejor de 3: 78.7 ns por bucle

 En [10]:% timeit bobj.a
 10000000 bucles, lo mejor de 3: 86.9 ns por bucle

Guido ha escrito The Inside Story en New-Style Classes , un excelente artículo sobre el estilo nuevo y la clase de estilo antiguo en Python.

Python 3 solo tiene una clase de estilo nuevo, incluso si escribe una ‘clase de estilo antiguo’, se deriva implícitamente del object .

Las clases de nuevo estilo tienen algunas características avanzadas que faltan en las clases de estilo antiguo, como super y el nuevo C3 Mro , algunos métodos mágicos, etc.

Aquí hay una diferencia muy práctica, Verdadero / Falso. La única diferencia entre las dos versiones del siguiente código es que, en la segunda versión, la persona hereda del objeto. Aparte de eso, las dos versiones son idénticas, pero con resultados diferentes:

1) clases de estilo antiguo

 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) clases de nuevo estilo

 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> >>> 

Las clases de estilo nuevo se heredan del object y se deben escribir como tales en Python 2.2 en adelante (es decir, class Classname(object): lugar de class Classname: . El cambio principal es unificar tipos y clases, y el efecto colateral de esto es que le permite heredar de los tipos incorporados.

Lea descrintro para más detalles.

Las nuevas clases de estilo pueden usar super(Foo, self) donde Foo es una clase y self es la instancia.

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

Devuelva un objeto proxy que delegue las llamadas de método a una clase de tipo padre o hermana. Esto es útil para acceder a los métodos heredados que se han anulado en una clase. El orden de búsqueda es el mismo que el utilizado por getattr (), excepto que se omite el tipo en sí.

Y en Python 3.x puedes simplemente usar super() dentro de una clase sin parámetros.

O más bien, siempre debe usar clases de estilo nuevo, a menos que tenga un código que necesite trabajar con versiones de Python anteriores a la 2.2.