2010-10-26 26 views
14

He estado aprendiendo más sobre Python recientemente, y como yo estaba pasando por la excelente Dive into Python el autor observó here que el método __init__ no es técnicamente un constructor, a pesar de que generalmente funciona como tal.diferencias entre Python y C++ constructores

Tengo dos preguntas:

  1. ¿Cuáles son las diferencias entre la forma en C++ construye un objeto y cómo Python "construye" un objeto?

  2. Lo que hace que un constructor un constructor, y cómo funciona el método __init__ no cumplen con este criterio?

+0

No estoy seguro de si estoy de acuerdo con 2 ... Como Python es un lenguaje de recolección de basura, el "primer" paso de un constructor en C++ (asignación de memoria) doesn' t debe ejecutarse, y los atributos pueden asignarse a la instancia. Entonces, IMO, '__init__' es un constructor ya que asigna valores a los atributos y completa/finaliza la instancia. –

+2

@Rafe Kettler: en C++, los constructores NO asignan memoria, sino que inicializan y convierten la memoria sin procesar (previamente asignada) en objetos. –

+0

@David: Bien, gracias por la aclaración. Supongo que asignan memoria * a * ese objeto en lugar de asignar memoria en general. –

Respuesta

15

La distinción que el autor extrae es que, en lo que se refiere al lenguaje Python, que tiene un objeto válido del tipo especificado antes incluso de entrar en__init__. Por lo tanto, no es un "constructor", ya que en C++ y teóricamente, un constructor convierte un objeto no válido y preconstruido en un objeto completo "adecuado" del tipo.

Básicamente __new__ en Python se define para devolver "la nueva instancia de objeto", mientras que los operadores nuevos de C++ simplemente devuelven algo de memoria, que aún no es una instancia de ninguna clase.

Sin embargo, __init__ en Python es probablemente donde primero estableces invariantes de clase importantes (qué atributos tiene, solo para empezar). Por lo que respecta a los usuarios de su clase, podría ser un constructor. Es solo que el tiempo de ejecución de Python no se preocupa por ninguno de esos invariantes. Si lo desea, tiene estándares muy bajos para lo que constituye un objeto construido.

Creo que el autor hace un buen punto, y sin duda es una observación interesante sobre la forma en que Python crea los objetos. Sin embargo, es una distinción bastante buena y dudo que llamar al __init__ sea un constructor resultará en código dañado.

Además, observo que la documentación de Python se refiere a __init__ como constructor (http://docs.python.org/release/2.5.2/ref/customization.html)

como un especial restricción en constructores, ningún valor puede ser devuelto

... así que si hay cualquier problema práctico con el pensamiento de __init__ como constructor, a continuación, Python está en problemas!

La forma en que los objetos de construcción de Python y C++ tienen algunas similitudes. Ambos llaman a una función con una responsabilidad relativamente simple (__new__ para una instancia de objeto frente a alguna versión de operator new para memoria sin procesar), luego ambos llaman a una función que tiene la oportunidad de trabajar más para inicializar el objeto en un estado útil (__init__ frente a constructor).

diferencias prácticas incluyen:

  • en C++, sin argumentos constructores de clases base son llamados automáticamente en el orden apropiado, si es necesario, mientras que para __init__ en Python, lo que tiene que init explícitamente su base en su propio __init__. Incluso en C++, debe especificar el constructor de la clase base si tiene argumentos.

  • en C++, tiene todo un mecanismo para lo que sucede cuando un constructor lanza una excepción, en términos de invocar destructores para subobjetos que ya han sido construidos. En Python creo que el tiempo de ejecución (a lo sumo) llama al __del__.

Luego está también la diferencia de que __new__ no solo asignar memoria, tiene que devolver una instancia de objeto real. Por otra parte, la memoria bruta no es realmente un concepto que se aplica al código Python.

+0

Gran explicación, gracias. – Zeke

+0

El tiempo de ejecución realmente no llama a '__del__', simplemente propaga la excepción hacia arriba, y después de que la última referencia al objeto inicializado se va, (eventualmente) el objeto se destruye. '__del__' * puede * llamarse justo antes de eso, pero en realidad no se usa para hacer ninguna destrucción; '__del__' es la contraparte de' __init__', no de '__new__' :) –

