Python Fundamentals =================== Python is case sensitive like C/C++. This is different from other languages such as FORTRAN or BASIC. To start working with python do one the following: * If you have installed Anaconda On Mac, Windows or Linux click on the **Anaconda Navigator** icon to start the software. You should see the following: .. _pf_fig1: .. figure:: pictures/anaconda_navigator.png :align: center :alt: An typical example of the anaconda navigator page. :scale: 70 % Fig.1: Anaconda Navigator window To start the work space click on the Spyder **launch** button(red arrow :ref:`Fig. 1`) . This opens the work space window (:ref:`Fig. 2` ). The next step is to customize Spyder. Delete the help window, and the variable explorer window, this should then reveal the file explorer window below (red arrow :ref:`Fig.2 `). You can save your new layout using :math:`View \rightarrow Window\ Layouts \rightarrow Save\ current\ layout` and enter a your name of choice for the layout. .. _pf_fig2: .. figure:: pictures/spyder_setup1.png :align: center :alt: Shows where to click to close the help window and the variable explorer window :scale: 80 % Fig.2: Delete the help window and the variable explorer windows below by twice clicking the cross (red arrow) After this you should open the settings window by clicking on the little wrench icon (red arrow :ref:`Fig. 3`). Then select as shown. After you have completed this click **Apply** and close. .. _pf_fig3: .. figure:: pictures/spyder_setup2.png :align: center :alt: shows how to set the working directory to the current working directory and the automatically load Pylab in the Ipython console. :scale: 80 % Fig.3: How to change Spyder settings. After these changes your spyder workspace should look like :ref:`Fig. 4`. Now you are ready to start learning to use Python. .. _pf_fig4: .. figure:: pictures/spyder_ws.png :align: center :alt: The recommended spyder layout: editor window left, file browser top right, IPython console bottom right. :scale: 80 % Fig.4: The Spyder work space, showing the file browser (1), the editor window(2) and the python interpreter (to enter commands) (3). To work interactively with Python you enter Python commands in the console window (area 3 in :ref:`Fig. 4 ` ). In the documentation and the tutorial you will read about entering commands to IPython which means the console window where IPython is running. A very short introduction into Python for non-programmers --------------------------------------------------------- You can find general information on Python in the `python tutorial `_. A great, free online course on Python programming can be found at `codeacademy `_. An more detailed introduction to scientific computation with Python including some the tools that we are going to use here as well are the `SciPy Lectures `_ which I can highly recommend especially chapters 1.1 - 1.7. This introduction is interactive and helps you to learn programming in Python. Below is a very short introduction specifice tailored for the needs in the Intermediate Lab Course. Python is an interactive interpreter which means your commands are interpreted as soon as they have been entered in the command area and completed with hitting the **enter** or **return** key. If you are using Spyder you should enter your commands in the python interpreter area (number (3) in :ref:`Fig. 4`) Simple statements and data types ++++++++++++++++++++++++++++++++ You can use python as a simple calculator: .. sourcecode:: ipython In [2]: 2.3 + 3.2 # hit return and you get Out[2]: 5.5 If you want to calculate the power of a number you type: .. sourcecode:: ipython In [3]: 4**2 # calculate the square of 4 Out[3]: 16 In [4]: 4**0.5 # calculate the square root of 4 Out[4]: 2.0 Notice the difference between the output ``Out [3]: 16`` and ``Out [4]:2.0``. In the first case, the output ``16`` is an integer (numbers like -1,3,4,5,5264) while in the second case ``2.0`` the result is a so-called floating point number or a float. You have now encountered what are called data types (Python also knows about complex numbers, they are entered as ``1. + 5.j``). There are many more data types and a program needs to now what kind of data type is it working with. E.g. operations between integers only result in integers while operations between integers and floats or between floats only result in floats: .. sourcecode:: ipython In [5]: 3/4 # division of 2 integers Out[5]: 0 In [6]: 3./4. # division of 2 floats Out[6]: 0.75 For the moment I recommend you only work with floats and therefore any number you enter contains a period as in the previous example. Python determines from your input what data type it is dealing with. Standard mathematical operations in Python: - +/- addition, subtraction - \* multiplication - / division - ** power - % modulo (or reminder) Try them out ! You can also enter text. Text is entered either between single quotes such as ``'hello there'`` or with double quotes ``"hello there"``. .. sourcecode:: ipython In [7]: 'Hello there' Out[7]: 'Hello there' Text like ``'Hello there'`` is called a string (a string of characters). You can add strings together with ``+``: .. sourcecode:: ipython In [8]: 'Hello there' + ' how are you ?' Out[8]: 'Hello there how are you ?' As you can see the two strings have been 'glued' together (called concatenated). This is useful when you have to create file names automatically or to make nice output. You can store any value of any data type in a variable (the name on the left side of the ``=`` sign): .. sourcecode:: ipython In [9]: greeting = 'Hello there' + ' how are you ?' # store the combined string in variable in greeting In [10]: x = 3.3 # store the value 3.3 in x In [11]: y = x**2 # calculate the square of 3.3 and store the value in y In [12]: sum_xy = x + y # add them together In [13]: print( greeting,x, y, sum_xy ) # print the result Hello there how are you ? 3.3 10.89 14.19 In the example above you encountered a new command: ``print``. It takes the comma separated list of objects following it, and writes them typically to your screen. Every line in the example above is called a statement. You can put these statements into a file and then execute them using the ``run`` command. A file containing statements is called a script (for more information see :ref:`script`). In order to see the results obtained in a script one often uses the ``print`` command. You can also control how numbers are presented. This is done using formatting. It is especially useful if you have a certain number of significant digits and it makes no sense to display more. The result of formatting is a string that can be printed or be used in another way (e.g. as part of a filename) Here is an example for formatting integers and floats. Instead of just printing the numbers from the previous example you would like to make a sentence where these numbers are part of. In Python 3 one can use the so-called f-string formatting as follows. .. sourcecode:: ipython In [13]: result = f"using x = {x} and y = {y} the sum of the {2} arguments is {sum_xy}" In [14]: result Out[14]: 'using x = 3.3 and y = 10.889999999999999 the sum of the 2 arguments is 14.189999999999998' Note that the variables whose values you would like to be inserted into your text are place in braces. With out any additional information on how the numbers are to be presented Python will print the full representation. In general you would like to control how number are presented. This formatting information is added to the variable name and separated by a colon as in the example below: .. sourcecode:: ipython In [13]: result = f"using x = {x:.1f} and y = {y:.1e} the sum of the {2:d} arguments is {sum_xy:.2e}" In [14]: result Out[14}: 'using x = 3.3 and y = 1.1e+01 the sum of the 2 arguments is 1.42e+01' The ``{x:.1f}`` means print the value of the variable x in the format ``.1f`` meaning show 1 digit after the period and display it as a regular number. ``{y:.1e}`` means, print the value of variable ``y`` and display it in scientific notation with 1 digit after the period. ``{2:d}`` means print the number 2 as an integer. And the last format statement ``{sum_xy:.2e}`` means print ``sum_xy`` in scientific notation with 2 digits after the period. If you also had a variable containing a string (e.g. called ``string_var``) the format would be ``{string_var:s}``. For further information on formatting check the python documentation. Functions +++++++++ Functions are like little programs that perform a specific action and return values. The concept is basically the same as the function in mathematics. You can define your own functions as follows: .. sourcecode:: ipython In [14]: def add_two_things(x,y): ....: sum = x + y ....: return sum # hit enter twice to end the function definition ....: In [15]: In this example we defined a function called ``add_two_things``, which takes two arguments called ``x`` and ``y``. The 'python command' to define a function is ``def`` then the name of the function with its arguments followed by a colon ``:``. This is important. In ipython you see that the prompt changes and the next lines are indented. All that is indented belongs now to the function. The ``return`` statement returns a value calculated in the function. You close the function definition by hitting ``enter`` twice. In a script you just end the indentation. You can now try this new function: .. sourcecode:: ipython In [15]: add_two_things(4.,5.) Out[15]: 9.0 # the function returns the sum of 4 and 5 In [16]: add_two_things('hello ', 'there!') Out[16]: 'hello there!' # it knows how to handle strings, too In [17]: add_two_things('hello ', 4.) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) /Users/boeglinw/Documents/teaching/Classes/Modern_lab_Software/python/sphinx/ in () /Users/boeglinw/Documents/teaching/Classes/Modern_lab_Software/python/sphinx/ in add_two_things(x, y) TypeError: cannot concatenate 'str' and 'float' objects The last addition did not work since python does not know how to add a string and a float. Functions are very useful when using python. You can even define one on one line, a so-called ``lambda function``: .. sourcecode:: ipython In [18]: square = lambda x: x**2 # define the function square(x) # define the function In [19]: square(2.) # use the function Out[19]: 4.0 There are a huge number of functions defined in python. To use one you **MUST** supply at least ``()``. Without it python will tell you that it is a function: .. sourcecode:: ipython In [20]: square # calling the function without arguments Out[20]: at 0x1b82430> In [21}; square() # calling the function with the wrong number of arguments --------------------------------------------------------------------------- TypeError Traceback (most recent call last) /Users/boeglinw/Documents/teaching/Classes/Modern_lab_Software/python/sphinx/ in () TypeError: () takes exactly 1 argument (0 given) In [22]: Calling a function with the wrong number of arguments does not work ! Below is an example of a function, as you would put it in a script, to calculate the magnetic field at the center of a Helmholtz Coil. The three arguments are the current and the radius and the number of turns:: def B(I, R, N): mu0 = 4.*np.pi* 1e-7 B = mu0*N*I/R * (4./5.)**1.5 return B # end of the function definition # use the function current = 0.8 print( 'the magnetic field is = {0:.2e} '.format( B(current, 0.15, 131) ) ) The last line nicely prints the value of the calculated field for a current of 0.8A, a coil radius of 0.15 m and 131 turns. Lists, tuples and dictionaries ++++++++++++++++++++++++++++++ One of the powerful features of Python is working with various kinds of collections of data. The first one is a simple **list**. The various items of a list are between brackets and separated by commas. Here is are a few examples: .. sourcecode:: ipython In [23]: l = [1.,2.,3.,4.,5.] # a simple list of floats In [24]: l Out[24]: [1.0, 2.0, 3.0, 4.0, 5.0] In [25]: lm = ll = [1, 'one', 2, 'two', 3, 'three'] # a list of mixed objects In [26]: lm Out[26]: [1, 'one', 2, 'two', 3, 'three'] In [27]: lm[3] # this is how you access e.g. the 4th element of the list Out[27]: 'two' You can get the length of a list using ``len(l)`` (a string is closely related to a list of characters) You can add more elements to the list using the ``append`` function .. sourcecode:: ipython In [28] l.append(6.) In [29]: print( l ) [1.0, 2.0, 3.0, 4.0, 5.0, 6.0] You can create an empty list ``l_empty = []``. Loops +++++ When you want to perform the same statements for each item in a list or a :func:`numpy.array`, you can use the ``for`` loop: .. sourcecode:: ipython In [30]: for d in lm: ....: print( d ) ....: ....: 1 one 2 two 3 three and you can also enumerate the content of the list: .. sourcecode:: ipython In [30]: for i,d in enumerate(lm): ....: print( 'element number : ', i, ' contains : ', d ) ....: ....: element number : 0 contains : 1 element number : 1 contains : one element number : 2 contains : 2 element number : 3 contains : two element number : 4 contains : 3 element number : 5 contains : three There are many more possibilities, check the python documentation to learn more. Another important list type is the **tuple**. It is a list where you cannot add or delete elements, you can only change an element's value .. sourcecode:: ipython In [31]: t = ('first_element', 'second', 'third and last') # this is a tuple The last type of a collection of data is the **dictionary**. It is similar to a list but instead of an index you have a ``key``. A key is a string and the value is separated from the key by a colon ``:``. Here is an example: .. sourcecode:: ipython In [32]: my_exp = {'Voltage':150., 'coil radius':0.15, 'Nturns':132} # notice the {} indicating a dictionary In [33]: my_exp Out[33]: {'Nturns': 132, 'Voltage': 150.0, 'coil radius': 0.14999999999999999} Note how the sequence of keys is very different from what you entered. You can access individual elements by using their keys, and you can get a list of all available keys: .. sourcecode:: ipython In [34]: my_exp['Voltage'] Out[34]: 150.0 In [35]: my_exp.keys() # this gives you the list of keys Out[35]: ['coil radius', 'Nturns', 'Voltage'] You can also easily add an additional key by doing: .. sourcecode:: ipython In [36]: my_exp['em_th'] = 1.76e+11 In [37]: my_exp.keys() Out[37]: ['em_th','coil radius', 'Nturns', 'Voltage'] You can also use ``for`` loop for a dictionary: .. sourcecode:: ipython In [37]: for k in my_exp.keys(): ....: print( k, my_exp[k] ) ....: ....: Later you will encounter a very powerful type of collection the multi-dimensional :func:`numpy.array`. Almost all of what follows in terms of working with data is based on working with :func:`numpy.array`'s. Slices ++++++ This is a way of selecting a subset of data from a list (this will not work for a dictionary !). Here is an example with a simple list: .. sourcecode:: ipython In [37]: li = [10, 20, 30, 40, 50, 60] # a list of integers In [38]: li[0:3] # select all elements starting with 0 up to 3 (element 3 is NOT included) Out[38]: [10, 20, 30] In [39]: li[-1] # select the last element of a list Out[39]: 60 In [40]: li[-2] # second to last element Out[40]: 50 In [41]: li[:4] # select all from the beginning up to 4 (4 is NOT included) Out[41]: [10, 20, 30, 40] In [42]: li[:-1] # select all except the last element Out[42]: [10, 20, 30, 40, 50] In [43]: p = 'Physics' In [44]: p[::-1] # reverses the sequence of the list Out[44]: 'scisyhP' In [45]: li[::-1] Out[45]: [60, 50, 40, 30, 20, 10] The principle of slices is illustrated below:: +----+----+----+----+----+----+ |10 | 20 | 30 | 40 | 50 | 60 | arrangement of the list +----+----+----+----+----+----+ 0 1 2 3 4 5 6 positive slice indices -6 -5 -4 -3 -2 -1 negative slice indice ``li[1:5]`` means, all the elements between the slice indices 1 and 5. You can even create a slice and store it in a variable: .. sourcecode:: ipython In [46]: my_slice = slice(2,5) In [47]: li[my_slice] Out[47]: [30, 40, 50] This is widely used in Python. Reading a text file +++++++++++++++++++ This is a simple example how you can read a text file, if you want to know how to read a binary file you need to consult the python documentation. .. sourcecode:: ipython In [48]: my_file = open('my_file.dat') # open the file In [49]: My_content = my_file.readlines() # read everything in the file and store it in the list my_content In [50]: my_file.close() # close the file In [50]: print( My_content ) # print the content of the file Writing a text file +++++++++++++++++++ Here is how you create a new file and write some text into it: .. sourcecode:: ipython In [51]: new_file = open('my_new_file.dat','w') # open the file, note the 'w' In [52]: new_file.write("This is the first sentence written into the new file (I will add a newline caracter next) \n") In [53]: new_file.write("Here is the next line \n") In [54]: new_file.write("And here is the last line \n") In [55]: new_file.close() # now the file is available to other programs .. include:: include/links.rst