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: A 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. Make sure you see the file browser. 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 display the file browser. :scale: 70 % Fig.2: How to show the file browser. 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 make sure your code is run in the current working directory. :scale: 70 % Fig.3: How to make sure your code is run in the current working directory. .. _pf_fig4: .. figure:: pictures/spyder_setup3.png :align: center :alt: shows how to automatically load Pylab in the Ipython console and set the correct graphics mode. :scale: 70 % Fig.4: How to automatically load Pylab in the Ipython console and set the correct graphics mode. After these changes your spyder workspace should look like :ref:`Fig. 5`. Now you are ready to start learning to use Python. .. _pf_fig5: .. figure:: pictures/spyder_ws.png :align: center :alt: The recommended spyder layout: editor window left, file browser top right, IPython console bottom right. :scale: 70 % Fig.5: 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. 5 ` ). 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. 5`) 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 # regular division of 2 integers Out[5]: 0.75 In [5]: 3//4 # integer 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 - // integer 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. The so-called f-string formatting method is especially useful for this. You do this 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 the letter ``f`` directly before the opening quote indicating to python that this is a f-string and also that the variables whose values you would like to be inserted into your text are placed in curly 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 numbers are presented, e.g. how many digits after the period etc. 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}``. These are the most important and and most frequently used formatting characters that you will need. For further information on formatting check the python documentation. Functions +++++++++ Functions are like little programs that perform a specific action and return values. They play a fundamental role in any programming language; you should definitely familiarize yourself with them. The python function concept is basically the same as the function in mathematics in that it has arguments and returns values or performs some action. You define your own functions as follows (this should become natural to you): .. 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 (or keyword) 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`` by following the example below: .. 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 most powerful and important 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 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. This is something you will be doing regularly. .. 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 = []``. You can access individual elements sof the list by their ``index`` i.e. their ``position`` starting at 0. As an example in list ``lm`` above the first list element is the number 1 and it has the index 0, the second element is the string 'one' and has the index 1, the third element is the number 2 with the index 2 etc. Try this by entering: .. sourcecode:: ipython In [30]: lm[0] # should return 1 In [31]: lm[1] # should return 'one' In [30]: lm[2] # should return 2 In [30]: lm[3] # should return 'two' etc. Remember: **the first element on any list has the index 0, and the last element of any list has the index -1** Loops +++++ You can automatically access each list item sequentially by using a so-called ``for``-loop. This is very useful when you want to perform the same statements for each item in your list (or a :func:`numpy.array` see later). Below is a simple example that prints each element of the list ``lm`` together with its output. .. sourcecode:: ipython In [30]: for d in lm: ....: print( d ) ....: ....: 1 one 2 two 3 three The keyword is ``for`` followed by the variable name that should contain the current list element, in this case ``d`` followed by the word ``in`` and then the name of the list (here ``lm``). The inside of the loop is indicated by the indentation (like in a function). Here we only have one statement ``print(d)``. If you also would like to get the corresponding index of each item automatically, you will use the ``enumerate`` command as shown below: .. 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 Note the ``for`` keyword is now followed by two variable names separated by a comma ``i,d``. The first one, ``i``, contains the current index value, and the second one , ``d``, contains the current item from the list. There are many more possibilities to write a for loop, check the python documentation to learn more, but the previous two are the ones you will most likely use. 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 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 use a ``for`` loop for a dictionary to loop over all its keys: .. sourcecode:: ipython In [37]: for k in my_exp.keys(): ....: print( k, my_exp[k] ) ....: ....: In general, objects such as lists, tuples and dictionaries are called collections since they contain multiple items of data. Later you will encounter a very powerful type of a collection the multi-dimensional :func:`numpy.array`. Almost all of what follows in terms of working with data and computation 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 and store it in the variable my_file In [49]: My_content = my_file.readlines() # read everything in my_file and store it in the list My_content In [50]: my_file.close() # close the file my_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