{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "l02-c000",
   "metadata": {},
   "source": [
    "# Lecture 2 - Strings and numbers\n",
    "\n",
    "<!-- <a rel=\"license\" href=\"https://creativecommons.org/licenses/by/4.0/\" target=\"_blank\"><img alt=\"Creative Commons Licence\" style=\"border-width:0\" src=\"https://licensebuttons.net/l/by/4.0/88x31.png\" title=\"This work is licensed under a Creative Commons Attribution 4.0 International License.\" align=\"right\"/></a> -->\n",
    "\n",
    "**Authors:** Fiona McNeill, Matteo Degiacomi, Rayo Verweij, and Nigel Topham\n",
    "\n",
    "## Introduction\n",
    "\n",
    "In this notebook we will look more closely at the values our programs work with. You have already stored and printed a few values; now we will slow down and see how strings, whole numbers, and decimal numbers behave differently.\n",
    "\n",
    "### Learning outcomes\n",
    "\n",
    "In this notebook, we'll discuss:\n",
    "\n",
    "- distinguishing `int`, `float`, and `str` values and inspecting them with `type()`\n",
    "- converting user input with `int()`, `float()`, and `str()`\n",
    "- using floor division, remainder, exponentiation, and compound assignment\n",
    "- combining and indexing strings and producing readable output with f-strings\n",
    "- diagnosing common type and conversion errors\n",
    "\n",
    "### Using the notebook\n",
    "\n",
    "Remember, this notebook is _yours_! You can edit each cell, for example by adding new examples or changing values to see what happens. Feel free to experiment!\n",
    "\n",
    "A common approach for learning how to read and write code in a structured way is called **PRIMM**:\n",
    "1. **Predict**: before running the code, look at it - do you understand each line? What do you think will happen?\n",
    "2. **Run**: now run the code and see what output you get.\n",
    "3. **Investigate**: did it go as you thought it would? If not, can you figure out why?\n",
    "4. **Modify**: now change the code and once again try to predict the output. If you got it wrong the first time, did you get it right now?\n",
    "5. **Make**: finally, try to write your own program from scratch using the skills you learned.\n",
    "\n",
    "You can apply steps 1-4 to each code cell in the notebook and many will have prediction prompts to help you get started. In addition, there will be challenges that ask you to put everything together yourself and execute step 5. There will often be multiple ways to solve these, but each challenge has a potential answer listed.\n",
    "\n",
    "### Navigating the notebook\n",
    "\n",
    "A Jupyter notebook can be operated with your keyboard. Here is a **cheat sheet**:\n",
    "- To run the currently highlighted cell and move focus to the next cell, hold <kbd>&#x21E7; Shift</kbd> and press <kbd>&#x23ce; Enter</kbd>;\n",
    "- To run the currently highlighted cell and keep focus in the same cell, hold <kbd>&#x21E7; Ctrl</kbd> and press <kbd>&#x23ce; Enter</kbd>;\n",
    "- To create a cell under the one currently highlighted, press <kbd>B</kbd>;\n",
    "- To delete the currently highlighted cell, press <kbd>X</kbd> (be careful with this one!);\n",
    "- To get help for a specific function, place the cursor within the function's brackets, hold <kbd>&#x21E7; Shift</kbd>, and press <kbd>&#x21E5; Tab</kbd>.\n",
    "\n",
    "Watch out: **code cells remember what happened in cells before**. So, especially in the more complicated notebooks later down the line, make sure to always run **every** cell from top to bottom, as one might rely on a piece of code that came before it!\n",
    "\n",
    "### Further reading\n",
    "\n",
    "- [Python: numbers](https://docs.python.org/3/tutorial/introduction.html#numbers)\n",
    "- [Python: text](https://docs.python.org/3/tutorial/introduction.html#text)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f15262ae",
   "metadata": {},
   "source": [
    "## 1. Values have types"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c001",
   "metadata": {},
   "source": [
    "Every value has a **type**. In this notebook, we will discuss three of them:\n",
    "\n",
    "- **Integers** (`int`): whole numbers such as `7` and `-2`\n",
    "- **Floats** (`float`): numbers with a fractional part such as `7.5`\n",
    "- **Strings** (`str`): text such as `\"7\"` and `\"Leith\"`\n",
    "\n",
    "The `type()` function will tell you what type a particular value is.\n",
    "\n",
    "**Predict:** Which type will each call display? What is the difference to writing a number with and without quotation marks?\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c002",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(type(7))\n",
    "print(type(7.0))\n",
    "print(type(\"7\"))\n",
    "\n",
    "temperature = 14.5\n",
    "location = \"Edinburgh\"\n",
    "print(type(temperature), type(location))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c003",
   "metadata": {},
   "source": [
    "The output of `type()` always looks something like `<class 'type'>`. A **class** is the specification of a type; for example, the `str` class in the Python source code defines everything that you can do with objects of the `str` type. In lecture 7, we'll discuss how you can create your own classes!\n",
    "\n",
    "For now, though, just remember that you can always use `type()` to check what something is."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "924fd4bb",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(type(print))\n",
    "print(type(str))\n",
    "print(type(int))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "95b19633",
   "metadata": {},
   "source": [
    "As you can see, **everything in Python has a type**. `print()` is a built-in function; nothing much more to say about that. `str` and `int`, as discussed, are types.\n",
    "For now, though, we'll just focus on strings, integers, and floats."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4f0dea4-c97a-424e-86ba-3dccb8cdbcf2",
   "metadata": {},
   "source": [
    "### Operators across types\n",
    "\n",
    "What **operators** do depends on the types of their **operands**, the values they are operating on.\n",
    "\n",
    "In lecture 1, we discussed the operators `+`, `-`, `*`, and `/`. When their operands are *integers* or *floats*, they function how you would expect them to when performing arithmetic.\n",
    "\n",
    "However, when they are used with *strings*, they have a completely different function!\n",
    "\n",
    "Let's start with the `+` operator."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c004",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(1 + 2)\n",
    "print(\"Edin\" + \"burgh\")\n",
    "print(\"1\" + \"2\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f32fa49d",
   "metadata": {},
   "source": [
    "**String concatenation** is the process of merging strings together. In Python, `+` is both the numerical addition *and* string concatenation operator.\n",
    "\n",
    "**Predict:** What happens if you use `+` with two different operand types?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "328f7552",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"2\" + 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c005",
   "metadata": {},
   "source": [
    "As you can see, Python raises a `TypeError`: it cannot guess whether you meant numeric addition or text concatenation.\n",
    "\n",
    "A `TypeError` is a type of error that tells you about erroneous types. Jokes aside, Python error messages are usually **quite descriptive**: in this case, it literally tells us `can only concatenate str (not \"int\") to str`. Fully spelled out: we tried to concatenate an integer to a string, which is not allowed, as we can only concatenate two strings together.\n",
    "\n",
    "**Predict:** What do you think the error message would say if we tried it the other way around?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "99dfe075",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(2 + \"3\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7528a528",
   "metadata": {},
   "source": [
    "We still get a `TypeError` but this time a slightly more generic one, as it simply tells us we cannot use a string and an integer together as operands for the `+` operator.\n",
    "\n",
    "***When you get an error in your code, always make sure to carefully read the message first!*** Errors are very useful things: they usually tell you exactly where you made what mistake. We will talk more about error types throughout the course.\n",
    "\n",
    "Next, let's try `*`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9082ee52",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(4 * 3)\n",
    "print(\"4\" * 3)\n",
    "print(2 * \"5\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ee42707",
   "metadata": {},
   "source": [
    "`*` works slightly differently: when used only on numbers, it is the numerical multiplication operator, but when used on a string and an integer, it repeats the string instead.\n",
    "\n",
    "**Predict:** What happens when you use `*` on two strings?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8c284189",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"4\" * \"3\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c006",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "source": [
    "Once again, a `TypeError`. The grammar in the error message is a bit odd, but carefully parsing it tells us that we cannot multiply a `str` by anything other than an `int`.\n",
    "\n",
    "The `-` and `/` operators cannot be used with strings at all.\n",
    "\n",
    "<div class=\"alert alert-success\">\n",
    "<b>Try it yourself: summarising valid combinations of operators</b>\n",
    "\n",
    "Let's create a program that prints a neat summary of the operators we have discussed so far. Replace each `?` in the table with what the operator does for each combination of operands, or whether Python throws a `TypeError`. Two fields have already been filled out for you to get started.\n",
    "\n",
    "If you're not sure about particular combinations, edit one of the code cells to try it out!\n",
    "</div>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c007",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "print(\"| Operator / Type combo |       int & int       |       int & str       |       str & str       |\")\n",
    "print(\"-------------------------------------------------------------------------------------------------\")\n",
    "print(\"|           +           |        Addition       |           ?           |           ?           |\")\n",
    "print(\"|           -           |           ?           |       TypeError       |           ?           |\")\n",
    "print(\"|           *           |           ?           |           ?           |           ?           |\")\n",
    "print(\"|           /           |           ?           |           ?           |           ?           |\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c008",
   "metadata": {
    "tags": [
     "solution"
    ]
   },
   "source": [
    "<details>\n",
    "<summary><b>Click for the solution</b></summary>\n",
    "\n",
    "```python\n",
    "print(\"| Operator / Type combo |       int & int       |       int & str       |       str & str       |\")\n",
    "print(\"-------------------------------------------------------------------------------------------------\")\n",
    "print(\"|           +           |        Addition       |       TypeError       |     Concatenation     |\")\n",
    "print(\"|           -           |      Subtraction      |       TypeError       |       TypeError       |\")\n",
    "print(\"|           *           |     Multiplication    |     Repeat string     |       TypeError       |\")\n",
    "print(\"|           /           |        Division       |       TypeError       |       TypeError       |\")\n",
    "```\n",
    "</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13ed87bc",
   "metadata": {},
   "source": [
    "## 2. More operators"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c009",
   "metadata": {},
   "source": [
    "Let's stay within the realm of numbers for a bit. Alongside `+`, `-`, `*`, and `/`, Python provides:\n",
    "\n",
    "- **Floor division** `//`: the whole-number quotient, rounded down\n",
    "- **Remainder** `%`: what remains after floor division\n",
    "- **Exponentiation** `**`: raise a value to a power\n",
    "\n",
    "**Predict:** Work out all four results before running the cell.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c010",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(17 / 5)    # Ordinary division\n",
    "print(17 // 5)   # How many 'complete groups' of 5 fit in 17?\n",
    "print(17 % 5)    # How much is left over after fitting 'complete groups' of 5 into 17?\n",
    "print(2 ** 5)    # 2 multiplied by itself 5 times"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "580f6a5d",
   "metadata": {},
   "source": [
    "Remember, *integers* refer to whole numbers, whereas *floats* refer to fractional numbers.\n",
    "\n",
    "**Predict:** What is going to be the type of the result of each expression?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4d95982d",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(type(17 / 5))\n",
    "print(type(17 // 5))\n",
    "print(type(17 % 5))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c011",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\">\n",
    "<b>Note: two types for numbers</b>\n",
    "\n",
    "You might wonder: why does Python need two types for numbers, actually? One of the main reasons is **speed**. For computers, it is a lot faster to do maths with integers than it is for floats. Secondly, there is the reason of **accuracy**, which we will return to in a later lecture.\n",
    "\n",
    "As far as programming languages go, Python is actually quite streamlined: for example, the Java programming language has no less than *six* types of numbers! \n",
    "</div>\n",
    "\n",
    "Floor division and remainder are often combined to break a number up into smaller units. For example, if we'd like to format 135 minutes into a standard time format, `135 // 60` gives complete hours and `135 % 60` gives remaining minutes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c012",
   "metadata": {},
   "outputs": [],
   "source": [
    "total_minutes = 135\n",
    "hours = total_minutes // 60\n",
    "minutes = total_minutes % 60\n",
    "print(hours, \":\", minutes)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c013",
   "metadata": {},
   "source": [
    "### Compound assignment\n",
    "\n",
    "So far, we've seen the *assignment operator*, `=`, as well as *arithmetic operators*. For an easy way to update variables, Python actually allows us to **combine them**!\n",
    "\n",
    "A **compound assignment** updates a variable using its existing value:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1a5ae902",
   "metadata": {},
   "outputs": [],
   "source": [
    "cakes = 5\n",
    "print(cakes)\n",
    "cakes = cakes + 2\n",
    "print(cakes)\n",
    "cakes += 2\n",
    "print(cakes)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1fa446e8",
   "metadata": {},
   "source": [
    "As you can see, `cakes += 2` is shorthand for `cakes = cakes + 2`. The forms `-=`, `*=`, `/=`, `//=`, `%=`, and `**=` follow the same pattern.\n",
    "\n",
    "**Predict:** What is going to be the final value of `score`?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c014",
   "metadata": {},
   "outputs": [],
   "source": [
    "score = 10\n",
    "score -= 3\n",
    "score *= 2\n",
    "print(score)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c015",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "source": [
    "<div class=\"alert alert-success\">\n",
    "<b>Try it yourself: split a quantity</b>\n",
    "\n",
    "You are organising an event for 94 participants but rooms only hold 20. Calculate the number of full rooms you'll need and how many will be left over for the overflow room.\n",
    "\n",
    "Then, increase `participants` by 7 using compound assignment and calculate again.\n",
    "</div>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c016",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "participants = 94\n",
    "room_size = 20\n",
    "# Calculate and print the quotient and remainder\n",
    "\n",
    "# Update participants, then calculate again\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c017",
   "metadata": {
    "tags": [
     "solution"
    ]
   },
   "source": [
    "<details>\n",
    "<summary><b>Click for a possible solution</b></summary>\n",
    "\n",
    "```python\n",
    "participants = 94\n",
    "room_size = 20\n",
    "print(\"Full rooms:\", participants // room_size, \"- and in the overflow room:\", participants % room_size)\n",
    "\n",
    "participants += 7\n",
    "print(\"Full rooms:\", participants // room_size, \"- and in the overflow room:\", participants % room_size)\n",
    "```\n",
    "</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "128e4d42",
   "metadata": {},
   "source": [
    "## 3. Type conversion"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c018",
   "metadata": {},
   "source": [
    "`input()` always returns a string, even when the user types digits. However, sometimes we want to be able to get numerical data instead!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5d7ea7e9",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Welcome to the great halving machine!\")\n",
    "fav_number = input(\"Please enter your favourite number: \")\n",
    "print(fav_number / 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e704059c",
   "metadata": {},
   "source": [
    "Thankfully, Python gives us easy ways to **convert** between types, using functions based on the type names. Where possible,\n",
    "* `int()` converts something to a whole number;\n",
    "* `float()` to a decimal number; and\n",
    "* `str()` to a string."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c019",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Converting a string to an integer\n",
    "text = \"24\"\n",
    "print(text + \"1\")\n",
    "number = int(text)\n",
    "print(number + 1)\n",
    "\n",
    "# Converting a string to a float\n",
    "price_string = \"3.50\"\n",
    "print(price_string * 2)\n",
    "price = float(price_string)\n",
    "print(price * 2)\n",
    "\n",
    "# Converting an integer to a string\n",
    "label = \"Room \" + str(4)\n",
    "print(label)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3638dab2-3462-4be0-88a1-3f2ac29ed759",
   "metadata": {},
   "source": [
    "Converting `float` to `int` is possible, but potentially dangerous for your numerical accuracy:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "acc9ee78-75a5-4da0-98fa-5bf064c20c2d",
   "metadata": {},
   "outputs": [],
   "source": [
    "int(4.99)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52b79098-9515-4095-879f-88903c7b9ea7",
   "metadata": {},
   "source": [
    "As you can see, converting `float` to `int` does not round the number to the closest integer. Rather, the integer number is produced by disregarding any decimal present in your float!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c020",
   "metadata": {},
   "source": [
    "Conversions are not always possible! For example, `float(\"four\")` and `int(\"4.5\")` both raise a `ValueError`. When converting strings to numbers, the strings can only contain valid numbers of the type you are converting to.\n",
    "\n",
    "**Predict:** What happens when the following piece of code is run with different types of input?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c021",
   "metadata": {},
   "outputs": [],
   "source": [
    "age_text = input(\"Enter your age in whole years: \")\n",
    "age = int(age_text)\n",
    "age_next_year = age + 1\n",
    "print(\"Next year you will be\", age_next_year)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c022",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "source": [
    "For now, when using `input()`, you'll have to assume that the user will also give you the input in the correct format. In Part 2 of the course, we'll discuss how to handle different types of input within one program.\n",
    "\n",
    "<div class=\"alert alert-success\">\n",
    "<b>Try it yourself: converting kilometres to miles</b>\n",
    "\n",
    "Ask for a journey distance in kilometres, convert it to a float, multiply it by 0.621371, and print the distance in miles.\n",
    "</div>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c023",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "# Enter kilometres and get miles back!\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c024",
   "metadata": {
    "tags": [
     "solution"
    ]
   },
   "source": [
    "<details>\n",
    "<summary><b>Click for a possible solution</b></summary>\n",
    "\n",
    "```python\n",
    "distance_text = input(\"Distance in kilometres: \")\n",
    "distance_km = float(distance_text)\n",
    "distance_miles = distance_km * 0.621371\n",
    "print(\"Distance in miles:\", distance_miles)\n",
    "```\n",
    "</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fff889f7",
   "metadata": {},
   "source": [
    "## 4. Strings and formatted output"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c025",
   "metadata": {},
   "source": [
    "That's enough for numbers for now; let's end by giving strings some attention too.\n",
    "\n",
    "Python has a bunch of built-in methods for **transforming strings**. Some convenient ones are:\n",
    "- `<string>.upper()` converts the string to uppercase characters\n",
    "- `<string>.lower()` converts the string to lowercase characters\n",
    "- `<string>.replace(<old>, <new>)` replaces a part of a string with something else "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c028",
   "metadata": {},
   "outputs": [],
   "source": [
    "city = \"Edinburgh\"\n",
    "print(city.upper())\n",
    "print(city.lower())\n",
    "print(city.replace(\"Edin\", \"Jed\"))\n",
    "print(city)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5940e3ec",
   "metadata": {},
   "source": [
    "Note that these methods do **not** change the string they are called on. Instead, they **return a new string** and leave the original untouched. That is why `city` still holds `\"Edinburgh\"` after all three calls above. If you want to keep a transformed version, you have to assign it to a variable.\n",
    "\n",
    "**Predict:** What is the value of `county` each time it is printed?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d519cd19",
   "metadata": {},
   "outputs": [],
   "source": [
    "county = \"East Lothian\"\n",
    "print(county)\n",
    "\n",
    "county.replace(\"East\", \"West\")\n",
    "print(county)\n",
    "\n",
    "county = county.replace(\"East\", \"West\")\n",
    "print(county)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8f22809-991a-48e6-a795-921cdde92689",
   "metadata": {},
   "source": [
    "There are a lot more methods available to transform strings, have a look [here](https://www.w3schools.com/python/python_ref_string.asp)!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c029",
   "metadata": {},
   "source": [
    "### Formatting output\n",
    "\n",
    "You've already seen how to print multiple things on one line by adding multiple variables and strings to `print()` separated with commas. However, there is another way of doing this.\n",
    "\n",
    "An **f-string** is a string that has an `f` written before the opening quotation marks. Inside of an f-string, expressions inside `{}` are evaluated and inserted into the text. This is called **string interpolation**. This is often easier to read and maintain than using a long chain of commas or conversions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c030",
   "metadata": {},
   "outputs": [],
   "source": [
    "item = \"notebook\"\n",
    "quantity = 3\n",
    "unit_price = 2.5\n",
    "total = quantity * unit_price\n",
    "\n",
    "print(f\"{quantity} {item}s cost £{total}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6fb94425",
   "metadata": {},
   "source": [
    "**Note:** when putting variables in f-strings, you do *not* have to convert a number to a string using `str()`. In this case, Python does it automatically for us.\n",
    "\n",
    "In addition to easily inserting variables, f-strings allow you to add **modifiers** to format them:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a2ac4f18",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(f\"The average price is £{total / quantity:.2f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c031",
   "metadata": {},
   "source": [
    "Here, in `{value:.2f}`, `.2f` formats a number with two digits after the decimal point.\n",
    "\n",
    "Just like the string methods, this just changes the displayed text, not the stored numeric value:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bcf6932a",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(total / quantity)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc235fd7",
   "metadata": {},
   "source": [
    "For a full list of available modifiers, see [Python String Formatting at W3Schools](https://www.w3schools.com/python/python_string_formatting.asp). You do not need to memorise these, just know that they are available for you to use as easy shorthands for formatting text."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c032",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "source": [
    "<div class=\"alert alert-success\">\n",
    "<b>Try it yourself: format a receipt</b>\n",
    "\n",
    "We're buying 2 cans of soup at £3.25 apiece. Calculate the total and print the receipt using an f-string.\n",
    "</div>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-c033",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "item = \"soup\"\n",
    "quantity = 2\n",
    "unit_price = 3.25\n",
    "# Calculate and format the receipt\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-c034",
   "metadata": {
    "tags": [
     "solution"
    ]
   },
   "source": [
    "<details>\n",
    "<summary><b>Click for a possible solution</b></summary>\n",
    "\n",
    "```python\n",
    "item = \"soup\"\n",
    "quantity = 2\n",
    "unit_price = 3.25\n",
    "total = quantity * unit_price\n",
    "print(f\"{quantity} bowls of {item} cost £{total:.2f}\")\n",
    "```\n",
    "</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-consolidation-prompt",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "source": [
    "## Consolidation challenge\n",
    "\n",
    "Let's finish with one more challenge to bring everything together.\n",
    "\n",
    "<div class=\"alert alert-success\">\n",
    "<b>Try it yourself: formatting a duration</b>\n",
    "    \n",
    "Ask for a large number of seconds as a whole number. Convert the input, calculate complete days, hours, minutes, and seconds, and display a sentence such as `200000 seconds is 2 day(s), 7 hour(s), 33 minute(s), and 20 second(s)`.\n",
    "</div>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l02-consolidation-work",
   "metadata": {
    "tags": [
     "exercise"
    ]
   },
   "outputs": [],
   "source": [
    "# your solution here!\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-consolidation-solution",
   "metadata": {
    "tags": [
     "solution"
    ]
   },
   "source": [
    "<details><summary><b>Click for a possible solution</b></summary>\n",
    "\n",
    "```python\n",
    "seconds_text = input(\"Enter a large number of seconds: \")\n",
    "total_seconds = int(seconds_text)\n",
    "\n",
    "# There are 86400 seconds in a day\n",
    "days = total_seconds // 86400\n",
    "days_remainder = total_seconds % 86400\n",
    "\n",
    "# Of the remaining time, find how many full hours fit in\n",
    "hours = days_remainder // 3600 \n",
    "hours_remainder = days_remainder % 3600\n",
    "\n",
    "# Finally, separate our minutes and seconds\n",
    "minutes = hours_remainder // 60 \n",
    "seconds = hours_remainder % 60\n",
    "\n",
    "# Now put it all together in a formatted string\n",
    "# We do not yet have the tools to check whether to write the singular or plural of the unit... but that will come next lecture!\n",
    "print(f\"{total_seconds} seconds is {days} day(s), {hours} hour(s), {minutes} minute(s), and {seconds} second(s)!\")\n",
    "```\n",
    "</details>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l02-consolidation-summary",
   "metadata": {
    "tags": [
     "summary"
    ]
   },
   "source": [
    "## Summary\n",
    "\n",
    "Good job, you now have the fundamentals of variables and types covered and have seen all main arithmetic and assignment operators. In the next two lectures, we'll explore *control flow*, or how to make programs branch and repeat themselves.\n",
    "\n",
    "### Key terms\n",
    "\n",
    "<dl>\n",
    "\t<dt><b>Type</b></dt>\n",
    "\t<dd>The label assigned to values denoting what kind of values they are. Different types have different functionalities attached to them.</dd>\n",
    "\t<dt><b>Type conversion</b></dt>\n",
    "\t<dd>Changing a value from one type to another.</dd>\n",
    "\t<dt><b>Integer</b></dt>\n",
    "\t<dd>A type of value that defines a whole number.</dd>\n",
    "\t<dt><b>Float</b></dt>\n",
    "\t<dd>A type of value that defines a number with fractional parts.</dd>\n",
    "\t<dt><b>String</b></dt>\n",
    "\t<dd>A type of value that defines text.</dd>\n",
    "\t<dt><b>Operator</b></dt>\n",
    "\t<dd>A symbol that performs an action on one or more values (its operands). May perform different actions depending on its operands' types.</dd>\n",
    "\t<dt><b>Operand</b></dt>\n",
    "\t<dd>The values that an operator acts on (e.g. the '2' and '3' in '2 + 3').</dd>\n",
    "\t<dt><b>Compound assignment</b></dt>\n",
    "\t<dd>A single operation that changes a value and updates the name that pointed to the old value to the new one.</dd>\n",
    "\t<dt><b>String concatenation</b></dt>\n",
    "\t<dd>Merging two strings together.</dd>\n",
    "\t<dt><b>String interpolation</b></dt>\n",
    "\t<dd>Evaluating variables and expressions directly inside of a formatted string.</dd>\n",
    "</dl>\n",
    "\n",
    "### New syntax\n",
    "\n",
    "<dl>\n",
    "\t<dt><code>type()</code></dt>\n",
    "\t<dd>Returns what type a value is in the format <code>&lt;class 'type'&gt;</code>.</dd>\n",
    "\t<dt><code>int()</code>, <code>float()</code>, and <code>str()</code></dt>\n",
    "\t<dd>Functions to convert a value to an integer, float, and string, respectively. Only work if their arguments actually <em>can</em> be converted to the new type.</dd>\n",
    "\t<dt><code>+</code> (on strings)</dt>\n",
    "\t<dd>Concatenates strings.</dd>\n",
    "\t<dt><code>*</code> (on a string and an integer <em>n</em>)</dt>\n",
    "\t<dd>Repeats the string <em>n</em> times.</dd>\n",
    "\t<dt><code>//</code></dt>\n",
    "\t<dd>Floor division: divides and rounds down to the nearest integer.</dd>\n",
    "\t<dt><code>%</code></dt>\n",
    "\t<dd>Remainder: returns an integer of how much is 'left over' after floor division.</dd>\n",
    "\t<dt><code>**</code></dt>\n",
    "\t<dd>Exponentiation: raises a number to a power.</dd>\n",
    "\t<dt><code>+=</code>, <code>-=</code>, <code>*=</code>, <code>/=</code>, <code>//=</code>, <code>%=</code>, <code>**=</code></dt>\n",
    "\t<dd>Compound assignment operators: shorthands that change the value by a set amount and update the name to point to the new value in one go.</dd>\n",
    "\t<dt><code>.upper()</code> and <code>.lower()</code></dt>\n",
    "\t<dd>Transform a string to uppercase or lowercase characters, respectively.</dd>\n",
    "\t<dt><code>.replace(old, new)</code></dt>\n",
    "\t<dd>Searches a string and replaces the substring 'old' with 'new'.</dd>\n",
    "\t<dt><code>f'...'</code> and <code>f\"...\"</code></dt>\n",
    "\t<dd>Denotes a formatted string (or f-string). Inside the f-string, variables may be interpolated using <code>{...}</code> and formatted using modifiers.</dd>\n",
    "\t<dt><code>TypeError</code></dt>\n",
    "\t<dd>A type of error that highlights when a function expected a value of a particular type, but received the wrong one.</dd>\n",
    "\t<dt><code>ValueError</code></dt>\n",
    "\t<dd>A type of error that highlights when a value mismatches its assigned type - for example, when attempting to convert a value to an incompatible type.</dd>\n",
    "</dl>\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "559ace4d-7380-4fb7-844a-638a35acc580",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
