¿Deberían todas las clases de Python extender el objeto?

129

He encontrado que ambos de los siguientes trabajos:

class Foo():
    def a(self):
        print "hello"

class Foo(object):
    def a(self):
        print "hello"

¿Deberían todas las clases de Python extender el objeto? ¿Hay algún problema potencial con no extender el objeto?

Kara
fuente
2
¿Hay alguna diferencia entre class Foo():y class Foo:? Como observo, ambos trabajan en Python 3.
Wolf
Está bien respondido en esta pregunta: stackoverflow.com/questions/4015417/…
nngeek

Respuestas:

117

En Python 2, no heredar de objectcreará una clase de estilo antiguo, que, entre otros efectos, causa typeresultados diferentes:

>>> class Foo: pass
... 
>>> type(Foo())
<type 'instance'>

vs.

>>> class Bar(object): pass
... 
>>> type(Bar())
<class '__main__.Bar'>

Además, las reglas para la herencia múltiple son diferentes en formas que ni siquiera intentaré resumir aquí. Toda la buena documentación que he visto sobre MI describe clases de estilo nuevo.

Finalmente, las clases de estilo antiguo han desaparecido en Python 3, y la herencia se objectha vuelto implícita. Por lo tanto, siempre prefiera nuevas clases de estilo a menos que necesite compatibilidad con software antiguo.

Fred Foo
fuente
68

En Python 3, las clases se extienden objectimplícitamente, lo diga usted mismo o no.

En Python 2, hay clases de estilo antiguo y nuevo . Para indicar que una clase es de estilo nuevo, debe heredar explícitamente de object. Si no, se usa la implementación de estilo antiguo.

Generalmente quieres una clase de nuevo estilo. Heredar de objectexplícitamente. Tenga en cuenta que esto también se aplica al código de Python 3 que pretende ser compatible con Python 2.

slezica
fuente
Sí, la diferencia que señaló Free Foo se ha ido, por cierto: ¿ son opcionales los paréntesis vacíos?
Wolf
44
Hay mucho código de Python 3 que usa foo (objeto) :. ¿Es esto solo una convención entonces?
RFV5s
2
@RFVenter Puede ser de código que se supone que se ejecute en tanto Python 2 y 3, en el que caso de que necesite objeto de subclase de forma explícita con el fin de hacer que la clase se comportan en gran medida el mismo bajo Python 2.
blubberdiblub
@blubberdiblub Eso es lo que sospechaba PERO nuestro proyecto se ejecuta exclusivamente en python 3.5 virtualenv. Creo que el código debe haber sido copiado de un proyecto de Python 2.
RFV5s
@RFVenter sí, esa puede ser otra explicación. Y, por supuesto, si es Python 3.x solo ahora, está bien deshacerse de las referencias a objetos.
blubberdiblub
17

En python 3 puede crear una clase de tres maneras diferentes e internamente todas son iguales (ver ejemplos). No importa cómo cree una clase, todas las clases en Python 3 heredan de una clase especial llamada objeto . El objeto de clase es una clase fundamental en python y proporciona mucha funcionalidad como métodos de doble subrayado, descriptores, método super (), método de propiedad (), etc.

Ejemplo 1.

class MyClass:
 pass

Ejemplo 2

class MyClass():
 pass

Ejemplo 3

class MyClass(object):
  pass
N Randhawa
fuente
1
Esto no es estrictamente cierto ... stackoverflow.com/questions/1238606/…
Philip Adler
No estoy seguro de seguirte. Y sí, probablemente no sea relevante para la mayoría de las personas hasta que sea relevante.
Philip Adler
@PhilipAdler Se supone comúnmente que objecthace referencia a la función integrada object. Si debemos tener en cuenta que cualquier identificador incorporado de CPython puede ser reemplazado, apenas podríamos hacer alguna afirmación sobre el modelo de datos. ¿Se puede argumentar seriamente que strno siempre se acepta una cadena como argumento porque se podría asignar builtins.str = None?
Nuno André
Sigo viendo esta afirmación de que esto es "ampliamente asumido", y acepto que es una suposición que cada implementación actual hace (no es un requisito del lenguaje), no ha sido mi experiencia que la mayoría de los programadores de Python I he conocido asumir esto, saberlo o incluso haberlo considerado. Independientemente de lo cual, la afirmación de que se asume comúnmente, incluso si es cierta, no invalida mi afirmación de que la equivalencia no es estrictamente cierta.
Philip Adler
1

Sí, todas las clases de Python deberían extender el objeto (o más bien la subclase, aquí está Python). Si bien normalmente no se producirán problemas graves, en algunos casos (como con múltiples árboles de herencia) esto será importante. Esto también garantiza una mejor compatibilidad con Python 3.

Pydsigner
fuente
1
exactamente, técnicamente, si no lo haces, obtendrás una clase clásica, pero no hay ventajas reales para esto y de todos modos no es compatible con python 3
max k.
Tengo curiosidad por saber por qué mejora la compatibilidad con python3. Según tengo entendido, python3 hará que extienda el objeto automáticamente incluso si no lo especifica, ¿verdad?
Paul Lo
2
@PaulLo Right, pero si heredas explícitamente de un objeto, obtendrás el mismo comportamiento (nuevo estilo) tanto en Python 2 como en Python 3. No se trata de cambiar cómo funciona Python 3, se trata de usar adelante -compatibilidad en Python 2.
pydsigner
Esta sugerencia no parece muy elegante, pero en caso de que aborde Python2 y Python3, parece efectiva. Pero, ¿qué tan relevante es en la práctica?
Wolf
@ Wolf Depende de lo que estés haciendo. Si tiene árboles de herencia complejos, es bastante importante. Si desea que su clase sea un descriptor, debe usar un nuevo estilo. Puede seguir los enlaces desde stackoverflow.com/questions/54867/… si desea obtener información más detallada.
pydsigner
1

Como han cubierto otras respuestas, la herencia de Python 3 del objeto está implícita. Pero no indican lo que debe hacer y qué es la convención.

Todos los ejemplos de documentación de Python 3 usan el siguiente estilo que es convencional, por lo que le sugiero que siga esto para cualquier código futuro en Python 3.

class Foo:
    pass

Fuente: https://docs.python.org/3/tutorial/classes.html#class-objects

Cita de ejemplo:

Los objetos de clase admiten dos tipos de operaciones: referencias de atributos e instanciación.

Las referencias de atributos utilizan la sintaxis estándar utilizada para todas las referencias de atributos en Python: obj.name. Los nombres de atributo válidos son todos los nombres que estaban en el espacio de nombres de la clase cuando se creó el objeto de clase. Entonces, si la definición de clase se ve así:

class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

Otra cita:

En términos generales, las variables de instancia son para datos únicos de cada instancia y las variables de clase son para atributos y métodos compartidos por todas las instancias de la clase:

class Dog:

    kind = 'canine'         # class variable shared by all instances

    def __init__(self, name):
        self.name = name    # instance variable unique to each instance
jmoz
fuente
0

en python3 no hay diferencia, pero en python2 no extender objectle da una clase de estilo antiguo; le gustaría usar una clase de estilo nuevo sobre una clase de estilo antiguo.

thkang
fuente
2
Esta respuesta es razonable, pero otras respuestas llegaron más rápido y / o con más detalle; Esta respuesta no agrega ningún valor a la página tal como está.
Mark Amery