La clase Python hereda el objeto


1245

¿Hay alguna razón para que una declaración de clase herede object?

Acabo de encontrar un código que hace esto y no puedo encontrar una buena razón.

class MyClass(object):
    # class code follows...

2
Esto crea una nueva clase de estilo .
SLaks

116
La respuesta a esta pregunta (aunque simple) es bastante difícil de encontrar. Buscar en Google cosas como "clase base de objeto de Python" o similar aparece con páginas y páginas de tutoriales sobre programación orientada a objetos. Votación a favor porque este es el primer enlace que me llevó a los términos de búsqueda "objetos de pitón antiguos frente a nuevos"
vastlysuperiorman

Respuestas:


765

¿Hay alguna razón para que una declaración de clase herede object?

En Python 3, aparte de la compatibilidad entre Python 2 y 3, no hay razón . En Python 2, muchas razones .


Historia de Python 2.x:

En Python 2.x (desde 2.2 en adelante) hay dos estilos de clases dependiendo de la presencia o ausencia de objectuna clase base:

  1. Clases de estilo "clásico" : no tienen objectcomo clase base:

    >>> class ClassicSpam:      # no base class
    ...     pass
    >>> ClassicSpam.__bases__
    ()
  2. Clases de estilo "nuevas" : tienen, directa o indirectamente (por ejemplo, heredar de un tipo incorporado ), objectcomo una clase base:

    >>> class NewSpam(object):           # directly inherit from object
    ...    pass
    >>> NewSpam.__bases__
    (<type 'object'>,)
    >>> class IntSpam(int):              # indirectly inherit from object...
    ...    pass
    >>> IntSpam.__bases__
    (<type 'int'>,) 
    >>> IntSpam.__bases__[0].__bases__   # ... because int inherits from object  
    (<type 'object'>,)

Sin duda, al escribir una clase siempre querrás ir a clases de estilo nuevo. Las ventajas de hacerlo son numerosas, para enumerar algunas de ellas:

  • Soporte para descriptores . Específicamente, las siguientes construcciones son posibles con descriptores:

    1. classmethod: Un método que recibe la clase como un argumento implícito en lugar de la instancia.
    2. staticmethod: Un método que no recibe el argumento implícito self como primer argumento.
    3. propiedades con property: Crear funciones para gestionar la obtención, configuración y eliminación de un atributo.
    4. __slots__: Guarda los consumos de memoria de una clase y también da como resultado un acceso de atributos más rápido. Por supuesto, impone limitaciones .
  • El __new__método estático: le permite personalizar cómo se crean nuevas instancias de clase.

  • Orden de resolución de método (MRO) : en qué orden se buscarán las clases base de una clase al intentar resolver qué método llamar.

  • Relacionado con MRO, superllamadas . Ver también, super()considerado super.

Si no heredas de object, olvídate de estos. Aquí se puede encontrar una descripción más exhaustiva de los puntos anteriores junto con otras ventajas de las "nuevas" clases de estilo .

Una de las desventajas de las clases de estilo nuevo es que la clase en sí misma requiere más memoria. Sin embargo, a menos que esté creando muchos objetos de clase, dudo que esto sea un problema y que sea un hundimiento negativo en un mar de positivos.


Historia de Python 3.x:

En Python 3, las cosas se simplifican. Solo existen clases de estilo nuevo (a las que se hace referencia claramente como clases), por lo que la única diferencia al agregar objectes que debe escribir 8 caracteres más. Esta:

class ClassicSpam:
    pass

es completamente equivalente (aparte de su nombre :-) a esto:

class NewSpam(object):
     pass

y a esto:

class Spam():
    pass

Todos tienen objecten su __bases__.

>>> [object in cls.__bases__ for cls in {Spam, NewSpam, ClassicSpam}]
[True, True, True]

¿Entonces, qué debería hacer?

En Python 2: siempre herede de forma objectexplícita . Obtén las ventajas.

En Python 3: herede objectsi está escribiendo código que intenta ser independiente de Python, es decir, debe funcionar tanto en Python 2 como en Python 3. De lo contrario, no hay diferencia, ya que Python lo inserta por usted entre bastidores.