+0

@Thomas: si' __del__' es realmente la contraparte de '__init__', entonces esperaría que se definiera para llamarse si (y solo if) '__init__' completa. Claro, podría liberar recursos del sistema asignados en '__init__', o para ese asunto en cualquier otro método de la clase. Mi comprensión limitada de CPython es que se llama a '__del__' cuando se destruye un objeto, independientemente de si' __init__' se completó, o incluso si se llamó en absoluto. Y que un objeto que no puede '__init__' se destruirá inmediatamente, aunque ese es un detalle de implementación de la reconfiguración de CPython. ¿Está bien? –

2

Un constructor en muchos otros idiomas asigna espacio para el objeto que se está construyendo; en Python este es el trabajo del método de asignación, __new__(). __init__() es solo un método de inicialización.

+1

Los constructores en C++ tampoco asignan espacio para el objeto. Ese es el trabajo de 'operator new'. O en el caso de una nueva ubicación degenerada, es en realidad el trabajo de la persona que llama contar esa versión de nuevo donde está la memoria, para que pueda hacer eco de ese valor. –

2

En Python se crea un objeto, por __new__, y ese tipo de objeto predeterminado genérico se modifica por __init__. Y __init__ es solo un método ordinario. En particular, se puede llamar virtualmente, y llamar a los métodos desde __init__ los llama virtualmente.

En C++ memoria prima para un objeto se asigna de alguna manera, de forma estática, o en una pila de llamadas, o dinámicamente a través de operator new, o como parte de otro objeto. A continuación, el constructor del tipo que está instanciando inicializa la memoria bruta a los valores adecuados. Un constructor de una clase determinada llama automáticamente a los constructores de las clases base y los miembros, por lo que la construcción se garantiza una construcción de "abajo hacia arriba", haciendo que las partes primero.

C++ añade compatibilidad con el idioma durante dos aspectos especialmente importantes de la idea de la construcción de las piezas:

  • Si un constructor falla (por lanzar una excepción), a continuación, las piezas que se han construido con éxito son destruidos, de forma automática, y la memoria para el objeto es desasignada, automáticamente.
  • Durante la ejecución del cuerpo de un constructor de un tipo T el objeto es de tipo T, por lo que las llamadas a métodos virtuales resolver como si el objeto es de tipo T (que es, en este punto), donde T puede ser una clase base de la clase que instanciaste.

El primer punto significa que con una clase de C++ diseñada correctamente, cuando tiene un objeto a mano, se puede utilizar tal como está. Si la construcción falla, simplemente no terminas con un objeto a mano.

Además, las reglas de C++ están diseñadas para garantizar que para cada objeto de la clase derivada T haya una y solo una llamada de constructor T. Solía ​​llamarlo la garantía de llamada de constructor único. No se especifica como tal en ningún lugar de la norma, y ​​puede frustrarlo utilizando instalaciones de muy bajo nivel del idioma, pero está ahí, es lo que las reglas detalladas de la norma están diseñadas para lograr (es casi lo mismo que usted ganó No se encuentra ninguna regla única sobre la terminación de sentencias de punto y coma, pero todas las innumerables reglas de sintaxis para varias declaraciones conspiran para producir una regla simple de alto nivel).

La garantía de llamada de constructor único, y la garantía de limpieza automática, y el tipo cambiante de un objeto como constructores de clases base se ejecutan, son quizás las tres diferencias más importantes de una construcción de objeto Python.

Hay mucho más que decir, pero creo que estas son las ideas más importantes.

Saludos & HTH.,

Cuestiones relacionadas