Why is it impossible to create a compiler than can compile Python to machinecode like C?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Feb 28 23:27:28 EST 2013


On Thu, 28 Feb 2013 12:25:07 -0800, kramer65 wrote:

> Hello,
> 
> I'm using Python for a while now and I love it. There is just one thing
> I cannot understand. There are compilers for languages like C and C++.
> why is it impossible to create a compiler that can compile Python code
> to machinecode?

Your assumption is incorrect. You can compile Python to machine-code, at 
least sometimes. It is quite tricky, for various reasons, but it can be 
done, at various levels of efficiency.

One of the oldest such projects was Psyco, which was a Just-In-Time 
compiler for Python. When Psyco was running, it would detect at run time 
that you were doing calculations on (say) standard ints, compile on the 
fly a machine-code function to perform those calculations, and execute 
it. Psyco has more or less been made obsolete by PyPy, which does the 
same thing only even more so.

http://en.wikipedia.org/wiki/Psyco
http://en.wikipedia.org/wiki/PyPy


> My reasoning is as follows:
> When GCC compiles a program written in C++, it simply takes that code
> and decides what instructions that would mean for the computer's
> hardware. What does the CPU need to do, what does the memory need to
> remember, etc. etc. If you can create this machinecode from C++, then I
> would suspect that it should also be possible to do this (without a
> C-step in between) for programs written in Python.

In principle, yes, but in practice it's quite hard, simply because Python 
does so much more at runtime than C++ (in general).

Take an expression like:

x = a + b

In C++, the compiler knows what kind of data a and b are, what kind of 
data x is supposed to be. They are often low-level machine types like 
int32 or similar, which the CPU can add directly (or at least, the 
compiler can fake it). Even if the variables are high-level objects, the 
compiler can usually make many safe assumptions about what methods will 
be called, and can compile instructions something like this pseudo-code:

10 get the int64 at location 12348   # "a"
20 get the int64 at location 13872   # "b"
30 jump to the function at location 93788  # add two int64s
40 store the result at location 59332  # "x"

which is fast and efficient because most of the hard work is done at 
compile time. But it's also quite restrictive, because you can't change
code on the fly, create new types or functions, etc. (Or, where you can,
then you lose some of the advantages of C++ and end up with something
like Python but with worse syntax.)

In Python, you don't know what a and b are until runtime. They could be 
ints, or lists, or strings, or anything. The + operator could call a 
custom __add__ method, or a __radd__ method, from some arbitrary class. 
Because nearly everything is dynamic, the Python compiler cannot safely 
make many assumptions about the code at compile time. So you end up with 
code like this:

10 search for the name "a" and take note of it
20 search for the name "b" and take note of it
30 decide whether to call a.__add__ or b.__radd__
40 call the appropriate method
60 bind the result to the name "x"


You can get an idea of what Python actually does by disassembling the 
byte code into pseudo-assembly language:


py> code = compile("x = a + b", '', 'single')
py> from dis import dis
py> dis(code)
  1           0 LOAD_NAME                0 (a) 
              3 LOAD_NAME                1 (b) 
              6 BINARY_ADD           
              7 STORE_NAME               2 (x) 
             10 LOAD_CONST               0 (None) 
             13 RETURN_VALUE         


Nevertheless, PyPy can often speed up Python code significantly, 
sometimes to the speed of C or even faster.

http://morepypy.blogspot.com.au/2011/02/pypy-faster-than-c-on-carefully-crafted.html

http://morepypy.blogspot.com.au/2011/08/pypy-is-faster-than-c-again-string.html



-- 
Steven



More information about the Python-list mailing list