ACN 903 S0: Python in an Eggshell

Céline Comte & Fabien Mathieu

In ACN 903, we will often benchmark theoretical results against numerical values. Note that there are two popular, non-compatible, Python branches (2.x and 3.x). We will use here Python 3. No strong developing skill is required besides defining a function. If you don't know anything about Python, you can use one of the numerous online tutorials. These should bring you up to speed within an hour or less.

Just in case, a small survival kit is provided below.

1. IDEs

There are multiple IDEs to write code in Python: VI, Emacs, Eclipse... In this course, we will use Jupyter Notebooks (formerly known as IPython Notebooks). One of the main advantages of Jupyter over other IDEs is that you can write code in Python and text in Markdown in the same file.

1.1 Jupyter Notebooks

Usage. In a terminal, go to your working directory and write jupyter notebook. If you are using a computer at Télécom, you may need to specify the path, like /cal/softs/anaconda/anaconda3/jupyter notebook. This command should launch a Jupyter window in your browser, which should display the files of your current directory.

You can use Jupyter to edit an existing Notebook (a file with the extension ipynb) or create a new one by clicking the button New in the upper right corner.

To learn how to use Jupyter, use the Help! Just in case, a very few tips:

  • A notebook is made of cells that contain Python code or comments. More precisely:
    • Markdown cells allow you to write formatted text (this the format of the current cell). You can write nice LaTeX formulas like $\int_2^3 x dx =\frac{5}{2}$.
    • Code cells should contain the code you wish to evaluate. They are preceded by In [X]: on the left-hand side of the window. You can use a large range of symbols, such as greek letters. For instance, you can write the letter $\mu$ by typing \mu and then pressing Tab on the keyboard.
    • Raw cells are for plain text. They can be very useful to write code without evaluating it, but you won't need them in this course.
  • Shortcuts are your friends. Go to command mode (Esc) and hit h to see them.
  • The advantage of Notebooks is that you can evaluate your code, then change part of it, and evaluate it again... Try in this tutorial!

1.2 Spyder

You are free to use any interface you are comfortable with. If you just begin with Python, Spyder is a nice IDE to start. Spyder has three main ways of evaluating Python expressions.

  • Use the console (lower right). You can use the console to evaluate simple expressions (1+1, print("Toto")). Useful to low level debugging (check the value of a variable, the validity of an expression...). Prefer IPython Console.
  • Evaluate file. Write some Python code in the editor (left side), hit F5 and voilà. Recommended for writing fully-automated standalone scripts.
  • Evaluate cells. Write some Python code in the editor and use #%% to delimit some portion of codes, called cells. Hitting Crl+Enter will evaluate the current cell in the IPython console. Very, very useful to build and evaluate your code interactively in a step-by-step fashion.

2. Basic usage

In most languages, the keyword end is used to tell that a loop/condition/definition ends. In Python, there is no end. Instead, the ranges are defined according to indentation.

For example, compare


In [ ]:
x = 0
for i in range(5):
    x = x + i
    print("x is "+str(x))

with


In [ ]:
x = 0
for i in range(5):
    x = x + i
print("x is "+str(x))

Function definitions start with the keyword def. You can assign default values to parameters, which allows for highly flexible function calls. For example, look at the following:


In [ ]:
def my_division(x = 10, y = 3):
    return x/y

In [ ]:
print(my_division(12,4))

In [ ]:
print(my_division())

In [ ]:
print(my_division(12))

In [ ]:
print(my_division(y = 5))

In [ ]:
print(my_division(y = 2, x = 10))

Be careful, arguments without a default value must (always!) precede those with a default value in order to avoir ambiguity.

3. Modules

One of the strength of Python is the vast amount of available modules. The following modules are highly recommended: numpy (for a minimum of maths primitives) and matplotlib (for conveniently displaying the results). A convenient way to load them in Jupyter Notebooks is to use %pylab inline, a magic command that loads both modules under the names np and plt and displays the figures inside the Notebook (otherwise, they may pop-up in a separate window). Once this magic is evaluated, its effect lasts for the whole session. A minimal example:


In [ ]:
%pylab inline

In [ ]:
x = np.arange(0, 5, .1)
plt.plot(x, np.sqrt(x), 'r', label = '$\sqrt{x}$')
plt.plot(x, np.log(x+1), 'g', label = '$\ln (x+1)$')
plt.xlabel('$x$')
plt.ylabel('$f(x)$')
plt.legend(loc = 4)
plt.show()

Remark. The command %pylab inline also loads numpy and matplotlib into the main namespace, so that you don't need to write the prefixes np and plt if you want (just try to remember that you are actually calling functions from modules).


In [ ]:
x = arange(0, 5, .1)
plot(x, sqrt(x), 'r', label = '$\sqrt{x}$')
plot(x, log(x+1), 'g', label = '$\ln (x+1)$')
xlabel('$x$')
ylabel('$f(x)$')
legend(loc = 4)
show()

4. A few more tips

4.1 Import or DIY?

Whatever you want to implement, there is probably a module that does all the heavy lifting for you. Must you re-invent the wheel? This is actually a very tricky question. We won't forbid you to use extra modules, but there are things you should ask yourself before making a decision:

  • Time: Is is faster (for me) to code what I want from scratch or to Google until I find the module (if I am lucky) and then learn how to use it properly.
  • Bugs: What is the more probable? A bug in my hand-made code or using a module the wrong way (doc badly explained...).
  • Performance: Will the module be faster than a hand-made code? (short answer: yes if the module brings a lot of pre-compiled stuff in the mix; no if the module brings tons of shinny, totally irrelevant, costly, features to your objects).
  • Evolution: If I foresee a possible evolution in my code, is the evolved version available in the module? Will it be hard to make my code evolve?
  • Importance: Are we talking of the main algorithm that will be used to grade you or of some insignificant sub-sub-subfunction totally unrelated to the course?

Additionally, most of the modules you actually need are given in the Notebooks of the practicals, along with explanations.

4.2 Avoid loops if you can

Python is interpreted, not compiled. As a consequence, for loops can rapidly become your main bottleneck. Always try to rely on numpy arrays if it can avoid loops.


In [ ]:
import time
n = 10000000
t = time.time()
x = zeros(n)
for i in range(n):
    x[i] = sqrt(i)
print("FOR loops: "+str(time.time()-t)+" s")
t = time.time()
y = sqrt(arange(n))
print("Numpy: "+str(time.time()-t)+" s")

Remark: if you cannot avoid loop, there are other ways to accelerate your code that will be explained during the course. Teaser:


In [ ]:
from numba import jit
@jit()
def my_loops(n):
    x = zeros(n)
    for i in range(n):
        x[i] = sqrt(i)
    return x
my_loops(1) # trigger compilation
t = time.time()
my_loops(n)
print("FOR loops with jit: "+str(time.time()-t)+" s")

4.3 Reference passing

Reference passing can be tricky.


In [ ]:
A = [1, 2, 3, 4]
B = A
A[0] = 0
print(A==B)

In [ ]:
A = [1, 2, 3, 4]
B = A.copy()
A[0] = 0
print(A==B)