Pergunta

Como seria viável para compilar Python (possivelmente através de uma representação intermédia C) para o código de máquina?

Provavelmente, seria necessário link para uma biblioteca de tempo de execução Python, e quaisquer partes da biblioteca padrão do Python que foram Python si precisaria ser compilado (e ligado in) também.

Além disso, seria necessário para agrupar o interpretador Python se você queria fazer avaliação dinâmica de expressões, mas talvez um subconjunto de Python que não permitiu que isso ainda seria útil.

Será que fornecer quaisquer vantagens de velocidade e / ou uso de memória? Presumivelmente, o tempo de inicialização do interpretador Python seria eliminado (embora bibliotecas compartilhadas ainda precisa de carregamento na inicialização).

Foi útil?

Solução

ShedSkin Python-to-C ++, mas está longe de ser perfeito. Também há Psyco - Python JIT que apenas aceleração é necessária. Mas IMHO isso não vale a pena o esforço. Para as peças de velocidade crítica de código melhor solução seria a escrevê-los como extensões C / C ++.

Outras dicas

Como @ Greg Hewgill diz que, há boas razões para que isso nem sempre é possível. No entanto, certos tipos de código (como código muito algorítmica) pode ser transformado em código de máquina "real".

Existem várias opções:

  • Psyco , que emite o código de máquina dinamicamente. Você deve escolher cuidadosamente quais métodos / funções para converter, no entanto.
  • Cython , que é um Python- como linguagem que é compilado em um Python extensão C
  • PyPy , que tem um tradutor de RPython (a restrito subconjunto de Python que faz não suporta alguns dos "dinâmica" a maioria das funcionalidades do Python) para C ou LLVM.
    • PyPy é ainda altamente experimental
    • Não todas as extensões estarão presentes

Depois disso, você pode usar um dos pacotes existentes (congelamento, py2exe, PyInstaller) para colocar tudo em um único binário.

Em suma: não há uma resposta geral para sua pergunta. Se você tem o código Python que é de desempenho crítico, tente usar tanta funcionalidade embutida possível (ou pedir a um "Como posso fazer o meu código Python mais rápido" questão). Se isso não ajudar, tente identificar o código e porta-lo para C (ou Cython) e usar a extensão.

