{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### This is a Jupyter notebook\n", "\n", "Throughout this course we will be running Python in Jupyter notebooks.\n", "\n", "Jupyter notebooks consist of a combination of markdown cells and code cells. This cell is a markdown cell.\n", "\n", "To run this code you will need to connect to a Python kernel. To do this, click on the Select Kernel button in the upper right hand corner of the window, then select Python Environments... from the command pallette, and then select the torchenv environment.\n", "\n", "The cell below is a code cell. To execute the code in the code cell, click the run triangle next to the cell. Any output generated by the cell will be displayed below the cell." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = [4,7,2,8,9,2]\n", "len(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python is a dynamic language. To create a variable we simply assign a value to the variable. The variable will take on the type of the data stored in the variable. In this example x contains a Python list object.\n", "\n", "When you evaluate a cell in a Jypyter notebook the output that gets printed is the result of the last statement in the cell." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Basics of Python\n", "\n", "Python uses indentation in place of curly braces to indicate structure in loops, if-else statements, and other types of statements. To add a level of indentation we use a tab." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "search = 5\n", "present = False\n", "for n in x:\n", " if n == search:\n", " present = True\n", "if present:\n", " print(\"5 is in the list\")\n", "else:\n", " print(\"5 is not in the list\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is an example of a function definition in Python." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def isPresent(x,xs):\n", " for n in xs:\n", " if n == x:\n", " return True\n", " return False\n", "\n", "if isPresent(7,x):\n", " print(\"7 is present\")\n", "else:\n", " print(\"7 is not present\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python offers a large number of packages. To import a Python package we use the import command.\n", "\n", "The numpy package is one of the more popular packages in Python. This package offers many facilities for manipulating lists and arrays of numbers." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "y = np.random.randint(low = 1,high=9,size=10)\n", "y" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(f\"The average of the numbers in the list is {y.mean()}.\")\n", "print(f\"The largest number in list is {y.max()}.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Loops\n", "\n", "The most common loop in Python is the for..in loop, which iterates over the items in a collection." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = [3,-2,5,7,-2,3]\n", "\n", "sum = 0\n", "\n", "for x in a:\n", " sum += x\n", "\n", "sum" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want to iterate over a range of indices instead of list values you can use the `range()` construct instead." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "total = 0\n", "\n", "for i in range(0,len(a)):\n", " total += a[i]\n", "\n", "total" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want to iterate over both list elements and their indices, use `enumerate()` in place of `range()`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "biggest = a[0]\n", "where = 0\n", "\n", "for i,x in enumerate(a):\n", " if x > biggest:\n", " biggest = x\n", " where = i\n", "\n", "print(f\"The largest number is {biggest}, which appears at index {where}.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Vector processing\n", "\n", "Numpy is built from the ground up to do a special style of data processing, called vector processing.\n", "\n", "The next couple of code samples demonstrate how this works.\n", "\n", "Here is numpy array containing a large set of sample points." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "xs = np.arange(0.,1.5,0.05)\n", "xs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can apply a function to each element of this list by using special Numpy vector functions." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ys = xs * np.sin(xs)\n", "ys" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In Numpy both the multiplication function (*) and the np.sin() function are vector functions. When you apply them to a numpy array the function automatically get applied to every element in the array." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tuples and list comprehensions\n", "\n", "As an alternative to the list structure Python also offers the tuple structure. Tuples and lists share many common features: you can access elements in tuple or a list via the usual list index notation using square braces. The main difference between lists and tuples is that lists are mutable while tuples are not:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "t = (5,6)\n", "lt = [5,6]\n", "print(f\"The second item in t is {t[1]}\")\n", "print(f\"The second item in lt is {lt[1]}\")\n", "\n", "lt.append(7)\n", "print(lt)\n", "t.append(7)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A frequently used programming pattern in Python is to return a tuple from a function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def betterSearch(x,xs):\n", " for i,n in enumerate(xs):\n", " if n > x:\n", " return (i,n)\n", " return (-1,-1)\n", "\n", "location, value = betterSearch(5,x)\n", "print((location,value))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Python `enumerate()` function returns a sequence of tuples: the first item in each tuple is the index of the current item in the list, and the second item is the current item.\n", "\n", "Note how we handle the tuple returned from the betterSearch() function: we use a tuple assignment to assign the two components of the returned tuple to variables `location` and `value`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another less commonly used programming pattern in Python loops is to iterate over a range of integers that covers all of the index positions in a list. Here is the last example rewritten to use this approach." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def betterSearch(x,xs):\n", " for i in range(0,len(xs)):\n", " if xs[i] > x:\n", " return (i,xs[i])\n", " return (-1,-1)\n", "\n", "location, value = betterSearch(5,x)\n", "print((location,value))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A Python list comprehension is an alterative method for constructing a list. This method is usually used to construct a new list from an existing list." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "z = [np.sqrt(n) for n in x]\n", "z" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can convert any Python list to a Numpy array by using the np.array() constructor function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "nz = np.array(z)\n", "nz" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Classes in Python\n", "\n", "The next cell below contains a class definition for a simple Python class. This class implements a counter with increment and decrement operations." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Counter:\n", " def __init__(self):\n", " self.value = 0\n", "\n", " def increment(self):\n", " self.value += 1\n", " \n", " def decrement(self):\n", " self.value -= 1\n", " \n", " def __str__(self):\n", " return f\"Counter with value {self.value}\" " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here are some important things to note about this example:\n", "\n", "- A Python class is a container for a collection of methods.\n", "- Each method needs to have a `self` parameter, which refers to the object that the method is being applied to.\n", "- There is no need to declare member variables; instead, we create member variables implicitly by assigning a value to them. This example class has a single member variable `value` that stores the value of the counter.\n", "- Python makes extensive use of operator overloading. To overload an operator we define a method whose name is linked to that operator: these methods are distinguished by names that start and end with double underscores. In this example I have overloaded the class constructor via the `__init__` method, and the string conversion operator via the `__str__` method.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is some sample code to demonstrate how to use the class." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "c = Counter()\n", "c.increment()\n", "c.increment()\n", "print(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Slicing lists\n", "\n", "A common operation in Python lists is slicing, which returns part of a list." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = [1,3,5,7,9]\n", "a[1:3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A slice covers a range of indices, starting with the first index and ending before the second index. In this example we make a slice that starts with a[1] (which is 3) and ends before a[3]." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you leave out the first index in a slice it defaults to 0. If you leave out the second index in the slice it defaults to the length of the list (which is one larger than the last index)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(a[:3])\n", "print(a[3:])\n", "print(a[:])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also use negative indices to count backward from the end of a list." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(a[1:-1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "numpy supports a wider range of slicing operations." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "b = np.array([[1,5,-2],[2,7,-3],[3,9,-4]])\n", "print(b[1:3])\n", "print(b[1:3,2:3])\n", "print(b[:,1])" ] } ], "metadata": { "kernelspec": { "display_name": "torchenv", "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.3" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }