diff --git a/00_index.ipynb b/00_index.ipynb index 3ff34ba..db6ddd7 100644 --- a/00_index.ipynb +++ b/00_index.ipynb @@ -7,6 +7,7 @@ "# Introduction\n", "\n", "- [Introduction to the tutorial](./00_intro.ipynb)\n", + "- [A quick tour of Python](./00_python_intro.ipynb)\n", "\n", "# Basic Tutorial\n", "\n", @@ -42,13 +43,6 @@ "\n", "- [Parallelism and concurrency in Python](./14_threads.ipynb)\n" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/00_python_intro.ipynb b/00_python_intro.ipynb new file mode 100644 index 0000000..98195a5 --- /dev/null +++ b/00_python_intro.ipynb @@ -0,0 +1,1447 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# A Quick Tour of Python" + ] + }, + { + "cell_type": "markdown", + "id": "1", + "metadata": {}, + "source": [ + "## Table of Contents\n", + " - [References](#References)\n", + " - [Introduction](#Introduction)\n", + " - [Python Basics for Absolute Beginners](#Python-Basics-for-Absolute-Beginners)\n", + " - [What is code?](#What-is-code?)\n", + " - [Python syntax basics](#Python-syntax-basics)\n", + " - [Indentation: Python's superpower](#Indentation:-Python's-superpower)\n", + " - [Comments: notes to yourself](#Comments:-notes-to-yourself)\n", + " - [Hello, World!](#Hello,-World!)\n", + " - [What is an expression?](#What-is-an-expression?)\n", + " - [What is a string?](#What-is-a-string?)\n", + " - [How Python executes this code](#How-Python-executes-this-code)\n", + " - [Basic datatypes and operations](#Basic-datatypes-and-operations)\n", + " - [Numbers](#Numbers)\n", + " - [Strings](#Strings)\n", + " - [The `type()` function](#The-type()-function)\n", + " - [Dynamic typing](#Dynamic-typing)\n", + " - [Conditional execution](#Conditional-execution)\n", + " - [Loops](#Loops)\n", + " - [The `for` loop](#The-for-loop)\n", + " - [The `while` loop](#The-while-loop)\n", + " - [Functions](#Functions)\n", + " - [Why functions?](#Why-functions?)\n", + " - [A first example](#A-first-example)\n", + " - [Parameters and Arguments](#Parameters-and-Arguments)\n", + " - [Defining a function](#Defining-a-function)\n", + " - [The function body](#The-function-body)\n", + " - [Calling a function](#Calling-a-function)\n", + " - [`return` vs `print`](#return-vs-print)\n", + " - [Type hints (optional but helpful)](#Type-hints-(optional-but-helpful))\n", + " - [Docstrings: special comments for functions](#Docstrings:-special-comments-for-functions)\n", + " - [Putting it all together: A complete example](#Putting-it-all-together:-A-complete-example)\n", + " - [What's next?](#What's-next?)" + ] + }, + { + "cell_type": "markdown", + "id": "2", + "metadata": {}, + "source": [ + "## References\n", + "\n", + "From the official documentation:\n", + "* [Beginner's Guide to Python](https://wiki.python.org/moin/BeginnersGuide)\n", + "* [Python for New Programmers](https://wiki.python.org/moin/BeginnersGuide/NonProgrammers)\n", + "* [Python for Programmers](https://wiki.python.org/moin/BeginnersGuide/Programmers)\n", + "* [The Python Language Reference](https://docs.python.org/3/reference/index.html)\n", + "* [Python Programming FAQ](https://docs.python.org/3/faq/programming.html)\n", + "\n", + "Other:\n", + "* [Python For Everybody](https://www.py4e.com/lessons)" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "## Introduction\n", + "\n", + "Welcome! 🐍\n", + "\n", + "This notebook provides a gentle introduction to the fundamental concepts of Python programming. \n", + "\n", + "Python is a high-level, interpreted programming language known for its clean syntax and readability.\n", + "In this tour, we will explore the core building blocks that make Python so popular.\n", + "\n", + "Each section introduces a concept with simple examples.\n", + "For deeper coverage of any topic, we provide links to the detailed notebooks that we will cover during the course of this training.\n", + "\n", + "Let's begin!" + ] + }, + { + "cell_type": "markdown", + "id": "4", + "metadata": {}, + "source": [ + "## Python Basics for Absolute Beginners\n", + "\n", + "If you have never programmed before, welcome!\n", + "This section will help you understand the fundamental building blocks of Python code." + ] + }, + { + "cell_type": "markdown", + "id": "5", + "metadata": {}, + "source": [ + "### What is code?\n", + "\n", + "**Code** is simply a set of instructions that tells a computer what to do.\n", + "When you write Python code, you are writing instructions in a language that humans can read and computers can execute.\n", + "\n", + "Think of it like a recipe:\n", + "- A recipe has steps written in a human language\n", + "- Code has steps written in a programming language (Python, in our case)\n", + "- Just as a chef follows a recipe, the computer follows your code\n", + "\n", + "The computer reads your Python code and performs the actions you have specified, one instruction at a time." + ] + }, + { + "cell_type": "markdown", + "id": "6", + "metadata": {}, + "source": [ + "### Python syntax basics\n", + "\n", + "**Syntax** refers to the rules for how code must be written.\n", + "Just like any natural language, programming languages have syntax rules too.\n", + "\n", + "Here are some basic Python syntax rules:\n", + "\n", + "#### 1. Statements and lines\n", + "\n", + "Most Python code is written as **statements**, meaning individual instructions that do something.\n", + "Each statement is typically written on a new line:\n", + "\n", + "```python\n", + "x = 5\n", + "y = 10\n", + "z = x + y\n", + "```\n", + "\n", + "Each line above is a separate statement." + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "#### 2. Variables\n", + "\n", + "You might have noticed that in the example above we used `x`, `y`, and `z`.\n", + "These are **variables**.\n", + "Variable names can use any alphanumeric character (letters and numbers) and underscore, but they **cannot** start with numbers.\n", + "\n", + "It is a good practice to choose variable names that describe what they are used for.\n", + "Try to avoid placeholders, or generic names such as `x`, `y`, `my_variable`, or `func`.\n", + "\n", + "Examples:\n", + "\n", + "- `gamma_factor` is **valid**\n", + "- `_planck_constant` is **valid**\n", + "- `epsilon_0` is **valid**\n", + "- `1_item` is **not** valid (because it starts with a number)\n", + "\n", + "A **variable** is like a label you can assign to an object.\n", + "Think of it as giving a name to a value so you can refer to it later.\n", + "\n", + "```python\n", + "x = 5 # Create a variable named 'x' and assign the number 5 to it\n", + "name = \"Alice\" # Create a variable named 'name' and assign the text \"Alice\" to it\n", + "```\n", + "\n", + "The `=` symbol is called the **assignment operator**.\n", + "Note that it does not mean \"equals\" like in math. \n", + "It means \"store the value on the right into the variable on the left.\"\n", + "\n", + "Variables are useful because they allow you to:\n", + "- **Reuse** the same value multiple times\n", + "- **Change** the value later if needed\n", + "- Make your code more **readable** (using `name` instead of just `Alice`)\n", + "\n", + "This \"assignment\" (binding names to objects) also happens with:\n", + "- Function definitions\n", + "- `import` statements\n", + "- Some language constructs (such as `for`, `while`, `with` , which all imply assignments)\n", + "\n", + "We do not have to go into detail here, but these are worth mentioning." + ] + }, + { + "cell_type": "markdown", + "id": "8", + "metadata": {}, + "source": [ + "#### 3. Case sensitivity\n", + "\n", + "Python is **case-sensitive**, which means it treats uppercase and lowercase letters as different:\n", + "\n", + "```python\n", + "name = \"Alice\" # This is different from...\n", + "Name = \"Alice\" # ...this variable\n", + "```\n", + "\n", + "Python understands the variables `name` and `Name` as completely different from each other." + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "#### 4. Parentheses and function calls\n", + "\n", + "When you want to use a **function** (a pre-written piece of code that does something), you write its name followed by parentheses `()`:\n", + "\n", + "```python\n", + "print(\"Hello!\")\n", + "```\n", + "\n", + "If the function needs information to work with, you put that information inside the parentheses.\n", + "We call this information **arguments**.\n", + "\n", + "We are going to dive deeper into this topic, when we talk about [Functions](./00_python_intro.ipynb#Functions) later." + ] + }, + { + "cell_type": "markdown", + "id": "10", + "metadata": {}, + "source": [ + "### Indentation: Python's superpower\n", + "\n", + "This is one of the most important concepts in Python: **indentation** refers to the spaces (or tabs) at the beginning of a line of code.\n", + "\n", + "In many programming languages, indentation is just for readability.\n", + "But in Python, **indentation has meaning**: it defines the structure of your code." + ] + }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "#### Why indentation matters\n", + "\n", + "Indentation tells Python which lines of code belong together as a **block**.\n", + "Let's see an example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], + "source": [ + "# Correct indentation\n", + "if 10 > 5:\n", + " print(\"This line is indented\")\n", + " print(\"This line is also indented\")\n", + " print(\"All these lines belong to the 'if 10 > 5' block\")\n", + "\n", + "print(\"This line is NOT indented, so it's outside the 'if' block\")" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, + "source": [ + "**What happened here?**\n", + "\n", + "1. The line `if 10 > 5:` ends with a colon `:` and this tells Python \"a block of code is coming next\"\n", + "2. The next three `print` statements are **indented** (they start with 4 spaces)\n", + "3. These indented lines form a **block** and they only run if the condition `10 > 5` is true\n", + "4. The last `print` statement is **not indented**, so it is outside the block and always runs\n", + "\n", + "Think of indentation like this:\n", + "```\n", + "Code at the left edge (no indent) → Always runs\n", + " Indented code → Runs only under certain conditions\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "14", + "metadata": {}, + "source": [ + "#### Common indentation mistakes\n", + "\n", + "Here are some errors beginners often make:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15", + "metadata": {}, + "outputs": [], + "source": [ + "# Missing indentation:\n", + "# This will cause an IndentationError!\n", + "\n", + "if 10 > 5:\n", + "print(\"This should be indented!\")\n", + "\n", + "# The line above would give an error because print is not indented" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16", + "metadata": {}, + "outputs": [], + "source": [ + "# Inconsistent indentation:\n", + "# This will also cause an IndentationError!\n", + "\n", + "if 10 > 5:\n", + " print(\"Indented with 4 spaces\")\n", + " print(\"Indented with 2 spaces - ERROR!\")\n", + "\n", + "# Python requires consistent indentation within the same block" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17", + "metadata": {}, + "outputs": [], + "source": [ + "# Inconsistent indentation:\n", + "# This will NOT cause an error but will lead to unexpected behavior!\n", + "\n", + "x = 15\n", + "\n", + "if x > 10:\n", + " print(\"x is greater than 10\")\n", + "print(\"This should only print if x > 10, but it always prints!\")\n", + "\n", + "# The second print is not indented, so it is outside the if block\n", + "# It will execute regardless of whether x > 10 is true or false" + ] + }, + { + "cell_type": "markdown", + "id": "18", + "metadata": {}, + "source": [ + "
\n", + "

