¿Cuál es la diferencia entre el estilo antiguo y las nuevas clases de estilo en Python? ¿Cuándo debo usar uno u otro?
De clases de estilo nuevo y clásico :
Hasta Python 2.1, las clases de estilo antiguo eran el único sabor disponible para el usuario.
El concepto de clase (estilo antiguo) no está relacionado con el concepto de tipo: si
x
es una instancia de una clase de estilo antiguo, entoncesx.__class__
designa la clase dex
, perotype(x)
siempre lo es<type 'instance'>
.Esto refleja el hecho de que todas las instancias de estilo antiguo, independientemente de su clase, se implementan con un único tipo incorporado, llamado instancia.
Se introdujeron nuevas clases de estilo en Python 2.2 para unificar los conceptos de clase y tipo . Una nueva clase de estilo es simplemente un tipo definido por el usuario, ni más ni menos.
Si x es una instancia de una clase de estilo nuevo,
type(x)
normalmente es lo mismo quex.__class__
(aunque esto no está garantizado: una instancia de clase de estilo nuevo puede anular el valor devuelto parax.__class__
).La principal motivación para introducir clases de estilo nuevo 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 integrados, o la introducción de "descriptores", que permiten propiedades calculadas.
Por razones de compatibilidad, las clases siguen siendo antiguas por defecto .
Las clases de estilo nuevo se crean especificando otra clase de estilo nuevo (es decir, un tipo) como una clase principal o el objeto "tipo de nivel superior" si no se necesita otro padre.
El comportamiento de las clases de estilo nuevo difiere del de las clases de estilo antiguo en varios 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 métodos especiales. Otros son "arreglos" que no se pudieron implementar antes por cuestiones de compatibilidad, como el orden de resolución del método en caso de herencia múltiple.
Python 3 solo tiene clases de estilo nuevo .
No importa si subclasa
object
o no, las clases son de nuevo estilo en Python 3.
type(x)
. Si no estoy subclasificando un tipo incorporado, entonces no parece haber ninguna ventaja que pueda ver de las clases de estilo nuevo. Hay una desventaja, que es la tipificación adicional de(object)
.super()
no funcionan en las clases de estilo antiguo. Sin mencionar, como dice ese artículo, hay soluciones fundamentales, como MRO, y métodos especiales, lo cual es más que una buena razón para usarlo.Declaración sabia:
Las clases de estilo nuevo heredan del objeto o de otra clase de estilo nuevo.
Las clases de estilo antiguo no.
Python 3 Nota:
Python 3 no admite clases de estilo antiguas, por lo que cualquiera de los formularios mencionados anteriormente da como resultado una clase de estilo nuevo.
fuente
object
.class AnotherOldStyleClass: pass
class A: pass
yclass A(): pass
son estrictamente equivalentes. El primero significa "A no hereda de ninguna clase principal" y el segundo significa "A no hereda de ninguna clase principal" . Eso es bastante similarnot is
yis not
Cambios importantes de comportamiento entre las clases de estilo antiguas y nuevas.
Exception
(ejemplo a continuación)__slots__
adicionalMRO (Orden de resolución de método) cambiado
Se mencionó en otras respuestas, pero aquí va un ejemplo concreto de la diferencia entre MRO clásico y MRO C3 (usado en nuevas clases de estilo).
La pregunta es el orden en que se buscan los atributos (que incluyen métodos y variables miembro) en herencia múltiple.
Las clases clásicas hacen una búsqueda profunda primero de izquierda a derecha. Detente en el primer partido. No tienen el
__mro__
atributo.Las clases de estilo nuevo 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 solo se busca una clase base una vez que se han buscado todas sus clases derivadas. Tienen el
__mro__
atributo que muestra el orden de búsqueda.No se pueden generar nuevos objetos de clase de estilo a menos que se deriven de
Exception
Alrededor de Python 2.5, muchas clases se podían generar, y alrededor de Python 2.6 se eliminó. En Python 2.7.3:
fuente
Las clases de estilo antiguo siguen siendo marginalmente más rápidas para la búsqueda de atributos. Esto generalmente no es importante, pero puede ser útil en el código Python 2.x sensible al rendimiento:
fuente
%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
Guido ha escrito The Inside Story en New-Style Classes , un artículo realmente genial sobre la clase de estilo nuevo y antiguo en Python.
Python 3 solo tiene una clase de estilo nuevo. Incluso si escribe una 'clase de estilo antiguo', se deriva implícitamente de
object
.Las clases de estilo nuevo tienen algunas características avanzadas que faltan en las clases de estilo antiguo, como
super
el nuevo C3 mro , algunos métodos mágicos, etc.fuente
Aquí hay una muy práctica, verdadera / falsa diferencia. 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:
Clases de estilo antiguo
Clases de nuevo estilo
fuente
_names_cache
es un diccionario que almacena en caché (almacena para la recuperación futura) cada nombre que le pasePerson.__new__
. El método setdefault (definido en cualquier diccionario) toma dos argumentos: una clave y un valor. Si la clave está en el dict, devolverá su valor. Si no está en el dict, lo establecerá primero en el valor pasado como segundo argumento y luego lo devolverá.__new__()
siempre se llama, y siempre construye un nuevo objeto, y luego lo arroja. En este casoif
es preferible a.setdefault()
.__new__
en realidad no es algo para las clases de estilo antiguo, no se usa en la construcción de instancias (es solo un nombre aleatorio que se ve especial, como definir__spam__
). Por lo tanto, construir la clase de estilo antiguo solo invoca__init__
, mientras que la construcción de estilo nuevo invoca__new__
(fusionándose a instancia de singleton por nombre) para construir e__init__
inicializar.Las clases de estilo nuevo heredan
object
y deben escribirse como tales en Python 2.2 en adelante (es decir, enclass Classname(object):
lugar declass Classname:
). El cambio principal es unificar tipos y clases, y el efecto secundario de esto es que le permite heredar de los tipos incorporados.Lea la descripción para más detalles.
fuente
Las nuevas clases de estilo pueden usar
super(Foo, self)
whereFoo
es una clase yself
es la instancia.Y en Python 3.x simplemente puede usar
super()
dentro de una clase sin ningún parámetro.fuente