파이썬을 기계 코드로 컴파일하는 것이 가능합니까?


128

파이썬을 (중간 C 표현을 통해) 머신 코드로 컴파일하는 것이 얼마나 가능합니까?

아마도 그것은 파이썬 런타임 라이브러리에 연결될 필요가있을 것이며, 파이썬 자체 인 파이썬 표준 라이브러리의 어떤 부분도 컴파일 (및 링크)되어야 할 것입니다.

또한 표현식의 동적 평가를 원한다면 Python 인터프리터를 번들로 제공해야하지만, 이것을 허용하지 않은 Python의 하위 세트는 여전히 유용 할 것입니다.

속도 및 / 또는 메모리 사용 이점을 제공합니까? 아마도 파이썬 인터프리터의 시작 시간이 제거 될 것입니다 (공유 라이브러리는 여전히 시작시로드해야하지만).


2
Btw, 객체 코드가 아닌 "머신 코드"를 요청하면 IMHO가 더 명확 해집니다.
Torsten Marek

답변:


31

ShedSkin Python-to-C ++ 컴파일러를 사용해보십시오 .하지만 완벽하지는 않습니다. 또한 속도 향상 만 필요한 경우 Psyco-Python JIT가 있습니다. 그러나 IMHO는 노력할 가치가 없습니다. 코드의 속도에 중요한 부분은 C / C ++ 확장으로 작성하는 것이 가장 좋습니다.


5
참고로 ShedSkin은 Windows 지원을 중단했습니다.
sorin

2
@sorin : 글쎄, 오늘은 윈도우를 지원합니다 ... code.google.com/p/shedskin/downloads/…

2
가장 좋은 해결책은 속도면에서 여전히 PyPy 일 수 있습니다 .
Cees Timmerman

