{ "cells": [ { "cell_type": "markdown", "source": [ "# Variables\n", "## Try me\n", "\n", "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ffraile/computer_science_tutorials/blob/main/source/Introduction/tutorials/Variables.ipynb)[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/ffraile/computer_science_tutorials/main?labpath=source%2FIntroduction%2Ftutorials%2FVariables.ipynb)\n", "\n", "## Introduction\n", "In the **Hello world** Notebook, we already provided an informal definition of variables as symbols that we introduce in our code to manage values that might change, for instance, depending on the use we want to make of the program. Thinking of programming languages as a proxy language between natural language and machine language, we can think of variables as human-readable names that we give to binary values stored in memory. As we know, computers work with binary data, and programming languages introduce variables to facilitate the management of these data.\n", "\n", "Although experienced programmers exhibit extreme binary code interpretation skills, for most humans, binary code is just gibberish and messages between humans and machines could be lost in translation if programming languages did not introduce variables to facilitate the process, as this video illustrates:\n", "\n", "\n" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "\n", "### Assignment\n", "As mentioned in the introduction, in Python, we define a variable and assign a value using the '=' operator, in what is called an assignment statement. To the left of the '=' operator, we write the name of the variable, and to the right of the '=' operator, we give the value that we want to assign to the variable, for instance:\n" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": 1, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The value of my first variable is: 15\n" ] } ], "source": [ "my_first_variable = 15\n", "print(\"The value of my first variable is:\", my_first_variable)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "### Learn the type of a variable (Type function)\n", "If we want to learn the type of the variable, we can use the built-in function ```type()``` ([see the docs](https://docs.python.org/3/library/functions.html#type)).\n", "\n", "### Type function\n", "The type function returns the type of the object that it is passed as argument. For instance, let us see what happens if we call the type function on the variable my_first_variable, it will return the string 'int'.\n" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": 2, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The type of my_first_variable is: \n" ] } ], "source": [ "print(\"The type of my_first_variable is:\", type(my_first_variable))" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "Note that the type is ``````, which is the type of the integer numbers in Python." ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "### Implicit versus Explicit Assignment\n", "Note that, to be able to support the management of different types of information, we need to specify what is the type of variable we want to store, but in the previous code cells, we never did specify the type of variables explicitly. In some programming languages, like C or Java, the type of variables must be specified explicitly, meaning that we need to define the type in the assignment statement. In Python, as we will see, we do not need to specify the type explicitly, we can let Python infer the type of the variable from the value that we assign to it. We will see this in detail in the next sections, but for now, let us assume that we want to store a number in a variable. We can just write the number to the right of the '=' operator, and Python will infer the type of the variable from the value that we assign to it." ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ " However, we can also explicitly specify the type of the variable, in this case, we want to store a string in a variable. We can do this by writing the type of the variable in the assignment statement, using the built-in ```string()``` function ([see the docs](https://docs.python.org/3/library/functions.html#str))." ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": 3, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The value of my number string is: 10\n", "The type of my number string is: \n" ] } ], "source": [ "my_number_string = str(10) # This is a string variable, using the str() function to convert the number 10 into a string.\n", "print(\"The value of my number string is:\", my_number_string)\n", "print(\"The type of my number string is:\", type(my_number_string))" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "Note that the syntax in both examples is similar, and we use the same value (10), but the resulting type of the variable is different (in the latter script, the type is ``````. In the first example, we let Python infer the type of the variable from the value that we assign to it, and in the second example, we explicitly specify the type of the variable using the ```str``` function, which converts the argument into a string. Normally in Python, we will define the type of the variable implicitly, but in some cases we will specify it explicitly to avoid ambiguity and errors. For instance, say we want to build a program that asks the user to enter a number, and then prints the power of 2 of the provided number back to the user, we can use the ```int``` function to convert the result of the ```input()`` function into an integer number, so that we can perform numeric operations:\n" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": 4, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The power of 2 of 4 is 16\n" ] } ], "source": [ "number = int(input(\"Please enter an integer number: \"))\n", "result = number * number # The asterisk is the multiplication operator\n", "print(\"The power of 2 of\", number, \"is\", result)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "Had we not converted the result of the ```input()``` function into an integer number, we would have had an error, because we would have tried to perform a numeric operation on a string. Just try the same example without the ```int()```function to see what happens!" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "## Variables and Types\n", "\n", "\n", "\n", "Ok, so we know that, ultimately, the value of a variable is a binary value, so Python will need to encode the value of the variable into bits. The process of encoding the value will depend on the **type** of information that we want to store. For instance, for some application we might want our variable to represent the text \"10\", but for other applications we might want to store the number 10 in decimal, and in other applications we might want to store the sequence of bits 10.\n", "\n", "The most basic variable types in Python are Integer numbers, floating point numbers, strings (sequences of characters), and boolean. These basic types are known as **primitive types**. Moreover, the main types of data (and in extension of variables) are:\n", "\n", "- **Numbers**: Numbers represent data like integers, floating-point numbers, complex numbers, etc. with which we can perform arithmetic operations and math.\n", "- **Strings**: String are sequences of characters of any length, representing paragraphs, words, sentences, or characters.\n", "- **Boolean**: boolean values, either True or False, are used in boolean logic operations.\n", "\n", "Additionally, in Python, we have other types of variables known as **iterables**, which are collections of values. Due to the increased complexity and importance of iterables, they are presented in another tutorial.\n", "\n", "The following sections describe the main characteristics of these variables in Python, but before we dive into practice, let us pay some attention to the syntax of the assignment statement.\n", "\n", "### Numeric types\n", "\n", "There are three basic numeric types in Python:\n", "\n", "- **Integer (int)**: Integer numbers, i.e. numbers with no decimal part\n", "- **Float (float)**: Numbers with fractional part\n", "- **Complex (complex)**: Numbers with real and imaginary part\n", "\n", "As mentioned above, the specific type of the variable is implicitly obtained from the assignment. As shown in this code cell, to define an integer variable, you just need to enter the integer value to the right of the '=' operator. To define a float variable, you need to enter the float value to the right of the '=' operator, using the '.' (dot) character as decimal separator. And finally, to define a complex variable, you need to enter the complex value to the right of the '=' operator, using the 'j' character to define the imaginary part and using the '+' operator to define a variable with combining real and imaginary parts:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": 5, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The value of integer_var is:\n", "5\n", "The type of integer_var is:\n", "\n", "The value of float_var is:\n", "5.2\n", "The type of float_var is:\n", "\n", "The value of complex_var is:\n", "(1.5+2.6j)\n", "The type of complex_var is:\n", "\n" ] } ], "source": [ "# Integer variable\n", "integer_var = 5\n", "print(\"The value of integer_var is:\")\n", "print(integer_var)\n", "print(\"The type of integer_var is:\")\n", "print(type(integer_var))\n", "\n", "# Real variable\n", "float_var = 5.2\n", "print(\"The value of float_var is:\")\n", "print(float_var)\n", "print(\"The type of float_var is:\")\n", "print(type(float_var))\n", "\n", "#Commplex variable\n", "complex_var = 1.5+2.6j\n", "print(\"The value of complex_var is:\")\n", "print(complex_var)\n", "print(\"The type of complex_var is:\")\n", "print(type(complex_var))\n", "\n" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Built-in numeric type constructors\n", "Also, there are built-in functions to define the type of a numeric variables explictly, as already shown before with the int type and the ```int()``` function, we can use the float function ```float()``` to explicitly define a float variable, and the complex function ```complex()``` to define a complex variable:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": 6, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The value of int_var_2 is: 5\n", "The type of int_var is: \n", "The value of float ar is: 3.0\n", "The type of float_var_2 is: \n", "(5+2.5j)\n", "\n" ] } ], "source": [ "# int creates an integer variable, from a number of string\n", "int_var_2 = int(\"5\")\n", "print(\"The value of int_var_2 is:\", int_var_2)\n", "print(\"The type of int_var is:\", type(int_var_2))\n", "\n", "# float() creates a float variable from a number or string, if possible\n", "float_var_2 = float(3)\n", "print(\"The value of float ar is:\", float_var_2)\n", "print(\"The type of float_var_2 is:\", type(float_var_2))\n", "\n", "# complex() creates a complex number from real and imaginary floating numbers:\n", "complex_var_2 = complex(5, 2.5)\n", "print(complex_var_2)\n", "print(type(complex_var_2))" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Built-in functions\n", "There are some interesting built-in functions that can be used with numeric variables. For instance:\n", "\n", "- **abs()**: Returns the absolute value of a number (see the docs)[https://docs.python.org/3/library/functions.html#abs]\n", "- **round()**: Rounds a number to a given number of decimal places (see the docs)[https://docs.python.org/3/library/functions.html#round]\n", "- **max()**: Gets the maximum numeric value of a set of numbers (see the docs)[https://docs.python.org/3/library/functions.html#max]\n", "\n", "#### Methods and attributes\n", "We have not introduced yet the concepts of methods and attributes. We will cover this concepts more extensively in the object-oriented programming tutorial, but for now, let´s provide an informal definition of the concepts:\n", "\n", "- **Methods**: Methods are functions that are associated with the type of the object, and are called using the dot (.) operator on the variable. For instance, if we have a variable ```my_number``` of type ```float```, we can call the ```as_integer_ratio()``` method on this variable, and the result will be a *duple* of numbers containing the numerator and denominator of a fraction of value equal to ```my_number```.\n", "- **Attributes**: Attributes are variables that are associated with the type of the object, and are accessed using the dot (.) operator on the variable. For instance, if we have a variable ```my_number``` of type ```complex```, we can access the imaginary part in the ```imag``` attribute on this variable.\n", "\n", "The numeric built-in types provide some interesting built-in methods and attributes, shown in the following code cell:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "float_var_3 = 1.5\n", "\n", "# as_integer_ratio() provides a pair of positive numbers whose ratio is equal to original float number\n", "\n", "print(\"The float value\", float_var_3, \"can be expressed as the ratio of\", float_var_3.as_integer_ratio())\n", "\n", "complex_var_3 = 2.5 + 5j\n", "\n", "# conjugate() returns the complex conjugate of the original complex number\n", "print(\"The conjugate of\", complex_var_3, \"is\", complex_var_3.conjugate())\n", "\n", "# imag returns the imaginary part of the original complex number\n", "print(complex_var_3.imag)\n", "\n", "# real returns the real imaginary part of the original complex number\n", "print(complex_var_3.real)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Arithmetic operators and numeric variables\n", "Basic arithmetic operators like addition, subtraction, multiplication, and division operators can be used with numeric variables in Python. The following table lists the arithmetic operators that can be used with numeric variables:\n", "\n", "| Operation | Symbol | Description |\n", "|--------------------| ------ |------------------------------------------------------|\n", "| Addition | ```+```| Adds the value of the operands |\n", "| Subtraction | ```-```| Subtracts the value of the operands |\n", "| Multiplication | ```*```| Multiplies the value of the operands |\n", "| Division | ```/```| Divides the value of the first operand by the second |\n", "| Exponentiation | ```**```| Raises the first operand to the power of the second |\n", "| Floor division | ```//```| Divides the first operand by the second and returns the integer part of the result |\n", "| Remainder (Modulo) | ```%```| Returns the remainder of the division of the first operand by the second |\n", "\n", "Use the following cell to test the arithmetic operators:\n" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "number = 1 + 2 * 3 / 4.0 - 0.5\n", "print(number)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "> ☝ **Important! Use parentheses to force the order of operations**\n", "> Python will use the order of operations to determine the order in which the operations are performed, so if you want to force the order of operations, please use parentheses.\n" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "number = (1 + 2) * 3 / 4.0 - 0.5\n", "print(number)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "I would like to call your attention on two operators you may not be familiar with. The remainder, or Modulo (```%```) operator returns the integer remainder of the division. Likewise, the integer division operator (//) returns the integer division or true integer division. If we are dealing with integers, the dividend is equal to the result of the integer division multiplied by the divisor, times the integer remainder:\n" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "dividend = 11\n", "divisor = 3\n", "remainder = dividend % divisor\n", "print(\"Remainder of\", dividend, \"divided by\", divisor, \"is\", remainder)\n", "true_division = dividend // divisor\n", "print(\"Integer division is\", true_division)\n", "print(true_division*divisor + remainder)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Extra tips: Hexadecimal and binary numbers\n", "We can use the ```0x``` prefix to define a hexadecimal number, and the ```0b``` prefix to define a binary number. For instance, the hexadecimal number ```0xFF``` is the same as the binary number ```0b11111111```:\n" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "hex_number = 0xFF\n", "print(hex_number)\n", "bin_number = 0b11111111\n", "print(bin_number)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Extra tips: Bitwise binary operators\n", "Python allows to perform bitwise (applied to every bit) operations to integer values. These operators work on the bits representing the number, rather than the number itself. The following table lists the bitwise operators that can be used with numeric variables:\n", "\n", "| Operation | Symbol | Description |\n", "|-------------|---------|--------------------------------------------------------------|\n", "| Bitwise AND | ```&``` | Returns 1 bitwise if the bits of both operands are 1. |\n", "| Bitwise OR | ```|``` | Returns 1 bitwise if at least one of the bits of both operands is 1. |\n", "| Bitwise XOR | ```^``` | Returns 1 bitwise if the bits of both operands are different. |\n", "| Bitwise NOT | ```~``` | Returns the complement of the bits of the operand. |\n", "| Bitwise Left Shift | ```<<``` | Shifts the bits of the operand to the left. |\n", "| Bitwise Right Shift | ```>>``` | Shifts the bits of the operand to the right. |\n", "\n" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "a = 0b10\n", "b = 0b11\n", "print(a & b)\n", "print(a | b)\n", "print(a ^ b)\n", "print(a << 2)\n", "print(a >> 2)\n", "print(~a)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Numeric cheatsheet\n", "The following image shows a cheatsheet for numeric types in Python:\n", "![Numeric cheatsheet](img/numeric_variables_cheat_sheet.png)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "\n", "### String (text) type\n", "\n", "Text is stored in variables of type `string`. To define a text variable, just enclose the text in single quotes `('...')` or double quotes `(\"...\")`:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "s = 'one string'\n", "print(s)\n", "print(\"The type is\", type(s))\n", "s = \"another string\"\n", "print(s)\n", "s = \"Don't worry about quotes\"\n", "print(s)\n" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Special characters\n", "Ok, so now we know that we need to enclose the text in single and double quotes, but what if what if we want to store a string that contains quotes? Quotes are not allowed inside a string, and in that sense, they are considered a **special character**. To deal with this, we can use the escape character (```\\```) to escape the quote we want to include in our string:\n", "\n" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "s = \"This is a \\\"special\\\" string\"\n", "print(s)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "There are other special characters that can be used in strings.\n", "Special characters can be escaped with `\\`. Find below some examples of special characters:\n", "\n", "- ```\\n```: new line\n", "- ```\\t```: tab space\n", "- ```\\N{name}```: [Unicode character](https://unicode.org/charts/charindex.html) by character name eg (\\N{ALIEN})\n", "- ```\\uhhhh```: Unicode character encoding (base 16) eg (\\u1F47E)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "### Built-in functions and string variables\n", "For now, we only want to highlight the **built-in** function `len` returns the length of a string:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "text = \"Hello world!\"\n", "print(len(text))" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Built-in String type constructor\n", "The function str() can be used to create string variables. It takes any numeric value as parameter, so it can be used to convert any value to a string:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "complex_var = 2.5 + 5j\n", "compex_var_str = str(complex_var_3)\n", "print(compex_var_str)\n", "print(type(compex_var_str))\n" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### String type built-in methods and attributes\n", "String variables have many useful built-in methods to manipulate strings. You can read their description in the [docs](https://docs.python.org/3/library/stdtypes.html#str), but let´s highlight here some outstanding examples:\n", "\n", "- **upper()**: Converts all characters to uppercase (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.upper]\n", "- **lower()**: Converts all characters to lowercase (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.lower]\n", "- **capitalize()**: Converts the first character to uppercase and the rest to lowercase (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.capitalize]\n", "- **title()**: Converts the first character of each word to uppercase and the rest to lowercase (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.title]\n", "- **strip()**: Removes leading and trailing whitespace (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.strip]\n", "- **replace()**: Replaces a substring with another (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.replace]\n", "- **split()**: Splits a string into a list of substrings (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.split]\n", "- **join()**: Joins a list of strings into a single string (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.join]\n", "- **find()**: Finds the first occurrence of a substring (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.find]\n", "- **count()**: Counts the number of occurrences of a substring (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.count]\n", "- **startswith()**: Checks if a string starts with a given substring (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.startswith]\n", "- **endswith()**: Checks if a string ends with a given substring (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.endswith]\n", "- **isalpha()**: Checks if a string is composed only of alphabetic characters (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.isalpha]\n", "- **isdigit()**: Checks if a string is composed only of digits (see the docs)[https://docs.python.org/3/library/stdtypes.html#str.isdigit]\n", "\n", "- `index` Finds the first occurrence of a character in a string\n", "- `count` Returns the number of occurrences of a character in a string\n", "- `upper`, `lower`, `capitalize` Transform strings to to UPPERCASE, lowercase, or capitalize the first letter of the string.\n", "- `startswith`, `endswith` Checks if a string starts with a certain substring or ends with a certain substring.\n", "- `replace` Replaces all occurrences of a substring in a string with another substring.\n", "- `find`, `rfind` Finds the first occurrence of a substring in a string. Same as index, but with multiple characters.\n" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "my_string = \"Hello world!\"\n", "# Find the index of the first occurrence of the letter \"o\" in the string\n", "print(my_string.index(\"o\"))\n", "\n", "# Count how many letters \"l\" are in the string\n", "print(my_string.count('l'))\n", "\n", "my_string = \"this is a string\"\n", "# To upper case\n", "print(my_string.upper())\n", "\n", "# To lower case\n", "print(my_string.lower())\n", "\n", "# Or capitalize the first character of the string\n", "print(my_string.capitalize())\n", "\n", "\n", "# check if the string ends with the specified suffix\n", "print(my_string.endswith(\"!\"))\n", "\n", "# Return a copy of the string with the specified substring replaced\n", "print(my_string.replace(\"world\", \"Thomas\"))\n" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "The format method is a very useful method to work with template strings. It can take an arbitrary number of input parameters and returns a string with the values of its parameters formatted according to the template [string format](https://docs.python.org/3/library/string.html#formatstrings):" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": 1, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "my_var is: 1, my_second_var is: 2, my_third_var is: 3\n", "my_var is: 1, my_second_var is: 2, my_third_var is: 3\n", "my_var is 1, and my_second_var is 2\n", "my_var is 2, and my_second_var is 1\n", "int: 42; hex: 2a; oct: 52; bin: 101010\n", "one decimal: 3.1, three decimals: 3.142\n", "The ratio is 85.71%\n", "The imaginary part is -2.2\n" ] } ], "source": [ "# format allows to insert the values of variables in a string using {}\n", "my_var = 1\n", "my_second_var = 2\n", "my_third_var = 3\n", "\n", "print('my_var is: {}, my_second_var is: {}, my_third_var is: {}'.format(my_var, my_second_var, my_third_var))\n", "\n", "# You can access the parameters by position using their index\n", "\n", "print('my_var is: {0}, my_second_var is: {1}, my_third_var is: {2}'.format(my_var, my_second_var, my_third_var))\n", "\n", "print(\"my_var is {1}, and my_second_var is {0}\".format(my_second_var, my_var))\n", "\n", "# You can also use names for the parameters:\n", "\n", "print(\"my_var is {first}, and my_second_var is {latest}\".format(first=my_second_var, latest=my_var))\n", "\n", "# format also supports different number formats (:d) decimal, :x hexadeximal, :o octal, :b binary:\n", "print(\"int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}\".format(42))\n", "\n", "# float numbers use the :f format. You can specify the number of decimals to show:\n", "print(\"one decimal: {0:.1f}, three decimals: {0:.3f}\".format(3.141516))\n", "\n", "# You can also represent percentages with format:\n", "\n", "print(\"The ratio is {0:.2%}\".format(6.0/7.0))\n", "\n", "# You can access the attributes of parameters:\n", "\n", "print(\"The imaginary part is {0.imag:.2}\".format(2.135-2.167j))" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Formatted strings\n", "Now, with formatted strings, you can use the `f` prefix to create a string with the values of variables formatted according to the same template format [string format](https://docs.python.org/3/library/string.html#formatstrings) as above, but taking the values of the variables directly from the context:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": 2, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "my_var is: 1, my_second_var is: 2, my_third_var is: 3\n", "int: 42; hex: 2a; oct: 52; bin: 101010\n", "one decimal: 3.1, three decimals: 3.142\n", "The ratio is 85.71%\n", "The imaginary part is -2.2\n" ] } ], "source": [ "my_var = 1\n", "my_second_var = 2\n", "my_third_var = 3\n", "\n", "print(f'my_var is: {my_var}, my_second_var is: {my_second_var}, my_third_var is: {my_third_var}')\n", "\n", "# format also supports different number formats (:d) decimal, :x hexadeximal, :o octal, :b binary:\n", "int_num = 42\n", "print(f\"int: {int_num:d}; hex: {int_num:x}; oct: {int_num:o}; bin: {int_num:b}\")\n", "\n", "# float numbers use the :f format. You can specify the number of decimals to show:\n", "float_num = 3.141516\n", "print(f\"one decimal: {float_num:.1f}, three decimals: {float_num:.3f}\")\n", "\n", "# You can also represent percentages with format:\n", "percent_num = 6.0/7.0\n", "print(f\"The ratio is {percent_num:.2%}\")\n", "\n", "# You can access the attributes of parameters:\n", "complex_num = 2.135-2.167j\n", "print(f\"The imaginary part is {complex_num.imag:.2}\")" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "Note that up to this point, we used the ```print``` function passing different values, but we can also use the ```format``` function to gain control and make our strings more readable.\n", "\n", "#### Basic arithmetic operations with strings\n", "The addition (+) operator is used to concatenate strings. It is also possible to use the multiplication operator with a string and an integer operand to repeat a string a number of times:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "helloworld = \"hello\" + \" \" + \"world\"\n", "print(helloworld)\n", "\n", "lotsofhellos = \"hello\" * 10\n", "print(lotsofhellos)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### String cheatsheet\n", "This cheatsheet contains a summary of the most important string operations in Python.\n", "\n", "![String cheatsheet](img/string_variables_cheat_sheet.png)\n", "\n", "### Boolean type\n", "Boolean variables are used to store the values True or False, and they are quite useful to build the logic of our programs. The type of a boolean variable is `bool` and it defines if something is `True` or `False`." ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "right = True\n", "print(right)\n", "print(type(right))\n", "\n", "wrong = False\n", "print(wrong)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Logical operators\n", "In the example above, it makes no practical sense to assign the value True to a variable, but rather to use logic to determine if a condition is met. In practice, we may assign some initial value to a boolean variable, and then we will use **Logical operators** to determine if different conditions are met and control the logic of our program. In short, logical operators are operators that either return boolean values or use boolean variables as operators. Logical operators are:\n", "\n", "| Operator | Symbol | Description |\n", "|-------------------------------|--------------------------|------------------------------------------------------------------------------------------------------|\n", "| `and` | `a & b` | Returns `True` if both operands (boolean variables a and b) are `True` |\n", "| `or` | a | b | Returns `True` if at least one of the operands (boolean variables a and b) is `True` |\n", "| `not` | `!a` | Returns `True` if the operand (boolean variable a) is `False` |\n", "| `xor` | `a ^ b` | Returns `True` if exactly one of the operands (boolean variables a and b) is `True` |\n", "\n", "\n", "#### Comparison operators\n", "Comparison operators are used to compare two values and return a boolean value depending on the result of the comparison. Comparison operators are:\n", "\n", "| Operator | Symbol | Description |\n", "|-------------------------------|--------------------------|------------------------------------------------------------------------------------------------------|\n", "| Greater than `>` | `a > b` | Returns `True` if the numeric operand a is greater than the numeric operand b |\n", "| Equal to `==` | `a == b` | Returns `True` if the numeric operand a is equal to the numeric operand b |\n", "| Greater than or equal to `>=` | `a >= b` | Returns `True` if the numeric operand a is greater than or equal to the numeric operand b |\n", "| Less than or equal to `<=` | `a <= b` | Returns `True` if the numeric operand a is less than or equal to the numeric operand b |\n", "| Less than `<` | `a < b` | Returns `True` if the numeric operand a is less than the numeric operand b |\n", "\n", "#### Boolean cheatsheet\n", "This cheatsheet contains a summary of the main features of boolean variables you should be aware of.\n", "\n", "![Boolean cheatsheet](img/boolean_variables_cheat_sheet.png)\n" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "### None type\n", "\n", "None is a special variable which is totally void, null or empty:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "var = None\n", "\n", "print(var)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "## Extra tips\n", "### Multiple assignment\n", "We can define more than one variable in a single statement:\n" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "x, y = 50, 100\n", "print(x, y)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "### Ternary assignment\n", "Also, Python implements a **ternary** operator that allows to assign the value of the variable depending on a condition:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "turn_right = True\n", "next_turn = \"right\" if turn_right else \"left\"\n", "print(next_turn)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "### How variables work in Python\n", "You probably are wondering how the magic happens, how variables work in Python, how does Python manage internally the variables that you create in your code. The key concept here is that Python manages variables as references to objects. When you declare a variable and assign a value to it using the following happens:\n", "\n", "- Python creates a data structure called [base structure](https://docs.python.org/3/c-api/structures.html) where it will store the information of your variable.\n", "- It sets the type field of the base structure to the type of your variable\n", "- It sets the value field of the base structure to the value of your variable\n", "- It creates the name of the variable in the **symbol table**. You can think of this table as a structure that maps the name of the variable to the base structure.\n", "- It creates a reference to the base structure.\n", "- It increases the reference counter of the base structure in 1. This counter will keep track of how many variables point to the same base structure\n", "\n", "\n", "![variables in python](img/variables_in_python.PNG)\n", "\n", "#### Id function and is operator\n", "The ```id``` function returns the memory address of the reference structure object of your variable. You can use this function to compare two variables and see if they are pointing to the same object. The ```is``` operator is used to compare two variables and returns `True` if they are pointing to the same object.\n", "\n", "Let´s see them in action to better understand how Python manages variable internally:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "my_first_variable = 23\n", "my_second_variable = my_first_variable\n", "\n", "print(\"The value of my first variable is:\")\n", "print(my_first_variable)\n", "print(\"Its memory address is:\")\n", "print(id(my_first_variable))\n", "\n", "print(\"An the value of my second variable is:\")\n", "print(my_second_variable)\n", "print(\"Its memory address is:\")\n", "print(id(my_second_variable))\n", "\n", "print(\"Do both variables share the same memory address?\")\n", "print(my_first_variable is my_second_variable)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "We do not have the same behavior when we assign two variables the same value:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "my_first_variable = 1000\n", "my_second_variable = 1000\n", "\n", "print(\"The value of my first variable is:\")\n", "print(my_first_variable)\n", "print(\"Its memory address is:\")\n", "print(id(my_first_variable))\n", "\n", "print(\"An the value of my second variable is:\")\n", "print(my_second_variable)\n", "print(\"Its memory address is:\")\n", "print(id(my_second_variable))\n", "\n", "print(\"Do both variables share the same memory address?\")\n", "print(my_first_variable is my_second_variable)" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Built-in getrefcount function\n", "The built-in function ```sys.getrefcount``` returns the number of references to the variable that is passed as argument to the function, for intance:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [ "import sys\n", "x = 1.0\n", "print(sys.getrefcount(x))\n", "y = x\n", "print(sys.getrefcount(x))\n", "\n", "z = object()\n", "print(sys.getrefcount(z))" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "Note that the result of getrefcount is always higher than expected because the function creates internally another reference. Note that the reference count for ```x``` is 3. This is because, when we assign a value to a variable, Python creates another object for that value, and all variables that are assigned the value reference the same memory address. So the reference count for ```x``` is 1 plus 1 for the reference of this internal object plus 1 of the getrefcount internal reference. Note that we did not assign an initial value to ```z```, but instead, we initialise it with the construction function ```object``` which creates a base object. For this variable, the reference count is 2 because Python does not create another object for the value, since it is not provided in the assignment statement." ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Immutable types\n", "\n", "In Python, most primitive types are **immutable**. This means that whenever we make changes to a variable, Python does not actually change the value stored in the memory address, it rather creates a new base structure at another memory address and assigns the new value:" ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": 29, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "the memory address of another variable is:\n", "140718223313376\n", "the memory address of another variable now is:\n", "140718223313408\n" ] } ], "source": [ "another_variable = 27\n", "print(\"the memory address of another variable is:\")\n", "print(id(another_variable))\n", "another_variable = another_variable + 1\n", "print(\"the memory address of another variable now is:\")\n", "print(id(another_variable))" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "#### Garbage Collector\n", "A process called [garbage collector](https://devguide.python.org/garbage_collector/) keeps track of the references to memory addresses and makes sure that unused memory (memory addresses to which no active variable is pointing) can be used again by any other process. It is important to bear in mind that although this process is transparent for developers, the performance of our code is going to depend on the way we manage variable assignments!" ], "metadata": { "collapsed": false } } ], "metadata": { "kernelspec": { "name": "python3", "display_name": "Python 2.7.15 64-bit (system)" }, "language_info": { "mimetype": "text/x-python", "nbconvert_exporter": "python", "name": "python", "pygments_lexer": "ipython2", "version": "2.7.15", "file_extension": ".py", "codemirror_mode": { "version": 2, "name": "ipython" } }, "pycharm": { "stem_cell": { "cell_type": "raw", "source": [], "metadata": { "collapsed": false } } }, "interpreter": { "hash": "3addd268b25661c1802571d40421a498472f412d745e7161ee2cc01d8b4a0718" } }, "nbformat": 4, "nbformat_minor": 4 }