There's also the history of development. Lua has always been an embedded language and the Lua team have always had an eye cocked to size and speed.
Finally, size. The Lua runtime is tiny, these days it fits into an L2 cache. If your program doesn't have a lot of data, the effects of cache locality may give you tremendous speedups.
http://docs.python.org/2/reference/datamodel.html#special-me...
Python's standard methods of creating new objects off common operations also leads to huge amounts of memory being used compared ('functional programming' to use the term of the moment) to Lua's more c-like mutate-in-place standard behavior.
Basically pretty much anything not from __builtin__ or from a C extension is entirely mutable at any time. Consider one of the problems PyPy had with some packages. PyPy didn't support `locals()[42] = value`, which some packages actually depended upon. Nor does PyPy support `instance.__dict__[42] = value` which even more depended upon. Generally Python used a lot of simple concepts such as mutable dictionaries with heterogeneously-typed keys as the implementation of how classes, modules, etc works, which is flexible but very hard to optimize in any way (especially since they are mutable).
In contrast, the Lua developers always cared a lot about efficiency, not just speed, also memory use, and even GC pause times. They simply have different priorities than the CPython developers.
Of course, bad designed language in terms of performance will suffer more to get into the state-of-the-art