¿Por qué Python no necesita un compilador?

29

Me pregunto (ahora que comencé con C ++ que necesita un compilador) ¿por qué Python no necesita un compilador?

Solo ingreso el código, lo guardo como un ejecutivo y lo ejecuto. En C ++ tengo que hacer compilaciones y todas esas otras cosas divertidas.

Billjk
fuente
44
Python es solo un lenguaje con muchas implementaciones. Iron Python se compila de la misma manera que C # y C ++ se compila, y puede haber otras implementaciones como esta.
Trabajo
1
C # y C ++ no se compilan de la misma manera, aunque podría argumentar que ambos terminan como instrucciones de máquina eventualmente, pero si lo hace, puede decir que BASIC también se compila de la misma manera.
gbjbaanb
77
@gbjbaanb pero, una vez más, el inglés no se compila y el análisis semántico de una oración podría arrojar dos resultados igualmente válidos y lo anterior podría leerse como "iron python se compila al igual que C # y C ++ se compila"
Rune FS
¿Qué plataforma / software estás usando para escribir tu código Python? Si escribe un archivo .py, no es un ejecutable. Todavía es un archivo de código fuente. Desde la línea de comando está usando el pythoncomando para interpretar el archivo .py o si usa IDLE o Eclipse, el IDE lo hace por usted.
Rick Henderson

Respuestas:

68

Python tiene un compilador! Simplemente no lo notas porque se ejecuta automáticamente. Sin embargo, puede decir que está allí: mire los archivos .pyc(o .pyosi tiene el optimizador activado) que se generan para los módulos que usted import.

Además, no se compila con el código de la máquina nativa. En cambio, se compila en un código de bytes que utiliza una máquina virtual. La máquina virtual es en sí misma un programa compilado. Esto es muy similar a cómo funciona Java; tan similar, de hecho, que hay una variante de Python ( Jython ) que compila el código de bytes de la máquina virtual Java. También está IronPython , que compila el CLR de Microsoft (utilizado por .NET). (El compilador de código de bytes de Python normal a veces se llama CPython para desambiguarlo de estas alternativas).

