Python has a compiler! You just don't notice it because it runs automatically. You can tell it's there, though: look at the .pyc
(or .pyo
if you have the optimizer turned on) files that are generated for modules that you import
.
Also, it does not compile to the native machine's code. Instead, it compiles to a byte code that is used by a virtual machine. The virtual machine is itself a compiled program. This is very similar to how Java works; so similar, in fact, that there is a Python variant (Jython) that compiles to the Java Virtual Machine's byte code instead! There's also IronPython, which compiles to Microsoft's CLR (used by .NET). (The normal Python byte code compiler is sometimes called CPython to disambiguate it from these alternatives.)
C++ needs to expose its compilation process because the language itself is incomplete; it does not specify everything the linker needs to know to build your program, nor can it specify compile options portably (some compilers let you use #pragma
, but that's not standard). So you have to do the rest of the work with makefiles and possibly auto hell (autoconf/automake/libtool). This is really just a holdover from how C did it. And C did it that way because it made the compiler simple, which is one main reason it is so popular (anyone could crank out a simple C compiler in the 80's).
Some things that can affect the compiler's or linker's operation but are not specified within C or C++'s syntax:
- dependency resolution
- external library requirements (including dependency order)
- optimizer level
- warning settings
- language specification version
- linker mappings (which section goes where in the final program)
- target architecture
Some of these can be detected, but they can't be specified; e.g. I can detect which C++ is in use with __cplusplus
, but I can't specify that C++98 is the one used for my code within the code itself; I have to pass it as a flag to the compiler in the Makefile, or make a setting in a dialog.
While you might think that a "dependency resolution" system exists in the compiler, automatically generating dependency records, these records only say which header files a given source file uses. They cannot indicate what additional source code modules are required to link into an executable program, because there is no standard way in C or C++ to indicate that a given header file is the interface definition for another source code module as opposed to just a bunch of lines you want to show up in multiple places so you don't repeat yourself. There are traditions in file naming conventions, but these are not known or enforced by the compiler and linker.
Several of these can be set using #pragma
, but this is non-standard, and I was speaking of the standard. All of these things could be specified by a standard, but have not been in the interest of backward compatibility. The prevailing wisdom is that makefiles and IDEs aren't broke, so don't fix them.
Python handles all this in the language. For example, import
specifies an explicit module dependency, implies the dependency tree, and modules are not split into header and source files (i.e. interface and implementation).
I think the reason is implementation simplicity. Let me elaborate.
The default value of the function is an expression that you need to evaluate. In your case it is a simple expression that does not depend on the closure, but it can be something that contains free variables - def ook(item, lst = something.defaultList())
. If you are to design Python, you will have a choice - do you evaluate it once when the function is defined or every time when the function is called. Python chooses the first (unlike Ruby, which goes with the second option).
There are some benefits for this.
First, you get some speed and memory boosts. In most cases you will have immutable default arguments and Python can construct them just once, instead of on every function call. This saves (some) memory and time. Of course, it doesn't work quite well with mutable values, but you know how you can go around.
Another benefit is the simplicity. It's quite easy to understand how the expression is evaluated - it uses the lexical scope when the function is defined. If they went the other way, the lexical scope might change between the definition and the invocation and make it a bit harder to debug. Python goes a long way to be extremely straightforward in those cases.
Best Answer
Guido van van Rossum answered it himself:
http://www.artima.com/weblogs/viewpost.jsp?thread=147358
Basically, he says that although a solution is possible, it's not congruent with how Python is.