Python is a programming language widely used in a number of applications, such as machine learning, computer graphics, video games, and shell scripts. Nearly any computer application can be implemented in Python, though there are some areas where Python may not be the best solution, such as low-level programs that have to access hardware. In general, though, Python is a good tool for initial application prototyping. Once the initial design has been clarified with Python, it can be re-implemented in a more appropriate language, or the Python code itself can be revised for better optimization.
What is Python?
Python versions
Two main version lines exist for Python: Python 2 and Python 3. Python 2 is the legacy line (version 2.7.15, at the time of writing); while it is still used for some new projects nowadays, it is predominately seen in old software that either can't or won't be upgraded to the Python 3 line. Python 2.7 is the last major release number for this line; incremental upgrades will be provided to back-port Python 3 features or for security patching, but no major features are written for it.
Python 3 (version 3.7.0, as of this writing) is the main development line, and all new features are added here first. Many features in Python 3 are not available in Python 2, or are renamed, so significant effort must be made to convert one version to another.
The Python tools 2to3 and 3to2 are provided with every Python download to help with this conversion process, but they can only handle simple things, such as changing print statements or automatically renaming built-in functions. Anything beyond that requires a programmer to look at the code and make the changes. As this is a non-trivial process (each line of code must be assessed), it may be easier to simply rewrite the code.
Python, as normally used, is technically called CPython, as it is actually written in C code. Python has bindings for use in non-native Python environments, such as Java (Jython), the .NET framework (IronPython), or microcontrollers (MicroPython). This means that you can write regular Python code and it will be interpreted into the correct byte-code for a particular environment. This way, for example, you can interact with a Java program without having to actually write Java code; the Jython interpreter translates Python into equivalent Java code.
Interpreted versus compiled
Python is classified as a scripting language, because it doesn't require a compiler to generate machine code. It actually uses an interpreter to create byte-code, which is cross-platform, and, therefore, any system that has Python installed should be able to run the code. (There are caveats to this, which will be addressed later in the book.)
Byte-code is common among higher-level languages, such as Java, because it makes it easy to write software that runs in many different environments. Languages that use byte-code have a language-specific virtual machine; that is, the virtual machine's sole purpose is to translate the byte-code into something the host computer's operating system can understand. Any OS that has a language-specific virtual machine can process and use the byte-code, thus making an interpreted programming language system agnostic. The programmer doesn't have to do anything special prior to releasing the software.
Machine code is basically the opposite. It is compiled from the raw source code for a particular computer system; this is more common for low-level languages like C++ and Go. The code is portable between systems, but has to be recompiled for each system; it cannot be run immediately like it can with byte-code. Thus, a programmer must either generate the compiled code for each target OS, or has to provide the source code so an end user can perform that compilation step.
Compiled languages tend to operate faster than interpreted languages because the code has already been optimized for the environment. The compiler also finds many errors before the code is actually executed (the "runtime"). However, compilers can take minutes or even hours to compile the source code, depending on various factors. When errors occur, the programmer has to fix them and rerun the compiler; this compile-fix-compile process continues until the compiler returns no errors.
Compilers can't identify all errors, so the final product must be tested. If problems are found, the code must be fixed, leading to another round of compile-fix-compile, as the fixes to the runtime errors may introduce new errors during compilation.
Working with interpreted languages can be quicker, as there is no compilation step. The code can be run as often as necessary while fixing errors, so the development process is much faster. For many products, developer time is more important than computer time, so having a programmer who can quickly write a program is more desirable than a program that is quicker to run.
In addition, utilizing interpreted languages also allows software developers to provide a scripting interface to the end user; the user can manipulate the program without having to dive into the source code itself. Referring to the previous Jython example, a program written in Java could allow the user to manipulate the data or the actions performed by writing a simple Jython script, essentially adjusting on the fly how the results are generated. This type of customization is commonly found in video games, such as modding communities.
Dynamic versus static
Python is a dynamic typed language. Many other languages are static typed, such as C/C++ and Java. A static typed language requires the programmer to explicitly tell the computer what type of "thing" each data construct is.
For example, if you were writing a C inventory program and one of the variables was cost, you would have to declare cost as a float type, which tells the C compiler that the only data that can be used for that variable must be a floating point number, that is, a number with a decimal point, such as 3.14. If any other data type was assigned to that variable, like an integer or a text string, the compiler would give an error when trying to compile the program. (A programming variable is similar to a math variable; it's just a placeholder for a particular value.)
Python, however, doesn't require this. You simply give your variables names and assign values to them. The interpreter takes care of keeping track of the kinds of objects your program is using. This also means that you can change the size of the values as you develop the program. (For the curious, this is handled by adding metadata to a C construct. Every time the item is used, the metadata is looked at to determine how Python should interact with it, as well as potentially modifying the metadata.)
Say you have another decimal number you need in your program. With a static typed language, you have to decide the memory size the variable can take when you first initialize that variable. A double is a floating point value that can handle a much larger number than a normal float (the actual amount of memory used depends on the operating environment, but a float is typically 32 bits long while a double is 64 bits). If you declare a variable to be a float but later on assign a value that is too big to it, your program can develop errors or be slower than expected; changing it to a double will correct these problems.
With Python, it doesn't matter what type of data a construct is. You simply give it whatever number you want, and Python will take care of manipulating it as needed. It even works for derived values. For example, say you are dividing two numbers. One is a floating point number and one is an integer. Python realizes that it's more accurate to keep track of decimals so it automatically calculates the result as a floating point number. The following code example shows what it would look like in the Python interpreter—floating point and integer division:
>>> 6.0 / 2
3.0
>>> 6 / 2.0
3.0
As you can see, it doesn't matter which value is the numerator or denominator; Python "sees" that a float is being used and gives the output as a decimal value.
This would be a good time to note one of the differences between Python 2 and Python 3. Python 2 truncates division operations, whereas Python 3 automatically converts to decimal values. The following section offers examples of the two versions.
Python 2 versus Python 3 division
While most Python 2.7 code is compatible with 3.x code, you can see that certain things don't carry over well. For example, Python 2 truncates the output of division calculations:
# Python 2
>>> 7/2
3
Python 3, as the following shows, provides the remainder when dividing. This is important to remember, as the code you're writing will break if it uses features or side effects of a particular version but is run on a different version:
# Python 3
>>> 7/2
3.5