C ++ necesita exponer su proceso de compilación porque el lenguaje en sí está incompleto; no especifica todo lo que el enlazador necesita saber para construir su programa, ni puede especificar opciones de compilación de forma portátil (algunos compiladores le permiten usar #pragma, pero eso no es estándar). Por lo tanto, debe hacer el resto del trabajo con archivos MAKE y posiblemente auto hell (autoconf / automake / libtool). Esto es realmente solo un remanente de cómo C lo hizo. Y C lo hizo así porque simplificó el compilador, que es una de las razones principales por la que es tan popular (cualquiera podría crear un compilador C simple en los años 80).


Algunas cosas que pueden afectar la operación del compilador o enlazador pero que no se especifican en la sintaxis de C o C ++:

  • resolución de dependencia
  • requisitos de la biblioteca externa (incluido el orden de dependencia)
  • nivel optimizador
  • ajustes de advertencia
  • versión de especificación de idioma
  • asignaciones de enlazador (qué sección va a dónde en el programa final)
  • arquitectura objetivo

Algunos de estos se pueden detectar, pero no se pueden especificar; por ejemplo, puedo detectar con qué C ++ está en uso __cplusplus, pero no puedo especificar que C ++ 98 sea el que se usa para mi código dentro del propio código; Tengo que pasarlo como una marca al compilador en el Makefile, o hacer una configuración en un diálogo.

Si bien puede pensar que existe un sistema de "resolución de dependencia" en el compilador, que genera automáticamente registros de dependencia, estos registros solo dicen qué archivos de encabezado utiliza un determinado archivo fuente. No pueden indicar qué módulos de código fuente adicionales se requieren para vincular a un programa ejecutable, porque no hay una forma estándar en C o C ++ para indicar que un archivo de encabezado dado es la definición de interfaz para otro módulo de código fuente en lugar de solo un montón de líneas que desea mostrar en varios lugares para que no se repita. Existen tradiciones en las convenciones de nomenclatura de archivos, pero el compilador y el vinculador no las conocen ni las aplican.

Varios de estos se pueden configurar usando #pragma, pero esto no es estándar, y estaba hablando del estándar. Todas estas cosas podrían especificarse mediante un estándar, pero no han sido en interés de la compatibilidad con versiones anteriores. La sabiduría predominante es que los makefiles y los IDE no están rotos, así que no los arregles.

Python maneja todo esto en el lenguaje. Por ejemplo, importespecifica una dependencia de módulo explícita, implica el árbol de dependencia y los módulos no se dividen en encabezado y archivos de origen (es decir, interfaz e implementación).

Mike DeSimone
fuente
3
La implementación C de Python es CPython , Cython es algo diferente.
Greg Hewgill
44
Otras razones por las que C compiló el código de la máquina fueron porque pretendía ser poco más que un ensamblador glorificado, porque los intérpretes de código de bytes eran técnicamente inviables en el hardware que tenían, y porque una de las tareas más importantes era escribir un núcleo del sistema operativo.
tdammers
2
@BillyONeal con la única gran excepción de que en c / c ++ usted como programador tiene que hacer cosas de cierta manera (ya sea makefiles o volcar todo en el mismo blob) en python solo hace su trabajo y el compilador junto con la VM se encarga del resto
Rune FS
3
"C ++ necesita exponer su proceso de compilación porque el lenguaje en sí está incompleto" Er, ¿qué?
Lightness compite con Monica el
3
Tu lees la parte justo después de eso , ¿verdad? "no especifica todo lo que el enlazador necesita saber para construir su programa, ni puede especificar opciones de compilación de manera portátil". No puede crear cualquier archivo C ++ al enviarlo a un compilador; con frecuencia tiene que proporcionar metadatos como compilar indicadores, incluir rutas, etc. Estos metadatos no están especificados por el estándar y no son portátiles, por eso tenemos que arrastrar otras cosas como make, cmake, Visual Studio o lo que sea para termina el trabajo. Por lo tanto, el estándar debe mencionar algunas cosas como en la unidad de compilación y otras como todo el programa.
Mike DeSimone
7

Python es un lenguaje interpretado. Esto significa que hay un software en su computadora que lee el código de Python y envía las "instrucciones" a la máquina. El artículo de Wikipedia sobre idiomas interpretados podría ser de interés.

Cuando se compila un lenguaje como C ++ (un lenguaje compilado), significa que se convierte en código de máquina para que el hardware lo lea directamente cuando se ejecuta. El artículo de Wikipedia sobre lenguajes compilados podría proporcionar un contraste interesante.

Zenon
fuente
21
No existe un lenguaje interpretado o compilado. Un lenguaje es un conjunto abstracto de reglas matemáticas. Un idioma no se compila ni se interpreta. Un idioma simplemente es . La compilación y la interpretación son rasgos del compilador o intérprete (¡duh!), No del lenguaje. Cada idioma puede implementarse con un compilador y cada idioma puede implementarse con un intérprete. La mayoría de los idiomas tienen implementaciones compiladas e interpretadas. Hay intérpretes para C ++ y hay compiladores para Python. (De hecho, todas las implementaciones actuales de Python tienen compiladores.)
Jörg W Mittag
44
La mayoría de las implementaciones modernas de lenguaje de alto rendimiento combinan un intérprete y un compilador (o incluso varios compiladores) para obtener el máximo rendimiento. En realidad, es imposible ejecutar cualquier programa sin un intérprete. Después de todo, un compilador es solo un programa que traduce un programa de un idioma a otro. Pero en algún momento debe ejecutar el programa, que lo realiza un intérprete (que puede o no implementarse en silicio).
Jörg W Mittag
10
@ JörgWMittag: Técnicamente tienes razón. Sin embargo, la mayoría de los idiomas fueron diseñados para un contexto interpretado o para una compilación completa. Escribir un intérprete para GW BASIC o Common Lisp es mucho más fácil que escribir uno para, por ejemplo, C ++ o C #; Python pierde muchos de sus puntos de venta sin el entorno interactivo; escribir un compilador para PHP es bastante difícil, y probablemente terriblemente ineficiente, ya que el ejecutable compilado tendría que contener todo el intérprete de PHP, debido a eval () y construcciones similares; uno podría argumentar que tal compilador estaría haciendo trampa.
tdammers
2
@tdammers, sí. Podemos usar razonablemente "lenguaje compilado" para referirnos a "lenguaje usualmente compilado". Pero eso pierde el punto de que PHP, Java, Python, Lua y C # se implementan como compiladores para bytecode. Todos estos idiomas también han implementado JIT para ellos. Entonces, realmente no se puede llamar a algunos de estos lenguajes compilados y otros interpretados porque tienen la misma estrategia de implementación.
Winston Ewert
2
@BillyONeal, no es cierto al menos para Python. Puede distribuir el código de bytes de Python y ejecutarlo sin la fuente. Pero es cierto que no puedes distribuir Python sin un compilador.
Winston Ewert
5

No todos los idiomas compilados tienen un ciclo de edición-compilación-enlace-ejecución en su cara.

En lo que se está encontrando es una característica / limitación de C ++ (o al menos implementaciones de C ++).

Para hacer cualquier cosa, debe almacenar su código en archivos y construir una imagen monolítica mediante un proceso llamado vinculación.

En particular, este proceso de enlace monolítico se confunde con la distinción entre compilar e interpretar.

Algunos lenguajes hacen todo esto mucho más dinámicamente, eliminando el torpe paso de enlace monolítico, no eliminando la compilación al código de máquina. Source aún se compila en archivos de objetos, pero estos se cargan en una imagen en tiempo de ejecución, en lugar de vincularse a un ejecutable monolítico.

Usted dice "recargar este módulo", y carga la fuente y lo interpreta, o lo compila, dependiendo de algún cambio de modo.

La programación del kernel de Linux tiene algo de este sabor aunque esté trabajando en C. Puede recompilar un módulo y cargarlo y descargarlo. Por supuesto, todavía eres consciente de que estás produciendo algo ejecutable, y está administrado por un complejo sistema de compilación, con algunos pasos manuales. Pero el hecho es que al final puede descargar y volver a cargar solo ese pequeño módulo y no tener que reiniciar todo el núcleo.

Algunos idiomas tienen una modularización aún más fina que esta, y la construcción y carga se realiza desde su tiempo de ejecución, por lo que es más transparente.

Kaz
fuente
2

qué desviación de la pregunta inicial ... Un punto no mencionado es que la fuente de un programa de Python es lo que usa y distribuye, desde la perspectiva del usuario ES el programa. Tendemos a simplificar las cosas en categorías que no están bien definidas.

Los programas compilados generalmente se consideran archivos independientes de código de máquina. (Es cierto que a menudo contiene enlaces a bibliotecas de enlaces dinámicos asociados con sistemas operativos específicos). Dicho esto ... hay variaciones de la mayoría de los lenguajes de programación que podrían describirse como compilados o interpretados.

Python no necesita un compilador porque se basa en una aplicación (llamada intérprete) que compila y ejecuta el código sin almacenar el código de la máquina que se está creando de forma que pueda acceder o distribuir fácilmente.

Stephen Robinson
fuente
1

Todos los lenguajes de programación requieren la traducción de conceptos humanos a un código de máquina de destino. Incluso el lenguaje ensamblador debe traducirse al código de la máquina. Esa traducción generalmente tiene lugar en las siguientes fases:

Fase 1: Análisis y traducción (análisis) en un código intermedio. Fase 2: Traducción del código intermedio al código de máquina de destino con marcadores de posición para referencias externas. Fase 3: Resolución de las referencias externas y el empaquetado en un programa ejecutable de la máquina.

Esta traducción a menudo se conoce como compilación previa y "Just in time" (JIT) o compilación en tiempo de ejecución.

Los lenguajes como C, C ++, COBOL, Fortran, Pascal (no todos) y Assembly son lenguajes precompilados que el sistema operativo puede ejecutar directamente sin necesidad de un intérprete.

Se interpretan lenguajes como Java, BASIC, C # y Python. Todos usan ese código intermedio creado en la Fase 1, pero a veces diferirán en cómo lo traducen al código de máquina. Las formas más simples usan ese código intermedio para ejecutar rutinas de código de máquina que hacen el trabajo esperado. Otros compilarán el código intermedio hasta el código de máquina y realizarán la reparación de la dependencia externa durante el tiempo de ejecución. Una vez compilado, se puede ejecutar de inmediato. Además, el código de la máquina se almacena en un caché de código de máquina reutilizable previamente compilado que luego se puede reutilizar si la función se necesita nuevamente más tarde. Si una función ya se ha almacenado en caché, el intérprete no necesita compilarla nuevamente.

La mayoría de los lenguajes modernos de alto nivel entran en la categoría interpretada (con JIT). La mayoría de los lenguajes antiguos, como C y C ++, son los que se precompilan.

Mark Baker
fuente