py2c ( http://code.google.com/p/py2c ) pode converter o código python para c / c ++ Eu sou o desenvolvedor individual de py2c.

Nuitka é um compilador Python para C ++ que as ligações contra libpython. Parece ser um projeto relativamente novo. O autor afirma um melhoria velocidade sobre CPython no benchmark pystone.

PyPy é um projeto para reimplementar Python em Python, usando a compilação de código nativo como uma das estratégias de implementação ( outros sendo uma VM com JIT, usando JVM, etc). Suas versões C compilados ficar mais lento do que o CPython em média, mas muito mais rápido para alguns programas.

Shedskin é um experimental Python-a-compilador C ++.

Pyrex é uma linguagem especialmente concebido para escrever módulos de extensão de Python. Ele foi projetado para preencher a lacuna entre o bom, de alto nível, fácil de usar mundo do Python eo confuso, mundo de baixo nível de C.

Pyrex é um subconjunto da linguagem Python que compila para C, feito pelo cara que primeiro construídos compreensões lista para Python. Ele foi desenvolvido principalmente para a construção de wrappers, mas pode ser usado em um contexto mais geral. Cython é um fork mais ativamente mantido de pirex.

Isso pode parecer razoável à primeira vista, no entanto, há um monte de coisas comuns em Python que não são diretamente mapeáveis ??para a uma representação C sem carregar mais de um lote do suporte de tempo de execução Python. Por exemplo, pato digitação vem à mente. Muitas funções em Python que a entrada de leitura pode tomar um arquivo ou arquivo-like objeto, desde que ele suporta determinadas operações, por exemplo. ler () ou readline (). Se você pensar sobre o que seria necessário para mapear este tipo de apoio para C, você começa a imaginar exatamente os tipos de coisas que o sistema de execução Python já faz.

Existem utilitários como py2exe que vai incluir um programa de Python e tempo de execução em um único executável (tanto quanto possível).

Algumas referências extras:

Jython tem um compilador alvo JVM bytecode. O bytecode é totalmente dinâmico, assim como a linguagem Python em si! Muito legal. (Sim, como alude resposta de Greg Hewgill, o bytecode não usar o tempo de execução Jython, e assim o arquivo jar Jython deve ser distribuído com o seu app.)

Psyco é uma espécie de (JIT) compilador just-in-time: compilador dinâmico para Python, executa código 2-100 vezes mais rápido, mas precisa de muita memória.

Em suma: é executar o seu software Python existente muito mais rápido, sem alteração na sua fonte, mas não compilar para código objeto da mesma maneira um compilador C faria

.

A resposta é "Sim, é possível". Você poderia tomar código Python e tentar compilá-lo para o código C equivalente usando a API CPython. Na verdade, costumava haver um projeto Python2C que fez exatamente isso, mas eu não ouvi sobre isso em muitos anos (de volta nos Python 1,5 dias é quando eu viu pela última vez.)

Você poderia tentar traduzir o código Python em C nativa, tanto quanto possível, e cair de volta para a API CPython quando você precisa real Python apresenta. Eu fui brincar com essa idéia me o último mês ou dois. É, no entanto, uma enorme quantidade de trabalho, e uma enorme quantidade de recursos Python são muito difíceis de traduzir em C: funções aninhadas, geradores, qualquer coisa mas classes simples, com métodos simples, nada que envolvem modificando globals módulo de fora do módulo, etc. , etc.

Esta não compilar Python para código de máquina. Mas permite criar uma biblioteca compartilhada para chamar código Python.

Se o que você está procurando é uma maneira fácil de executar código Python de C sem depender de coisas execp. Você poderia gerar uma biblioteca compartilhada a partir do código python envolvido com algumas chamadas para Python incorporar API . Bem, a aplicação é uma biblioteca compartilhada, um .so que você pode usar em muitas outras bibliotecas / aplicações.

Aqui está um exemplo simples que criar uma biblioteca compartilhada, que você pode ligar com um programa C. A biblioteca compartilhada executa código Python.

O arquivo de python que será executado é pythoncalledfromc.py:

# -*- encoding:utf-8 -*-
# this file must be named "pythoncalledfrom.py"

def main(string):  # args must a string
    print "python is called from c"
    print "string sent by «c» code is:"
    print string
    print "end of «c» code input"
    return 0xc0c4  # return something

Você pode experimentá-lo com python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO'). Ele irá imprimir:

python is called from c
string sent by «c» code is:
HELLO
end of «c» code input

A biblioteca compartilhada será definido pela seguinte por callpython.h:

#ifndef CALL_PYTHON
#define CALL_PYTHON

void callpython_init(void);
int callpython(char ** arguments);
void callpython_finalize(void);

#endif

O callpython.c associado é:

// gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <python2.7/Python.h>

#include "callpython.h"

#define PYTHON_EXEC_STRING_LENGTH 52
#define PYTHON_EXEC_STRING "import pythoncalledfromc; pythoncalledfromc.main(\"%s\")"


void callpython_init(void) {
     Py_Initialize();
}

int callpython(char ** arguments) {
  int arguments_string_size = (int) strlen(*arguments);
  char * python_script_to_execute = malloc(arguments_string_size + PYTHON_EXEC_STRING_LENGTH);
  PyObject *__main__, *locals;
  PyObject * result = NULL;

  if (python_script_to_execute == NULL)
    return -1;

  __main__ = PyImport_AddModule("__main__");
  if (__main__ == NULL)
    return -1;

  locals = PyModule_GetDict(__main__);

  sprintf(python_script_to_execute, PYTHON_EXEC_STRING, *arguments);
  result = PyRun_String(python_script_to_execute, Py_file_input, locals, locals);
  if(result == NULL)
    return -1;
  return 0;
}

void callpython_finalize(void) {
  Py_Finalize();
}

Você pode compilá-lo com o seguinte comando:

gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so

Crie um arquivo chamado callpythonfromc.c que contém o seguinte:

#include "callpython.h"

int main(void) {
  char * example = "HELLO";
  callpython_init();
  callpython(&example);
  callpython_finalize();
  return 0;
}

compilar e executar:

gcc callpythonfromc.c callpython.so -o callpythonfromc
PYTHONPATH=`pwd` LD_LIBRARY_PATH=`pwd` ./callpythonfromc

Este é um exemplo muito básico. Ele pode trabalhar, mas, dependendo da biblioteca pode ser ainda difícil de serializar estruturas de dados C para Python e do Python para C. As coisas podem ser automatizados pouco ...

Nuitka pode ser útil.

Também há numba mas ambos não visam a fazer o que você quer exatamente. Gerando um cabeçalho C a partir do código Python é possível, mas somente se você especificar a forma de converter os tipos Python para tipos C ou pode-se inferir que as informações. Consulte python astroid para um analisador de ast Python.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top