Every Python symbol reference requires a dictionary lookup. Every function call and operator requires that the type of the left hand side be examined for dispatching purposes. More than 99% of the time, the symbol and type will be the same as last time, and it's a huge win to assume that it will be and compile code for that case. You still have to be prepared for the times when it isn't, and have a backup system. That's basically what PyPy does.
More stuff is mutable in Python than really needs to be mutable.
Unladen Swallow did JIT compilation and recompilation, despite not doing better.
25% speedup for pure Python code is not that appealing in numerical analysis code, when you can use NumPy, or sprinkle a few typedefs into a critical function and compile with Cython for a 1000x speedup.
If C extension compatibility is broken, then many Python programs will altogether still be slower, despite the pure python speedup.
Not an apples to apples comparison, but my guess is the state of the art of JIT is way ahead of what the cython compiler can detect; some of the JIT tricks will likely work in the cython static translation step.