"dependiendo de la presencia o ausencia de un tipo incorporado como clase base" => en realidad no se trata de "ausencia o presencia de un tipo incorporado como clase base" sino de si la clase hereda, directa o indirectamente , de object. IIRC hubo un punto en el tiempo en el que no todos los tipos incorporados fueron transferidos a clases de estilo nuevo todavía.
bruno desthuilliers

@brunodesthuilliers Mi impresión fue que todos los tipos integrados heredaron object. Tengo un Python 2.2.3 alrededor y, después de una comprobación rápida, no pude encontrar un delincuente, pero volveré a redactar la respuesta más adelante para aclararlo. Sin embargo, me interesaría si pudieras encontrar un ejemplo, mi curiosidad se despertó.
Dimitris Fasarakis Hilliard

Con toda honestidad (ver el "IIRC" en mi comentario anterior) no estoy 101% seguro de este punto (si todos los tipos incorporados ya se convirtieron en clases de estilo nuevo cuando se introdujeron clases de estilo nuevo), podría ser simple mal, o esto solo podría haber afectado a algunos de los tipos de lib estándar (pero no incorporados). Pero, sin embargo, creo que debería ser mejor aclarar que lo que hace que una clase de estilo nuevo esté objecten sus bases.
bruno desthuilliers

77
lástima stackoverflow solo hace upvote = upvote + 1 para estas respuestas, desearía poder hacer upvote + = N
PirateApp

1
staticmethody classmethodfunciona bien incluso en clases de estilo antiguo. propertymás o menos funciona para leer en clases de estilo antiguo, simplemente no intercepta las escrituras (por lo tanto, si asigna el nombre, la instancia obtiene un atributo del nombre dado que sombrea la propiedad). También tenga en cuenta que __slots__la mejora en la velocidad de acceso al atributo se trata principalmente de deshacer la pérdida en la que incurre el acceso al atributo de la clase de estilo nuevo, por lo que no es realmente un punto de venta de las clases de estilo nuevo (aunque el ahorro de memoria es un punto de venta).
ShadowRanger

540

Python 3

  • class MyClass(object): = Clase de nuevo estilo
  • class MyClass:= Clase de estilo nuevo (hereda implícitamente de object)

Python 2

  • class MyClass(object): = Clase de nuevo estilo
  • class MyClass:= CLASE DE ESTILO ANTIGUO

Explicacion :

Al definir clases base en Python 3.x, se le permite soltar el object de la definición. Sin embargo, esto puede abrir la puerta a un problema realmente difícil de rastrear ...

Python introdujo clases de estilo nuevo en Python 2.2, y ahora las clases de estilo antiguo son realmente bastante antiguas. La discusión de las clases de estilo antiguo está enterrada en los documentos 2.x , y no existe en los documentos 3.x.

El problema es que la sintaxis para las clases de estilo antiguo en Python 2.x es la misma que la sintaxis alternativa para las clases de estilo nuevo en Python 3.x . Python 2.x todavía se usa ampliamente (por ejemplo, GAE, Web2Py), y cualquier código (o codificador) que, sin saberlo, traiga definiciones de clase de estilo 3.x al código 2.x terminará con algunos objetos base muy desactualizados. Y debido a que las clases de estilo antiguo no están en el radar de nadie, probablemente no sabrán qué les golpeó.

Así que deletrearlo en el camino largo y salvar a algunos desarrolladores 2.x las lágrimas.


13
"Al definir las clases base en Python 3.x, se le permite eliminar el objeto de la definición. Sin embargo, esto puede abrir la puerta a un problema muy difícil de rastrear ..." ¿A qué problemas se refiere?
Aidis

66
@Aidis: Creo que significan que el código que se ejecuta tanto en Py2 como en Py3 estaría bien en Py3, pero se rompería en Py2 si se basa en características de clase de nuevo estilo. Personalmente, si estoy escribiendo un código como ese, omito la herencia explícita y solo pongo __metaclass__ = typeen la parte superior del módulo (después de la from __future__ import absolute_import, division, print_functionlínea :-)); es un truco de compatibilidad en Py2 que hace que todas las clases definidas posteriormente en el módulo sean de nuevo estilo por defecto, y en Py3, se ignora por completo (solo una variable global aleatoria sentada), por lo que es inofensivo.
ShadowRanger

