{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction to Python\n", "\n", "\n", "## Try me\n", " [![Open In Colab](../../_static/colabs_badge.png)](https://colab.research.google.com/github/ffraile/operations-research-notebooks/blob/main/docs/source/Introduction/libraries/PythonTutorial.ipynb)[![Binder](../../_static/binder_badge.png)](https://mybinder.org/v2/gh/ffraile/operations-research-notebooks/main?labpath=docs%2Fsource%2FIntroduction%2Flibraries%2FPythonTutorial.ipynb)\n", "\n", "\n", "[Python](https://www.python.org/Python) is a high level programming language that is particularly suited for data science and operations research. Python has three main versions labelled 1, 2, and 3. Within each version, there are several minor releases, like 2.2 and 3.3. Therefore, there are many Python versions labelled 1.x, 2.x, 3.x, where the x is the minor version number. This course covers 3.x, but it is not difficult to change from one version to another. This notebook provides a quick introduction to Python in Notebooks. If you are not familiar with this environment, check the partner book on computer programming in this [link](https://programming.engineeringcodehub.com/en/latest/)\n", "\n", "## Your first code cell\n", "Let us start easy with our first code block. In this cell, we will **assign variables** and use a **function**. We will use the Python function **print()** that prints a message in the output of the code cell. The message is passed as a **string** variable. Let us introduce briefly these two concepts in the context of Jupyter Notebooks.\n", "\n", "### Basic variables\n", "Variables allow us to store a *value* and use it in our Notebook through a *name*. To assign value to a variable, we first type the name, then the equal sign (=) and then the value: \n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "x=1\n", "y=0.4\n", "msg='Hello world'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are different types of variables. In the example above, *x* and *y* are two numeric variables. We will talk about numeric variables later in this Notebook. The variable msg is a string variable (text). You can either use quotes or double quotes to assign a string variable. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic functions\n", "In Python, a function takes variables as arguments and return a value. The standard Python library provides many convenient functions. Let us start with a simple example." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello world\n", "Hello again!\n" ] } ], "source": [ "# This is your first Python cell\n", "print(msg)\n", "print('Hello again!')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The first line in the example above is a comment. Comments help us humans read the code and start with a '#'. Therefore, the code cell above has only one comment and two lines of code. The first line of code calls the function print with the string variable *msg*. Note that we can use variables in separate code cells of a Notebook. Note also that variables are declared when we Run a code cell. Cells should be run in the order they are presented in a Notebook. The second line of code takes a string value as argument, because we do not want to store this value to use it later. \n", "You can play around with the print function to print a different message or several messages, just give it a try! \n", "Do not be afraid to change the values of variables. Variables are mutable, meaning that you can change the value of a variable in your code. But before you do, note that Python documentation normally includes references to the group comedy Monty Python and the words \"spam\" and \"eggs\" are normally used as fill-in variables. The example below reassigns the value of the variable msg to print the word \"spam\". You can try to add a new line of code to print \"spam\" and \"and eggs!\" in two separate lines of the output in the next cell code." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "spam\n" ] } ], "source": [ "msg=\"spam\"\n", "print(msg) #Tip: I can also add a comment to a line of code\n", "# Add a new line to print \"spam\" and \"and eggs!\" to the output of this code cell" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Numeric Variables\n", "In Python, you can declare variables and do simple operations with them. We are going to do mathematical operations with variables, so you need to get familiar with the operands and the results, depending on the type of arguments used. Let us start with numerical variables.\n", "Python uses standard variable notations, so the operands +, -, *, / and ** represent sum, rest, multiply, divide and power operations. You can also use parenthesis to control the order of operations and declare negative or decimal variables using the - sign or a . (eg -4 or -4.5). In the following block of code you can find some examples." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2\n", "6\n", "45.0\n" ] } ], "source": [ "x = 2 #x is a numeric variable, equal to 2.\n", "y = x+4 #y is a numeric variable, equal to x+4 = 6.\n", "z = (x+3)*(y**2)/4 #z is a numeric variable equal to (2+3)*(6**2)/4 = 5\n", "print(x)\n", "print(y)\n", "print(z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that z is different from x and y. While x and y are integers, z is a floating variable. One of the main characteristics of Python is that it is a [weakly typed](https://en.wikipedia.org/wiki/Strong_and_weak_typing) programming language. Roughly, this means that you can do operations with variables of different types and Python will make the operation to its best effort to avoid a compilation error. That is why Python generated a floating variable from the division operation. Also, as in math, the order of the operands is important, and we can use parenthesis to control it.\n", "\n", "## Errors\n", "We cannot use any combination of variables. For instance, adding a numeric variable to a string could result in a compilation error. Another important piece of information is that in Jupyter, you can use variables declared in different code cells as long as you run them first. If you have run the previous cell, you can test the following cell." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "can only concatenate str (not \"int\") to str", "output_type": "error", "traceback": [ "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", "\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)", "\u001B[1;32m\u001B[0m in \u001B[0;36m\u001B[1;34m()\u001B[0m\n\u001B[1;32m----> 1\u001B[1;33m \u001B[0mms\u001B[0m \u001B[1;33m=\u001B[0m \u001B[1;34m'x is '\u001B[0m \u001B[1;33m+\u001B[0m \u001B[0mx\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m 2\u001B[0m \u001B[0mprint\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mms\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n", "\u001B[1;31mTypeError\u001B[0m: can only concatenate str (not \"int\") to str" ] } ], "source": [ "ms = 'x is ' + x\n", "print(ms)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the output of the cell now shows an error message. Do not panic. The message gives you information to interpret and correct the error. While you program, specially when you are a beginner, it is normal to get errors and very important to get familiar with the error messages. In this message, Python warns you of a TypeError and the reason why (you cannot concatenate an int to a string). There are other things that you are not allowed. For instance, you cannot divide by zero. The only person that can divide by zero is Chuck Norris. If you are not Chuck Norris, you will get a different error if you try the following cell:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "ename": "ZeroDivisionError", "evalue": "division by zero", "output_type": "error", "traceback": [ "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", "\u001B[1;31mZeroDivisionError\u001B[0m Traceback (most recent call last)", "\u001B[1;32m\u001B[0m in \u001B[0;36m\u001B[1;34m()\u001B[0m\n\u001B[1;32m----> 1\u001B[1;33m \u001B[0mz\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0my\u001B[0m\u001B[1;33m/\u001B[0m\u001B[1;36m0\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m", "\u001B[1;31mZeroDivisionError\u001B[0m: division by zero" ] } ], "source": [ "z = y/0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case, the error message is different. In both cases, you get enough context information to identify the line of code that gave error and the reason why that line resulted in an error. \n", "## Printing results to output\n", "Now some tips, if you want to print a msg with values, you can pass more variables to the print function as comma separated values. As we saw in the previous example, the print function can also take numeric values, so this is a way to get the expected result. We could also use the function str to convert a number to a string and use the + operator to concatenate the strings on a message. We can also use the [format](https://docs.python.org/3.4/library/string.html) function to a string with two parameters to tell the function print how do you want to see them:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x is 2 , y is 6 , z is 5.0\n", "x is 2, y is 6, z is 5.0\n", "x is 2, y is 6 and z is 5.0\n" ] } ], "source": [ "print('x is ', x , ', y is ', y, ', z is ', z)\n", "print('x is ' + str(x) + ', y is ' + str(y) + ', z is ' + str(z))\n", "print('x is {x:d}, y is {y:d} and z is {z:.1f}'.format(x=x,y=y,z=z))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In Python, there are many ways to achieve the same result, so it is very important to read the docs and experiment to understand the different trade-offs!." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Lists\n", "We will work quite a lot with lists in this course. Lists are used to store an indexed list of objects. To assign a list variable, we use brackets, surrounding the values of the objects we want to store. Indexed means that we can get the value of a specific item in the list using its position in the list. The index is specified again using brackets. Let us see a basic example:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello!\n", "spam\n", "eggs\n" ] } ], "source": [ "words = [\"Hello!\", \"spam\", \"eggs\"]\n", "print(words[0])\n", "print(words[1])\n", "print(words[2])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Boolean variables\n", "Another important type in Python is the Boolean type. Boolean variables can take two values, False or True.\n" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "b = True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Boolean logic\n", "Normally, in Python we used logical operands to do operations with boolean variables and build logic into our code. Basic boolean operators are *logic and* (and), *logic or* (or) and *negate* (not):" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "False\n", "False\n", "True\n", "True\n" ] } ], "source": [ "c = not b\n", "print(c)\n", "print(c & b)\n", "print(c and b)\n", "print(c | b)\n", "print(c or b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Comparisons are also important operators that return boolean values. Comparators are less (<), less or equal (<=), exactly equal (==), greater or equal (>=), and greater (>). Normally, they take numerical values:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "True\n", "True\n", "True\n", "True\n" ] } ], "source": [ "x = 5\n", "y = 6\n", "z = 6\n", "print(x < y)\n", "print(y <= z)\n", "print(y == z)\n", "print(y >= z)\n", "print(y > x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The *in* operator is important in the context of lists. It allows us to check if any element of a list contains a specific value. It can be combined with the *not* operator if we want the opposite logic." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "True\n", "True\n" ] } ], "source": [ "print(\"tomato\" in words)\n", "print(\"spam\" in words)\n", "print(\"tomato\" not in words)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Control Structures\n", "Control structures allow us to implement complex logic into our programs, creating different execution pathways or repeating code blocks to make our code more efficient. The next subsections describe basic selection structures (```if else``` clauses) and repetition structures (```for loops```) in Python.\n", "\n", "### If and else clauses\n", "If clauses allow us to execute some code if a condition is true. This is the notation of the if clause:\n", "```python\n", "if expression:\n", " sentence(s)\n", "```\n", "\n", "The *sentences* inside the if clause are only executed if the *expression* is true.\n", "On the other hand, else clauses execute sentences if the previous clause does not terminate normally. In general, we will use else clauses after if clauses to execute other clauses when the expression is not true.\n", "Therefore, an if clause combined with an else clause looks something like this:\n", "```python\n", "if expression:\n", " sentence(s)\n", "else:\n", " other_sentence(s)\n", "```\n", "\n", "Let us see an example:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "b is:\n", "False\n", "This message is always shown\n" ] } ], "source": [ "if b:\n", " print(\"b is:\")\n", " print(c)\n", "else:\n", " print(\"False!\")\n", " \n", "print(\"This message is always shown\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that there is an *indent* (a space from the left margin) in the sentences inside the if and else clauses. This is very important because it is the way we have to tell Python which lines of codes are inside a clause and which are not." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### For loops\n", "*For loops* iterate over iterable variables like lists (we will see other iterable types later in the course). *For loops* allow us to declare a variable and use it inside it to control the sentences it contains. For loops are primarily used to write very efficient code with few lines. The structure of a for loop is\n", "\n", "```python\n", "for var in vars:\n", " sentence(s)\n", "```\n", "\n", "The for loop declares a (*var*) variable that can only be used inside the sentences it contains. It will run the *sentence(s)* it contains as many times as elements are contained in the (*vars*) list used in the clause.\n", "\n", "Take as example the code we used when we defined lists. We could rewrite it as:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello!\n", "spam\n", "eggs\n" ] } ], "source": [ "for word in words:\n", " print(word) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### List comprehension\n", "One of the main features of Python lists we will use in the course is list comprehension. List comprehension allows us to assign list variables very efficiently using for loops inside a bracket. Let us see how it works by example:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 4, 9]\n", "['x_0', 'x_1', 'x_2', 'x_3']\n" ] } ], "source": [ "base = [0, 1, 2, 3]\n", "squares = [i**2 for i in base]\n", "print(squares)\n", "variable_names = ['x_'+str(i) for i in base]\n", "print(variable_names)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Libraries\n", "In Python, we can import libraries using the keyword import. Libraries encapsulate functions and declare variables that provide additional functionalities and type declarations to provide a specific functionality. In next tutorials, we are going to introduce two libraries, numpy and matplotlib, but before that, you need to know how to import a library. Imports work like this:\n", "```python\n", "import library as lib\n", "```\n", "in the code snippet above, we use the keyword import to ask python to import the *library* and use the alias *lib*. Later on our code, we will be able to use the functions in the library using the alias. Python and Conda allow you to import many useful libraries through import commands, but not every available library. For some libraries, first we will need to install the library in our environment, normally using Conda (but we could also use other tools like pip). This is however everything you need to know for now. You can now check the following tutorials to learn more about **numpy** and **matplotlib**." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" }, "pycharm": { "stem_cell": { "cell_type": "raw", "source": [], "metadata": { "collapsed": false } } } }, "nbformat": 4, "nbformat_minor": 2 }