shedskin은 현재 약 2 년 동안 아무런 작업을 수행하지 않았습니다. :(
퍼킨스

53

@Greg Hewgill이 말했듯이 이것이 항상 가능하지 않은 이유는 충분합니다. 그러나 특정 알고리즘 (예 : 매우 알고리즘적인 코드)을 "실제"기계 코드로 변환 할 수 있습니다.

몇 가지 옵션이 있습니다.

  • 머신 코드를 동적으로 방출하는 Psyco를 사용하십시오 . 하지만 변환 할 메소드 / 함수를 신중하게 선택해야합니다.
  • 사용 사이 썬 Python-이며, 같은 파이썬 C 확장으로 컴파일 언어
  • RPython ( Python의 가장 "동적"기능을 지원하지 않는 Python 의 제한된 서브 세트 )에서 C 또는 LLVM으로 의 변환기가있는 PyPy를 사용하십시오 .
    • PyPy는 여전히 실험 중입니다
    • 모든 확장이 존재하지는 않습니다

그런 다음 기존 패키지 중 하나 (freeze, Py2exe, PyInstaller)를 사용하여 모든 것을 하나의 바이너리에 넣을 수 있습니다.

대체로 귀하의 질문에 대한 일반적인 답변은 없습니다. 성능이 중요한 Python 코드가 있다면 가능한 한 많은 내장 기능을 사용하십시오 (또는 "Python 코드를 더 빨리 만드는 방법"질문). 그래도 도움이되지 않으면 코드를 식별하고 C (또는 Cython)로 이식하고 확장을 사용하십시오.


3
Pypy는 Psyco의 후속 버전
bcattle

19

py2c ( https://github.com/pradyun/Py2C )는 파이썬 코드를 c / c ++로 변환 할 수 있습니다. 나는 py2c의 솔로 개발자입니다.


이것은 유용한 도구처럼 보입니다. 여전히 유지되고 있습니까?
Anderson Green

@AndersonGreen 마지막으로 작업했던 초기 개발 단계에 있습니다 (아마도 비슷 함). 나는 게으 르기 때문에 프로젝트를 떠났습니다. "중요한"텍스트를 보지 못했다면 이제 GitHub로 옮겨졌습니다.
Ramchandra Apte

링크 는 다른 프로젝트 인 것처럼 보이는 unvanquished-installer를 가리 킵니다 . GitHub에서 py2c를 계속 사용할 수 있습니까?
Anderson Green

@AndersonGreen 너무 오랫동안 주목받지 못한 와우! 여기 당신은 간다.
Ramchandra Apte

code.google.com/p/py2c 의 링크는 여전히 unvanquished-installer를 가리 키므로 지금 업데이트해야합니다.
Anderson Green

15

PyPy 는 구현 전략 (JIT가있는 VM, JVM을 사용하는 VM 등) 중 하나로 네이티브 코드로 컴파일을 사용하여 Python에서 Python을 다시 구현하는 프로젝트입니다. 컴파일 된 C 버전은 평균적으로 CPython보다 느리지 만 일부 프로그램의 경우 훨씬 빠릅니다.

Shedskin 은 실험적인 Python-to-C ++ 컴파일러입니다.

Pyrex 는 Python 확장 모듈을 작성하기 위해 특별히 설계된 언어입니다. 훌륭하고 사용하기 쉬운 Python의 세계와 지저분한 저수준의 C 세계 사이의 격차를 해소하도록 설계되었습니다.


3
Cython은 Pyrex의 가장 널리 사용되고 적극적으로 개발 된 친숙한 포크입니다.
Mike Graham

"좋은 수준의 사용하기 쉬운 파이썬의 세계와 지저분하고 낮은 수준의 C의 세상"-C와 어셈블러가 어떻게 "좋고"단순하며, 파이썬이 " 지저분한 ","높은 수준의 "세계
리버스 엔지니어

14

Nuitka 는 libpython과 연결되는 Python to C ++ 컴파일러입니다. 비교적 새로운 프로젝트 인 것 같습니다. 필자 는 pystone 벤치 마크에서 CPython보다 속도가 향상 되었다고 주장합니다 .


10

이것은 언뜻보기에는 합리적으로 보일 수 있지만 Python에는 많은 Python 런타임 지원을 수행하지 않고 C 표현에 직접 매핑 할 수없는 많은 평범한 것들이 있습니다. 예를 들어, 오리 타이핑이 떠 오릅니다. 입력을 읽는 파이썬의 많은 함수 는 특정 연산을 지원 하는 한 파일 이나 파일과 같은 객체를 취할 수 있습니다 . read () 또는 readline (). 이 유형의 지원을 C에 매핑하는 데 무엇이 필요한지 생각하면 Python 런타임 시스템이 이미 수행하는 작업을 정확하게 상상하기 시작합니다.

파이썬 프로그램과 런타임을 단일 실행 파일로 묶을 수있는 py2exe 와 같은 유틸리티가 있습니다 (가능한 한).


1
정적 컴파일 언어는 (적어도 제 생각에는) 런타임에 폭파 될 가능성이 적기 때문에 코드가 컴파일되도록하는 것이 목표라면 어떨까요? 호출 할 당시 시간 이 foo.x없기 때문에 일부 표현식이 작동하지 않을 것이라고 판단 할 수 있습니까? 파이썬에 대한 정적 코드 검사기가 있습니까? 파이썬은 ... 조립 닷넷으로 컴파일 할 수 있습니다foox
해미 Grubijan을

10

Pyrex 는 Python에 대한 목록 이해 를 처음 만든 사람이 C로 컴파일하는 Python 언어의 하위 집합입니다 . 주로 래퍼 작성을 위해 개발되었지만보다 일반적인 상황에서 사용할 수 있습니다. Cython 은 파이렉스의보다 적극적으로 유지되는 포크입니다.


2
Cython은 Pyrex의 가장 널리 사용되고 적극적으로 개발 된 친숙한 포크입니다.
Mike Graham


3

자이 썬은 JVM 바이트 코드를 목표로하는 컴파일러를 가지고있다. 바이트 코드는 파이썬 언어와 마찬가지로 완전히 동적입니다! 매우 시원합니다. (예, Greg Hewgill의 답변에서 알 수 있듯이 바이트 코드는 Jython 런타임을 사용하므로 Jython jar 파일은 앱과 함께 배포해야합니다.)


2

Psyco 는 일종의 JIT (Just-In-Time) 컴파일러입니다. Python 용 동적 컴파일러는 코드를 2-100 배 빠르게 실행하지만 많은 메모리가 필요합니다.

즉, 소스를 변경하지 않고 기존 Python 소프트웨어를 훨씬 빠르게 실행하지만 C 컴파일러와 동일한 방식으로 객체 코드로 컴파일하지 않습니다.


2

대답은 "예, 가능합니다"입니다. CPython API를 사용하여 Python 코드를 가져와 동등한 C 코드로 컴파일하려고 시도 할 수 있습니다. 사실, 그 일을하는 Python2C 프로젝트가 있었지만 수년 동안 그 소식을 듣지 못했습니다 (Python 1.5에서 다시 마지막으로 보았습니다).

파이썬 코드를 가능한 한 네이티브 C로 변환하려고 시도하고 실제 파이썬 기능이 필요할 때 CPython API로 대체 할 수 있습니다. 나는 지난 한두 달 동안 그 아이디어를 가지고 놀았습니다. 그러나 많은 작업이 필요하고 중첩 된 함수, 생성기, 간단한 메서드가있는 간단한 클래스 이외의 모듈, 모듈 외부에서 모듈 전역을 수정하는 것과 같은 파이썬 함수는 C로 변환하기가 매우 어렵습니다. 등


2

이것은 파이썬을 기계 코드로 컴파일하지 않습니다. 그러나 파이썬 코드를 호출하는 공유 라이브러리를 만들 수 있습니다.

찾고있는 것이 execp에 의존하지 않고 C에서 Python 코드를 실행하는 쉬운 방법입니다. Python embedding API 호출로 래핑 된 Python 코드에서 공유 라이브러리를 생성 할 수 있습니다. 응용 프로그램은 공유 라이브러리입니다. 다른 많은 라이브러리 / 응용 프로그램에서 사용할 수 있습니다.

다음은 C 프로그램과 링크 할 수있는 공유 라이브러리를 작성하는 간단한 예입니다. 공유 라이브러리는 Python 코드를 실행합니다.

실행될 파이썬 파일은 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

당신은 그것을 시도 할 수 있습니다 python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO'). 출력됩니다 :

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

공유 라이브러리는 다음에 의해 다음과 같이 정의됩니다 callpython.h.

#ifndef CALL_PYTHON
#define CALL_PYTHON

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

#endif

관련 내용 callpython.c은 다음 과 같습니다.

// 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();
}

다음 명령으로 컴파일 할 수 있습니다.

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

callpythonfromc.c다음을 포함하는 이름의 파일을 작성하십시오 .

#include "callpython.h"

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

컴파일하고 실행하십시오.

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

이것은 매우 기본적인 예입니다. 작동 할 수는 있지만 라이브러리에 따라 C 데이터 구조를 Python 및 Python에서 C로 직렬화하는 것이 여전히 어려울 수 있습니다. 상황이 다소 자동화 될 수 있습니다 ...

누 잇카 가 도움이 될 수 있습니다.

또한 numba가 있지만 둘 다 원하는 것을 정확하게 목표로하지는 않습니다. Python 코드에서 C 헤더 생성은 가능하지만 Python 유형을 C 유형으로 변환하는 방법을 지정하거나 해당 정보를 유추 할 수있는 경우에만 가능합니다. Python ast analyzer는 python astroid 를 참조하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.