400

Sí, este es un objeto 'nuevo estilo'. Era una característica introducida en python2.2.

Los nuevos objetos de estilo tienen un modelo de objeto diferente a los objetos clásicos, y algunas cosas no funcionarán correctamente con objetos de estilo antiguos, por ejemplo super(), @propertyy descriptores. Consulte este artículo para obtener una buena descripción de lo que es una nueva clase de estilo.

Enlace SO para una descripción de las diferencias: ¿Cuál es la diferencia entre el estilo antiguo y las nuevas clases de estilo en Python?


110
+1 esto. Tenga en cuenta que las clases de estilo antiguo se han ido en Python 3, por lo que sólo necesita heredar de objecten Python 2.

99
Esta no es una respuesta real. Solo hago referencia a otros artículos. Creo que la respuesta de Yarin debería aceptarse como la respuesta a esta pregunta.
alwbtc

2
@alwbtc: Esta respuesta también tiene algo nuevo. Por ejemplo, la mención de "super ()" me llevó a otro importante [aquí] ( stackoverflow.com/questions/576169/… ).
ViFI

34

Historia de Learn Python the Hard Way :

La versión original de Python de una clase se rompió de muchas maneras serias. Cuando se reconoció esta falla, ya era demasiado tarde y tuvieron que apoyarla. Para solucionar el problema, necesitaban un estilo de "nueva clase" para que las "viejas clases" siguieran funcionando, pero puede usar la nueva versión más correcta.

Decidieron que usarían una palabra "objeto", en minúscula, para ser la "clase" de la que se hereda para hacer una clase. Es confuso, pero una clase hereda de la clase llamada "objeto" para hacer una clase, pero no es un objeto realmente es una clase, pero no olvide heredar del objeto.

También para hacerle saber cuál es la diferencia entre las clases de estilo nuevo y las clases de estilo antiguo, es que las clases de estilo nuevo siempre heredan de la objectclase o de otra clase que hereda de object:

class NewStyle(object):
    pass

Otro ejemplo es:

class AnotherExampleOfNewStyle(NewStyle):
    pass

Mientras que una clase base de estilo antiguo se ve así:

class OldStyle():
    pass

Y una clase infantil de estilo antiguo se ve así:

class OldStyleSubclass(OldStyle):
    pass

Puede ver que una clase base de Old Style no hereda de ninguna otra clase, sin embargo, las clases de Old Style pueden, por supuesto, heredarse entre sí. La herencia del objeto garantiza que cierta funcionalidad esté disponible en cada clase de Python. Se introdujeron nuevas clases de estilo en Python 2.2


8
Llamar a la clase raíz objectno es tan confuso, y de hecho es bastante estándar. Smalltalk tiene una clase raíz llamada Objecty una metaclase raíz llamada Class. ¿Por qué? Porque, tal como Doges una clase para perros, Objectes una clase para objetos, y Classes una clase para clases. Java, C #, ObjC, Ruby y la mayoría de los otros lenguajes OO basados ​​en clases que las personas usan hoy en día que tienen una clase raíz usan alguna variación Objectcomo nombre, no solo Python.
abarnert

30

Sí, es histórica . Sin ella, crea una clase de estilo antiguo.

Si usa type()un objeto de estilo antiguo, solo obtiene "instancia". En un objeto de nuevo estilo obtienes su clase.


Además, si lo usa type()en una clase de estilo antiguo, obtiene "classobj" en lugar de "tipo".
Joel Sjögren

7

La sintaxis de la declaración de creación de clase:

class <ClassName>(superclass):
    #code follows

En ausencia de cualquier otra superclase de la que desee heredar específicamente, superclasssiempre debería ser object, que es la raíz de todas las clases en Python.

objectes técnicamente la raíz de las clases de "nuevo estilo" en Python. Pero las clases de estilo nuevo de hoy son tan buenas como ser el único estilo de clases.

Pero, si no usa explícitamente la palabra objectal crear clases, entonces, como otros mencionaron, Python 3.x hereda implícitamente de la objectsuperclase. Pero supongo que explícito siempre es mejor que implícito (infierno)

Referencia

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.