Indentation Tips

\n", + " \n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "19", + "metadata": {}, + "source": [ + "### Comments: notes to yourself\n", + "\n", + "**Comments** are lines in your code that Python ignores.\n", + "They are notes for humans (including your future self) to understand what the code does.\n", + "\n", + "In Python, comments start with the `#` symbol.\n", + "Everything on the same line after the `#` symbol is ignored by Python." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20", + "metadata": {}, + "outputs": [], + "source": [ + "# This is a comment - Python will ignore this line\n", + "\n", + "# Calculate the area of a rectangle\n", + "width = 10 # This comment explains what width represents\n", + "height = 5 # You can put comments at the end of lines too\n", + "area = width * height\n", + "\n", + "print(area) # Output: 50" + ] + }, + { + "cell_type": "markdown", + "id": "21", + "metadata": {}, + "source": [ + "Comments are useful for:\n", + "- Explaining **why** you wrote the code a certain way\n", + "- Leaving notes for your future self or teammates\n", + "- Temporarily \"turning off\" code without deleting it\n", + "\n", + "\n", + "
\n", + "

Good practice

\n", + " Write comments that explain the \"why,\" not the \"what.\"\n", + " Your code should be clear enough that it shows what it does; comments should explain why you made certain choices.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "22", + "metadata": {}, + "source": [ + "## Hello, World!\n", + "\n", + "Let's start with the simplest possible Python program:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Hello, world!\")" + ] + }, + { + "cell_type": "markdown", + "id": "24", + "metadata": {}, + "source": [ + "This simple line already contains several important concepts.\n", + "Let's break them down." + ] + }, + { + "cell_type": "markdown", + "id": "25", + "metadata": {}, + "source": [ + "### What is an expression?\n", + "\n", + "An **expression** is any piece of code that produces a value.\n", + "In the example above:\n", + "\n", + "- `\"Hello, world!\"` is an expression (it evaluates to the string value `\"Hello, world!\"`)\n", + "- `print(\"Hello, world!\")` is also an expression: It is a **function call** that evaluates to `None`, but produces the side effect of printing text\n", + "\n", + "Expressions are the building blocks of Python programs.\n", + "They can be as simple as a number (`42`) or as complex as any calculation (`(5 + 3) * 2`)." + ] + }, + { + "cell_type": "markdown", + "id": "26", + "metadata": {}, + "source": [ + "### What is a string?\n", + "\n", + "A **string** is a sequence of characters enclosed in quotes.\n", + "In Python, you can use either single quotes (`'`) or double quotes (`\"`):\n", + "\n", + "```python\n", + "\"Hello, world!\" # Double quotes\n", + "'Hello, world!' # Single quotes - equivalent\n", + "```\n", + "\n", + "Strings are one of Python's fundamental **data types**.\n", + "They represent text and are used extensively in programming." + ] + }, + { + "cell_type": "markdown", + "id": "27", + "metadata": {}, + "source": [ + "### How Python executes this code\n", + "\n", + "Python is an **interpreted** language, which means that the Python interpreter reads and executes your code line by line, from top to bottom.\n", + "This interactive nature makes Python great for experimentation and learning.\n", + "\n", + "You can see this in action in Jupyter notebooks like this one: each cell is executed independently when you run it." + ] + }, + { + "cell_type": "markdown", + "id": "28", + "metadata": {}, + "source": [ + "## Basic datatypes and operations\n", + "\n", + "Now let's explore some of Python's basic data types and what we can do with them." + ] + }, + { + "cell_type": "markdown", + "id": "29", + "metadata": {}, + "source": [ + "### Numbers\n", + "\n", + "Python supports various numeric types.\n", + "Let's try some basic arithmetic:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30", + "metadata": {}, + "outputs": [], + "source": [ + "1 + 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31", + "metadata": {}, + "outputs": [], + "source": [ + "10 - 3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32", + "metadata": {}, + "outputs": [], + "source": [ + "4 * 5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33", + "metadata": {}, + "outputs": [], + "source": [ + "15 / 3" + ] + }, + { + "cell_type": "markdown", + "id": "34", + "metadata": {}, + "source": [ + "We can also make comparisons:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35", + "metadata": {}, + "outputs": [], + "source": [ + "3 > 5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36", + "metadata": {}, + "outputs": [], + "source": [ + "3 < 5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37", + "metadata": {}, + "outputs": [], + "source": [ + "3 == 5" + ] + }, + { + "cell_type": "markdown", + "id": "38", + "metadata": {}, + "source": [ + "### Strings\n", + "\n", + "Strings can also be combined using the `+` operator (called **concatenation**):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39", + "metadata": {}, + "outputs": [], + "source": [ + "'Hello, ' + 'world!'" + ] + }, + { + "cell_type": "markdown", + "id": "40", + "metadata": {}, + "source": [ + "Notice how the `+` operator works differently depending on what you're adding.\n", + "Numbers are added mathematically, while strings are joined together.\n", + "This is a simple example of how Python adapts behavior based on data types." + ] + }, + { + "cell_type": "markdown", + "id": "41", + "metadata": {}, + "source": [ + "### The `type()` function\n", + "\n", + "Python has a built-in function called `type()` that tells you what type of data you are working with:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42", + "metadata": {}, + "outputs": [], + "source": [ + "type(1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43", + "metadata": {}, + "outputs": [], + "source": [ + "type(1.0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44", + "metadata": {}, + "outputs": [], + "source": [ + "type(\"Hello\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "45", + "metadata": {}, + "outputs": [], + "source": [ + "type(True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46", + "metadata": {}, + "outputs": [], + "source": [ + "type([1, 2, 3])" + ] + }, + { + "cell_type": "markdown", + "id": "47", + "metadata": {}, + "source": [ + "Here we see several fundamental types:\n", + "- `int` - integers (whole numbers)\n", + "- `float` - floating-point numbers (decimals)\n", + "- `str` - strings (text)\n", + "- `bool` - boolean values (`True` or `False`)\n", + "- `list` - ordered collections of items" + ] + }, + { + "cell_type": "markdown", + "id": "48", + "metadata": {}, + "source": [ + "
\n", + "

Note

\n", + " We will cover all topics related to datatypes very soon, during the Basic Datatypes section of the tutorial.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "49", + "metadata": {}, + "source": [ + "### Dynamic typing\n", + "\n", + "An important characteristic of Python is that **type attribution is implicit and context-dependent**.\n", + "As you may have noticed, you do not need to explicitly declare the type of a variable, as you may have done in other programming languages.\n", + "Python figures it out automatically based on the value you assign." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50", + "metadata": {}, + "outputs": [], + "source": [ + "x = 42\n", + "print(type(x))\n", + "\n", + "x = \"Now I'm a string!\"\n", + "print(type(x))" + ] + }, + { + "cell_type": "markdown", + "id": "51", + "metadata": {}, + "source": [ + "The variable `x` can change type freely. \n", + "This makes Python very flexible, but also means you need to be mindful of what type your variables hold." + ] + }, + { + "cell_type": "markdown", + "id": "52", + "metadata": {}, + "source": [ + "## Conditional execution\n", + "\n", + "Programs often need to make decisions.\n", + "Python uses `if-else` statements to execute different code based on conditions:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53", + "metadata": {}, + "outputs": [], + "source": [ + "if 5 > 3:\n", + " print(\"True\")\n", + "else:\n", + " print(\"False\")" + ] + }, + { + "cell_type": "markdown", + "id": "54", + "metadata": {}, + "source": [ + "Since `5 > 3` evaluates to `True`, the block executes and prints \"True\". \n", + "\n", + "Let's try another example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55", + "metadata": {}, + "outputs": [], + "source": [ + "temperature = 25\n", + "\n", + "if temperature > 30:\n", + " print(\"It's hot!\")\n", + "elif temperature > 20:\n", + " print(\"It's pleasant\")\n", + "else:\n", + " print(\"It's cold!\")" + ] + }, + { + "cell_type": "markdown", + "id": "56", + "metadata": {}, + "source": [ + "Conditionals allow your program to **deviate** from linear execution and make decisions based on data." + ] + }, + { + "cell_type": "markdown", + "id": "57", + "metadata": {}, + "source": [ + "## Loops\n", + "\n", + "Loops allow us to execute code repeatedly.\n", + "This is essential for processing collections of data or performing repetitive tasks." + ] + }, + { + "cell_type": "markdown", + "id": "58", + "metadata": {}, + "source": [ + "### The `for` loop\n", + "\n", + "The most common type of loop in Python is the `for` loop, which iterates over a sequence:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59", + "metadata": {}, + "outputs": [], + "source": [ + "for i in range(3):\n", + " print(i)" + ] + }, + { + "cell_type": "markdown", + "id": "60", + "metadata": {}, + "source": [ + "The `range(3)` function generates the sequence `[0, 1, 2]`, and the loop executes once for each value.\n", + "\n", + "Here's a practical example that sums the numbers in a list:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61", + "metadata": {}, + "outputs": [], + "source": [ + "total = 0\n", + "\n", + "for num in range(5):\n", + " total = total + num\n", + "\n", + "print(total)" + ] + }, + { + "cell_type": "markdown", + "id": "62", + "metadata": {}, + "source": [ + "### The `while` loop\n", + "\n", + "The `while` loop continues executing as long as a condition remains `True`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63", + "metadata": {}, + "outputs": [], + "source": [ + "count = 0\n", + "\n", + "while count < 5:\n", + " print(count)\n", + " count = count + 1" + ] + }, + { + "cell_type": "markdown", + "id": "64", + "metadata": {}, + "source": [ + "Loops are fundamental for automating repetitive tasks and processing data collections.\n", + "\n", + "
\n", + "

Note

\n", + " We will cover all topics related to Conditionals and Loops, during the Control flow section of the tutorial.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "65", + "metadata": {}, + "source": [ + "## Functions\n", + "\n", + "As programs grow more complex, we need a way to organize and reuse code.\n", + "**Functions** are the solution to this." + ] + }, + { + "cell_type": "markdown", + "id": "66", + "metadata": {}, + "source": [ + "### Why functions?\n", + "\n", + "Functions allow you to:\n", + "1. **Reuse code**: write once, use many times\n", + "2. **Organize code**: break complex problems into manageable pieces\n", + "3. **Abstract details**: hide complexity behind a simple interface" + ] + }, + { + "cell_type": "markdown", + "id": "67", + "metadata": {}, + "source": [ + "### A first example\n", + "\n", + "Here's a simple function that greets someone:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68", + "metadata": {}, + "outputs": [], + "source": [ + "def greet(name):\n", + " return \"Hello, \" + name + \"!\"" + ] + }, + { + "cell_type": "markdown", + "id": "69", + "metadata": {}, + "source": [ + "Notice here how we are able not only to [concatenate strings](./00_python_intro.ipynb#Strings), as we have seen before, but also concatenate the value of variable `name` to the string, using the `+` sign.\n", + "\n", + "Now we can call this function with different names:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70", + "metadata": {}, + "outputs": [], + "source": [ + "print(greet(\"Alice\"))\n", + "print(greet(\"Bob\"))" + ] + }, + { + "cell_type": "markdown", + "id": "71", + "metadata": {}, + "source": [ + "
\n", + "

Note

\n", + " We will explain every detail about functions in the Functions notebook, but, for now, let's cover the basic information you will need in order to start the tutorial.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "72", + "metadata": {}, + "source": [ + "### Parameters and Arguments\n", + "\n", + "You can see that the function we defined above is expecting to receive a value for the variable called `name`.\n", + "The variable `name` itself is called a **parameter**.\n", + "\n", + "The value that we assign to this parameter, for example, `\"Alice\"`, is called an **argument**.\n", + "\n", + "These two terms are often used interchangeably, so no need to stress about that now.\n", + "Just remember that when we want to *define* and *call* a function, you need to do the following:" + ] + }, + { + "cell_type": "markdown", + "id": "73", + "metadata": {}, + "source": [ + "### Defining a function\n", + "\n", + "To define a function you need to use the keyword `def`, followed by the name of the function.\n", + "The function name should not contain any space characters and, as a good practice, should be indicative of what the function is supposed to be doing.\n", + "\n", + "After that, you define the **parameters** of the function, inside **parentheses**.\n", + "You can have as many parameters as you want, separated by **commas**.\n", + "\n", + "Finally, remember what we mentioned about [indentation](./00_python_intro.ipynb#Indentation:-Python's-superpower) earlier:\n", + "The function **signature** finishes with a **colon** character.\n", + "Below that, all the code that you would like to include in your function, should be **indented**.\n", + "\n", + "Here is what we have so far:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "74", + "metadata": {}, + "outputs": [], + "source": [ + "def add_numbers(a, b):\n", + " # Does something..." + ] + }, + { + "cell_type": "markdown", + "id": "75", + "metadata": {}, + "source": [ + "If you try to execute this cell, you will get an error.\n", + "That is because Python sees this function definition as incomplete.\n", + "Each function should have a **body** *and/or* a **return statement**." + ] + }, + { + "cell_type": "markdown", + "id": "76", + "metadata": {}, + "source": [ + "### The function body\n", + "\n", + "The **body** of a function is the block of **indented code** that runs when the function is called.\n", + "It contains the instructions that perform the function's task." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77", + "metadata": {}, + "outputs": [], + "source": [ + "def add_numbers(a, b): # 'a' and 'b' are PARAMETERS\n", + " # This is the body of the function\n", + " c = a + b\n", + " return c\n", + "\n", + "result = add_numbers(5, 3) # 5 and 3 are ARGUMENTS\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "id": "78", + "metadata": {}, + "source": [ + "### Calling a function\n", + "\n", + "Calling a function is easy.\n", + "You write the name of the function and then, inside the parentheses, the arguments that you would like to pass, separated by commas.\n", + "\n", + "If your function is returning something, you can assign that value to a variable, similarly to how you would write any other [statement](./00_python_intro.ipynb#Python-syntax-basics).\n", + "We already did this in the example above:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79", + "metadata": {}, + "outputs": [], + "source": [ + "result = add_numbers(5, 3)" + ] + }, + { + "cell_type": "markdown", + "id": "80", + "metadata": {}, + "source": [ + "This way you can reuse the value of `result` in other calculations.\n", + "\n", + "If your only objective is to print the result of the function and not reuse it in any way, then you could even pass the function call directly as the `print` argument:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81", + "metadata": {}, + "outputs": [], + "source": [ + "print(add_numbers(5, 3))" + ] + }, + { + "cell_type": "markdown", + "id": "82", + "metadata": {}, + "source": [ + "By now, you may have noticed that we have already used a function multiple times in our examples.\n", + "That function is no other than the `print` function.\n", + "\n", + "Notice how we call it like we would call any other function: \n", + "with its name, followed by parentheses, and inside the parentheses the argument." + ] + }, + { + "cell_type": "markdown", + "id": "83", + "metadata": {}, + "source": [ + "### `return` vs `print`\n", + "\n", + "The code that we just wrote contains a crucial distinction that could confuse many beginners:\n", + "\n", + "- **`return`** sends a value back to whoever called the function (the value can be used in further calculations)\n", + "- **`print`** displays text on the screen (it's just for showing output to humans)\n", + "\n", + "Let's see the difference:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84", + "metadata": {}, + "outputs": [], + "source": [ + "# Function that PRINTS (does not return a value)\n", + "def add_numbers_and_print(a, b):\n", + " c = a + b\n", + " print(c)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85", + "metadata": {}, + "outputs": [], + "source": [ + "# Function that RETURNS a value\n", + "def add_numbers_and_return(a, b):\n", + " c = a + b\n", + " return c" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86", + "metadata": {}, + "outputs": [], + "source": [ + "result1 = add_numbers_and_print(5, 3)\n", + "print(result1)\n", + "# result1 is None: no value was returned\n", + "\n", + "result2 = add_numbers_and_return(5, 3)\n", + "print(result2) \n", + "# result2 contains calculated value" + ] + }, + { + "cell_type": "markdown", + "id": "87", + "metadata": {}, + "source": [ + "Here's why `return` is important:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88", + "metadata": {}, + "outputs": [], + "source": [ + "def square(x):\n", + " result = x * x\n", + " return result\n", + "\n", + "# You can reuse the returned value\n", + "result = square(5)\n", + "print(result)\n", + "\n", + "# You can do further calculations\n", + "doubled = result * 2\n", + "print(doubled)" + ] + }, + { + "cell_type": "markdown", + "id": "89", + "metadata": {}, + "source": [ + "Notice that return is not followed by parentheses, as it is not a function." + ] + }, + { + "cell_type": "markdown", + "id": "90", + "metadata": {}, + "source": [ + "
\n", + "

Common Beginner Mistake

\n", + "

Beginners often use print in functions when they should use return. Remember:

\n", + " \n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "91", + "metadata": {}, + "source": [ + "### Type hints (optional but helpful)\n", + "\n", + "While Python does not require you to specify types, you can add **type hints** to make your code clearer.\n", + "Type hints document what types of data a function expects and returns.\n", + "\n", + "This is what the syntax looks like:\n", + "- `parameter: type` → tells what type the parameter should be\n", + "- `-> type` → tells what type the function returns\n", + "\n", + "For example:\n", + "\n", + "```python\n", + "# Without type hints\n", + "def multiply(a, b):\n", + " return a * b\n", + "\n", + "# With type hints\n", + "def multiply_with_hints(a: int, b: int) -> int:\n", + " return a * b\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "92", + "metadata": {}, + "source": [ + "
\n", + "

Note

\n", + "

Type hints in Python are documentation, not enforcement. This means that Python will not stop you from passing the wrong type of argument when calling a function.

\n", + "
\n", + "\n", + "As mentioned above, type hints are optional.\n", + "However, throughout the tutorial, you will see that we use them extensively, especially in the exercises that we ask you to solve.\n", + "This is done mainly to provide you with additional information about what your code is expected to be doing." + ] + }, + { + "cell_type": "markdown", + "id": "93", + "metadata": {}, + "source": [ + "### Docstrings: special comments for functions\n", + "\n", + "While regular comments use `#`, Python has a special type of comment called a **docstring** (short for \"documentation string\").\n", + "Docstrings are used to document what functions, classes, and modules do.\n", + "So let's see how we can use that in a function.\n", + "\n", + "Unlike regular comments, docstrings:\n", + "- Use **triple quotes** (`\"\"\"` or `'''`)\n", + "- Appear as the **first statement** inside a function\n", + "- Can span over multiple lines\n", + "- Bonus: they can be accessed programmatically (Python can read them!)\n", + "\n", + "Here's how they work:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "94", + "metadata": {}, + "outputs": [], + "source": [ + "def greet():\n", + " \"\"\"\n", + " This is a docstring.\n", + " It describes what the function does.\n", + " \n", + " You can write multiple lines to explain the function clearly.\n", + " \"\"\"\n", + " return \"Hello, world!\"\n", + "\n", + "# The function still works normally\n", + "print(greet())" + ] + }, + { + "cell_type": "markdown", + "id": "95", + "metadata": {}, + "source": [ + "A well-written docstring typically includes:\n", + "1. What the function does\n", + "2. What parameters it expects\n", + "3. What it returns\n", + "\n", + "Here is a more detailed example.\n", + "The exercises that you will be asked to solve will look like this:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96", + "metadata": {}, + "outputs": [], + "source": [ + "def calculate_area(width, height):\n", + " \"\"\"\n", + " Calculate the area of a rectangle.\n", + " \n", + " Parameters:\n", + " width (float): The width of the rectangle\n", + " height (float): The height of the rectangle\n", + " \n", + " Returns:\n", + " float: The area of the rectangle (width × height)\n", + " \"\"\"\n", + " return width * height\n", + "\n", + "print(calculate_area(5, 10))" + ] + }, + { + "cell_type": "markdown", + "id": "97", + "metadata": {}, + "source": [ + "## Putting it all together: A complete example\n", + "\n", + "Let's create an example that covers all the concepts we have talked about:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "98", + "metadata": {}, + "outputs": [], + "source": [ + "def rectangle_area(width: float, height: float) -> float:\n", + " \"\"\"\n", + " Calculate the area of a rectangle.\n", + " \n", + " Parameters:\n", + " width: The width of the rectangle (in any unit)\n", + " height: The height of the rectangle (in same unit as width)\n", + " \n", + " Returns:\n", + " The area of the rectangle (width × height)\n", + " \"\"\"\n", + " # Function body starts here (indented)\n", + " area = width * height # Do the calculation\n", + " return area # Return the result \n", + " # Function body ends here\n", + "\n", + "# Now use the function:\n", + "result = rectangle_area(5.0, 10.0)\n", + "print(result)\n", + "\n", + "# We can use the returned value in more calculations\n", + "double_area = result * 2\n", + "print(double_area)" + ] + }, + { + "cell_type": "markdown", + "id": "99", + "metadata": {}, + "source": [ + "In this complete example:\n", + "\n", + "1. **`width` and `height`** are **parameters**\n", + "2. **`5.0` and `10.0`** are **arguments** (the actual values we pass when calling)\n", + "3. **Type hints** (`float` and `-> float`) document expected types\n", + "4. The **function body** (indented section) contains all the logic\n", + "5. **`print`** displays information for us to see\n", + "6. **`return`** gives back the calculated value so we can use it\n", + "7. The **docstring** (triple-quoted text) explains what the function does\n", + "\n", + "This is how all the pieces work together!" + ] + }, + { + "cell_type": "markdown", + "id": "100", + "metadata": {}, + "source": [ + "## What's next?\n", + "\n", + "Congratulations on completing this quick tour of Python! 🎉\n", + "\n", + "You have now learned the fundamental building blocks:\n", + "- ✅ Python syntax and indentation rules\n", + "- ✅ Comments and docstrings\n", + "- ✅ Basic data types and operations\n", + "- ✅ Conditional execution with `if-else`\n", + "- ✅ Loops with `for` and `while`\n", + "- ✅ Functions with parameters and return values\n", + "\n", + "Each topic we touched on has much more depth to explore in the detailed notebooks:\n", + "\n", + "- **[Basic datatypes](./01_basic_datatypes.ipynb)** - Dive deep into numbers, strings, lists, dictionaries, sets, and more\n", + "- **[Control flow](./02_control_flow.ipynb)** - Master conditionals, loops, and exception handling\n", + "- **[Functions](./03_functions.ipynb)** - Learn about parameters, scope, decorators, and functional programming\n", + "- **[Input/Output](./04_input_output.ipynb)** - Work with files, paths, and data persistence\n", + "- **[Object-oriented programming](./05_object_oriented_programming.ipynb)** - Explore inheritance, special methods, and design patterns\n", + "- **[Modules and packages](./06_modules_and_packages.ipynb)** - Organize code into reusable modules and work with external libraries\n", + "\n", + "Happy coding! 🐍" + ] + } + ], + "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.12.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}