{ "cells": [ { "cell_type": "markdown", "id": "39e41d4a", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# DS2500 Lesson 2\n", "Jan 17, 2023\n", "\n", "Content:\n", "- Slicing a list/tuple\n", "- Functions\n", "- Assert\n", " - input validation & test cases\n" ] }, { "cell_type": "markdown", "id": "6171b09f", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Slicing a list (part 1)\n", "A slice refers to a \"contiguous\" run of items in a list. Slicing returns these elements from the list.\n", "\n", "![](https://i.ibb.co/JK1VHpy/list1.png)\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "3a84f6f4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[-45, 6, 0, 72, 1543]" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# lets build the example above\n", "c = [-45, 6, 0, 72, 1543]\n", "c\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "de2b7003", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[6, 0, 72]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c[1:4]" ] }, { "cell_type": "code", "execution_count": 3, "id": "5f446ff2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[6, 0, 72]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# the first index is the starting index (included in slice)\n", "# the second index is the ending index (not included in slice)\n", "c[1:1 + 3]\n" ] }, { "cell_type": "code", "execution_count": 8, "id": "5e047171", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[-45, 6]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# by default, if we exclude the starting index it is assumed to be 0\n", "c[:2]\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "7e8216a8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(c)" ] }, { "cell_type": "code", "execution_count": 12, "id": "06dee335", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 72, 1543]" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# by default, if we exclude the ending index it is assumed the length of the list\n", "c[2:]\n" ] }, { "cell_type": "markdown", "id": "55c8f566", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Slicing a list (part 2)\n" ] }, { "cell_type": "markdown", "id": "b1189659", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "Negative indices are helpful if we want to start counting from the \"end\" of a list:\n", "\n", "![](https://i.ibb.co/RGF8sPW/list2.png)\n" ] }, { "cell_type": "code", "execution_count": 13, "id": "79962040", "metadata": {}, "outputs": [], "source": [ "c = [-45, 6, 0, 72, 1543]\n" ] }, { "cell_type": "code", "execution_count": 15, "id": "d238c055", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[72, 1543]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c[3:5]" ] }, { "cell_type": "code", "execution_count": 19, "id": "126d4a9b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[72, 1543]" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# just the same as c[3:5]\n", "c[-2:]\n" ] }, { "cell_type": "code", "execution_count": 20, "id": "0582602d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 72, 1543]" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# this backwards counting & default ending index make for an elegant way to get the last n elements of a list\n", "c[-3:]\n" ] }, { "cell_type": "markdown", "id": "8274c8ff", "metadata": {}, "source": [ "### Skip counting in a slice (1, 3, 5, 7, ...)\n", "\n", "We might be interested in skipping through the list by some constant index (skipping by 2 gets every other index, for example)\n" ] }, { "cell_type": "code", "execution_count": 21, "id": "154f0f04", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[-45, 6, 0, 72, 1543]" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = [-45, 6, 0, 72, 1543]\n", "c\n" ] }, { "cell_type": "code", "execution_count": 22, "id": "b2fb0b3c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[-45, 0, 1543]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# some_list[start_idx: stop_idx: step_size]\n", "# starting idx: 0, ending idx: 5, step size: 2\n", "c[0:5:2]\n" ] }, { "cell_type": "code", "execution_count": 11, "id": "74a8ddf6", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[-45, 0, 1543]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# same as above but now we use defaults\n", "c[::2]\n" ] }, { "cell_type": "code", "execution_count": 12, "id": "d02f91de", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[6, 72]" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# grab all the odd indexed elements\n", "c[1::2]\n" ] }, { "cell_type": "code", "execution_count": 13, "id": "b1688c2e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[-45, 6, 0, 72, 1543]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c\n" ] }, { "cell_type": "code", "execution_count": 23, "id": "bdeeb9a5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1543, 72, 0, 6]" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# we can even take negative steps if we want to\n", "c[5:0:-1]\n" ] }, { "cell_type": "code", "execution_count": 26, "id": "bd0912ff", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1543, 72, 0, 6, -45]" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# reverses list order\n", "c[::-1]\n" ] }, { "cell_type": "markdown", "id": "464e6f1c", "metadata": {}, "source": [ "### Good to know:\n", "\n", "This slice syntax is common among many python data types:\n", "- tuples / lists / strings\n", "- pandas dataframes (like a table of data)\n", "- numpy arrays\n" ] }, { "cell_type": "markdown", "id": "079c3ab7", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# In Class Assignment A\n", " \n", "Slice the string `ascii_letters` below to:\n", "- produce the 10th through the 15th letters of the alphabet (lowercase). please include the 15th letter of hte alphabet in your output\n", " - 'a' is the first letter of the alphabet\n", "- produce all \"odd\" indexed characters ('bdfh...')\n", "- produce the first 3 letters\n", "- produce the last 10 letters\n", "- reverse the order of the string\n" ] }, { "cell_type": "code", "execution_count": 28, "id": "4e034a48", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from string import ascii_letters\n", "ascii_letters" ] }, { "cell_type": "code", "execution_count": 33, "id": "4a01fa70", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'jklmno'" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ascii_letters[9:15]" ] }, { "cell_type": "code", "execution_count": 35, "id": "06b1dcba", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'bdfhjlnprtvxzBDFHJLNPRTVXZ'" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ascii_letters[1::2]" ] }, { "cell_type": "code", "execution_count": 37, "id": "bacf6fe7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'abc'" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ascii_letters[:3]" ] }, { "cell_type": "code", "execution_count": 38, "id": "ee6a016e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'QRSTUVWXYZ'" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ascii_letters[-10:]" ] }, { "cell_type": "code", "execution_count": 39, "id": "0a59c0b3", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba'" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ascii_letters[::-1]" ] }, { "cell_type": "code", "execution_count": 27, "id": "e4c7f106", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "db2fc422", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Functions\n", "\n", "* defining and calling functions\n", "* functions with multiple inputs\n", "* functions with multiple outputs (tuple unpacking to the rescue!)\n", "* default parameter values\n" ] }, { "cell_type": "code", "execution_count": 55, "id": "24dac786", "metadata": {}, "outputs": [], "source": [ "def square(number):\n", " \"\"\" squares a number\n", " \n", " Args:\n", " number (float): input number\n", " \n", " Returns:\n", " sq (float): square of input\n", " \"\"\"\n", " sq = number ** 2\n", " return sq\n" ] }, { "cell_type": "code", "execution_count": 61, "id": "c40006ad", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "100" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "square(10)" ] }, { "cell_type": "code", "execution_count": 48, "id": "afe8ee45", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "121\n" ] } ], "source": [ "square(11)\n" ] }, { "cell_type": "markdown", "id": "355bf36b", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Anatomy of a Function\n", "\n", "1. function definition: \n", "```python\n", "def square(number):\n", "```\n", " - `def` is python keyword to say \"this next block is a function\"\n", " - `square` is the name of the function:\n", " - convention: lowercase w/ underscores\n", " - `number` is input to function\n", "2. function documentation string (docstring):\n", " ```python\n", " \"\"\" squares a number\n", "\n", " Args:\n", " number (float): input number\n", "\n", " Returns:\n", " sq (float): square of input\n", " \"\"\"\n", " ```\n", "3. \"guts\" of function:\n", " ```python\n", " sq = number ** 2\n", " ```\n", " - notice: `number` corresponds to user's input\n", "4. return statement\n", " ```python\n", " return sq\n", " ```\n", " - in effect: the function call `square(10)` will be replaced with `sq`\n" ] }, { "cell_type": "markdown", "id": "d4acc42b", "metadata": {}, "source": [ "### Multiple Inputs to Fnc\n", "- passing by order\n", "- passing by keyword\n", "- default inputs\n", "- passing by order & keyword\n" ] }, { "cell_type": "code", "execution_count": 62, "id": "b9af7635", "metadata": {}, "outputs": [], "source": [ "def raise_to_power(a, b=2):\n", " \"\"\" compute a to the b power\n", " \n", " Args:\n", " a (float): base\n", " b (float): exponent\n", " \n", " Returns:\n", " out (float): a to the b-th power\n", " \"\"\"\n", " return a ** b\n" ] }, { "cell_type": "code", "execution_count": 63, "id": "4abe9fed", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1024" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# notice: the arguments (inputs) are distinguished by the order they're passed in\n", "raise_to_power(2, 10)\n" ] }, { "cell_type": "code", "execution_count": 20, "id": "a0a1445c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1024" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# passing arguments by keyword\n", "raise_to_power(a=2, b=10)\n" ] }, { "cell_type": "code", "execution_count": 66, "id": "b42663f4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1024" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "raise_to_power(b=10, a=2)\n" ] }, { "cell_type": "code", "execution_count": 67, "id": "79302838", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "64" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# passing by order & keyword (all ordered args before keyword args)\n", "raise_to_power(4, b=3)\n" ] }, { "cell_type": "code", "execution_count": 69, "id": "4c394c42", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "49" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# using default param\n", "raise_to_power(a=7)\n" ] }, { "cell_type": "markdown", "id": "24c0a3d6", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Multiple Outputs From Fnc\n", "- tuple unpacking allows for multiple outputs\n" ] }, { "cell_type": "code", "execution_count": 70, "id": "6c5c7160", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "('a', 1, 3.14)" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# make a tuple\n", "some_tuple = ('a', 1, 3.14)\n", "some_tuple\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "0dba82a8", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'some_tuple' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[4], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# tuple unpacking: break a tuple into its component variables\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m item0, item1, item2 \u001b[38;5;241m=\u001b[39m \u001b[43msome_tuple\u001b[49m\n", "\u001b[0;31mNameError\u001b[0m: name 'some_tuple' is not defined" ] } ], "source": [ "# tuple unpacking: break a tuple into its component variables\n", "item0, item1, item2 = some_tuple" ] }, { "cell_type": "code", "execution_count": null, "id": "8365bfbc", "metadata": {}, "outputs": [], "source": [ "item2" ] }, { "cell_type": "code", "execution_count": 5, "id": "cd3f9fe5", "metadata": {}, "outputs": [], "source": [ "def get_multiple(x):\n", " \"\"\" computes first few multiples of x\n", " \n", " Args:\n", " x (float): input number\n", " \n", " Returns:\n", " mult1 (float): x\n", " mult2 (float): 2x\n", " mult3 (float): 3x\n", " \"\"\"\n", " mult1 = x\n", " mult2 = x * 2\n", " mult3 = x * 3\n", " \n", " return mult1, mult2, mult3\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "14cffe9d", "metadata": {}, "outputs": [], "source": [ "# supports returning multiple values\n", "mult1, mult2, mult3 = get_multiple(100)\n" ] }, { "cell_type": "code", "execution_count": 7, "id": "7efed177", "metadata": {}, "outputs": [], "source": [ "# ignore an output of a function with the underscore\n", "mult1, _, _ = get_multiple(100)\n" ] }, { "cell_type": "code", "execution_count": 89, "id": "fa6b3779", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "100" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mult1" ] }, { "cell_type": "code", "execution_count": 83, "id": "64b20af6", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(3, 6, 9)" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# you can also store all outputs as the tuple (if you wanted)\n", "tuple_out = get_multiple(3)\n", "tuple_out" ] }, { "cell_type": "markdown", "id": "65fc1a46", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# When should I make a function? (what are they good for?)\n", "\n", "Use a function to:\n", "1. avoid repeating code which is necessary in more than one place\n", "2. encapsulate some part of your program with a particular job\n", " - its easier to understand / debug a program broken down into pieces than as a whole\n", " \n", "A guideline:\n", "- using a function in your program should be simpler than not using a function\n", " - note: we have some overly simple functions in class notes for pedagogical reasons ... don't mimic this\n" ] }, { "cell_type": "markdown", "id": "e9272559", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Assert\n", "\n", "`assert` evaluates some boolean\n", "- if True does nothing\n", " - \"passing the assert\"\n", "- if False, immediately stops your program with an `AssertionError`\n", " - \"failing the assert\"\n" ] }, { "cell_type": "code", "execution_count": 15, "id": "ed7c40e2", "metadata": {}, "outputs": [], "source": [ "assert 3 == 3\n" ] }, { "cell_type": "code", "execution_count": 17, "id": "ebaa6f58", "metadata": {}, "outputs": [ { "ename": "AssertionError", "evalue": "", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[17], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;241m3\u001b[39m \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m5\u001b[39m\n", "\u001b[0;31mAssertionError\u001b[0m: " ] } ], "source": [ "assert 3 == 5\n" ] }, { "cell_type": "code", "execution_count": 19, "id": "38716115", "metadata": {}, "outputs": [ { "ename": "AssertionError", "evalue": "testing 3 equals 5 aosifdjapodsifa", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[19], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# assert also accepts a string, which is shared if assert fails\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;241m3\u001b[39m \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m5\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtesting 3 equals 5 aosifdjapodsifa\u001b[39m\u001b[38;5;124m'\u001b[39m\n", "\u001b[0;31mAssertionError\u001b[0m: testing 3 equals 5 aosifdjapodsifa" ] } ], "source": [ "# assert also accepts a string, which is shared if assert fails\n", "assert 3 == 5, 'testing 3 equals 5 aosifdjapodsifa'\n" ] }, { "cell_type": "markdown", "id": "70942ca1", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Whats an `assert` good for?\n", "- validating function inputs\n", "- testing functions\n", "\n", "(there are other uses too ... but we focus on these two)\n" ] }, { "cell_type": "markdown", "id": "c28873cf", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## `assert` to validate function inputs (part 1)\n", "\n", "By checking that the inputs to our function are appropriate, we can warn a programmer with a clear error message.\n" ] }, { "cell_type": "code", "execution_count": 20, "id": "d2d22b7a", "metadata": {}, "outputs": [], "source": [ "def triple_dangerous(x):\n", " \"\"\" scales a number (supposedly)\n", " \n", " Args:\n", " x (float): input number (supposedly)\n", " \n", " Return:\n", " triple_x (float): scale * x\n", " \"\"\"\n", " return 3 * x\n" ] }, { "cell_type": "code", "execution_count": 24, "id": "3c1f2a46", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "333333" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# seems ok to me ...\n", "triple_dangerous(111111)\n" ] }, { "cell_type": "code", "execution_count": 25, "id": "78b9cd1f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'is this an appropriate input? is this an appropriate input? is this an appropriate input? '" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# what happened?!?!1\n", "triple_dangerous('is this an appropriate input? ')\n" ] }, { "cell_type": "code", "execution_count": 26, "id": "59639443", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'asdfasdfasdf'" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# oh yeah... strings * integers just repeates the string\n", "'asdf' * 3\n" ] }, { "cell_type": "markdown", "id": "a825c631", "metadata": {}, "source": [ "The output of `triple_dangerous()` should be a number, but its a string! The string will head off to some other part of our program and break it ... and we'll have to trace the problem back here. \n", "\n" ] }, { "cell_type": "markdown", "id": "51208d9a", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## `assert` to validate function inputs (part 2)\n" ] }, { "cell_type": "code", "execution_count": 27, "id": "5fe853b7", "metadata": {}, "outputs": [], "source": [ "def triple_safe(x):\n", " \"\"\" scales a number (supposedly)\n", " \n", " Args:\n", " x (float): input number (supposedly)\n", " \n", " Return:\n", " scaled_x (float): scale * x\n", " \"\"\"\n", " # check that x is a number\n", " assert type(x) == int or type(x) == float, 'int or float required'\n", " \n", " return 3 * x\n" ] }, { "cell_type": "code", "execution_count": 30, "id": "9e8e6a66", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "33333" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "triple_safe(11111)" ] }, { "cell_type": "code", "execution_count": 31, "id": "5d186968", "metadata": { "scrolled": false }, "outputs": [ { "ename": "AssertionError", "evalue": "int or float required", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[31], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# its nice that this breaks in a way which is easy to understand now, right?\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[43mtriple_safe\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mIm not sure a string is an appropriate input to this function ...\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", "Cell \u001b[0;32mIn[27], line 11\u001b[0m, in \u001b[0;36mtriple_safe\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\" scales a number (supposedly)\u001b[39;00m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;124;03m\u001b[39;00m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;124;03mArgs:\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[38;5;124;03m scaled_x (float): scale * x\u001b[39;00m\n\u001b[1;32m 9\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 10\u001b[0m \u001b[38;5;66;03m# check that x is a number\u001b[39;00m\n\u001b[0;32m---> 11\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28mtype\u001b[39m(x) \u001b[38;5;241m==\u001b[39m \u001b[38;5;28mint\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mtype\u001b[39m(x) \u001b[38;5;241m==\u001b[39m \u001b[38;5;28mfloat\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mint or float required\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 13\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;241m3\u001b[39m \u001b[38;5;241m*\u001b[39m x\n", "\u001b[0;31mAssertionError\u001b[0m: int or float required" ] } ], "source": [ "# its nice that this breaks in a way which is easy to understand now, right?\n", "triple_safe('Im not sure a string is an appropriate input to this function ...')\n" ] }, { "cell_type": "markdown", "id": "9d9e6d7d", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# When should I validate inputs to my function?\n", "\n", "Doing it all the time is rather cumbersome ... though not doing it at all is dangerous.\n", "\n", "Validate inputs which:\n", "- might commonly be misunderstood\n", "- would cause \"silent\" errors\n", " - the function returns something inappropriate without warning user\n", "- its very important that your function works as intended\n", " - is your software for an ICA or a pacemaker?\n" ] }, { "cell_type": "markdown", "id": "405f1d61", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Test Cases: `assert` to test a function behavior (part 1)\n", "\n", "Does the function above work? Until we test it, we shouldn't be so sure ...\n" ] }, { "cell_type": "code", "execution_count": 33, "id": "ee7f564c", "metadata": {}, "outputs": [], "source": [ "def alpha_sort_list(list_in):\n", " \"\"\" sorts a list, alphabetically (regardless of case)\n", " \n", " Args:\n", " list_in (list): list of strings\n", " \n", " Return:\n", " list_out (list): list of strings, alpha sorted\n", " \"\"\"\n", " \n", " return sorted(list_in)\n" ] }, { "cell_type": "markdown", "id": "6e4f98d1", "metadata": {}, "source": [ "A **test case** is a set of inputs and outputs to a function with our intended behavior:\n", "\n", "case0:\n", "- input: `list_in=['Bruno', 'Callum', 'Eliana']`\n", "- expected output: `['Bruno', 'Callum', 'Eliana']`\n", "\n", "case1:\n", "- input: `list_in=['Bruno', 'callum', 'Eliana']`\n", "- expected output: `['Bruno', 'callum', 'Eliana']`\n" ] }, { "cell_type": "code", "execution_count": 34, "id": "2a6ee39f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Bruno', 'Callum', 'Eliana']" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# test case0: works\n", "alpha_sort_list(list_in=['Bruno', 'Callum', 'Eliana'])\n" ] }, { "cell_type": "code", "execution_count": 35, "id": "4590ad0e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Bruno', 'Eliana', 'callum']" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# test case1: doesn't work!\n", "alpha_sort_list(list_in=['Bruno', 'callum', 'Eliana'])\n" ] }, { "cell_type": "code", "execution_count": 36, "id": "cffbff60", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# why doesn't test case 1 work? capitalization matters with string comparisons\n", "'Z' < 'a'\n" ] }, { "cell_type": "markdown", "id": "25cd8c02", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Test Cases: `assert` to test a function behavior (part 2)\n", "\n", "It was cumbersome to manually test like that ... lets use an `assert` instead\n" ] }, { "cell_type": "code", "execution_count": 37, "id": "22320c19", "metadata": { "scrolled": true }, "outputs": [ { "ename": "AssertionError", "evalue": "", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[37], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m alpha_sort_list([\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mEliana\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCallum\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mBruno\u001b[39m\u001b[38;5;124m'\u001b[39m]) \u001b[38;5;241m==\u001b[39m [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mBruno\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCallum\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mEliana\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m alpha_sort_list([\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mEliana\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcallum\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mBruno\u001b[39m\u001b[38;5;124m'\u001b[39m]) \u001b[38;5;241m==\u001b[39m [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mBruno\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcallum\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mEliana\u001b[39m\u001b[38;5;124m'\u001b[39m]\n", "\u001b[0;31mAssertionError\u001b[0m: " ] } ], "source": [ "assert alpha_sort_list(['Eliana', 'Callum', 'Bruno']) == ['Bruno', 'Callum', 'Eliana']\n", "assert alpha_sort_list(['Eliana', 'callum', 'Bruno']) == ['Bruno', 'callum', 'Eliana']\n" ] }, { "cell_type": "markdown", "id": "1d7ef492", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# In Class Activity B\n", "\n", "Not only do test cases validate that your function works, they specify its behavior! By studying the given test cases, you can fully understand what the function should be doing.\n", "\n", "For example, after studying the test cases, you can complete the `evaluate_rps()` function below, which evaluates a round of [rock, paper, scissors](https://en.wikipedia.org/wiki/Rock_paper_scissors). Be sure to [document your code:\n", "](https://course.ccs.neu.edu/ds2500/python_style.html):\n", "- function docstring\n", "- comments\n", "- \"chunks\" of code which do similar things\n", "- variable names which are short and descriptive\n", "\n", "++ If you're done early, see if you can simplify your implementation as much as possible. I found an early return statement (a return in some if block where the function continues afterwards) to be helpful here.\n" ] }, { "cell_type": "code", "execution_count": 38, "id": "f26a7acb", "metadata": {}, "outputs": [], "source": [ "def evaluate_rps(user0_rps, user1_rps):\n", " # your docstring goes here!\n", " \n", " # validate proper inputs given\n", " rps_tuple = 'rock', 'paper', 'scissors'\n", " assert user0_rps in rps_tuple, 'invalid user0 input' \n", " assert user1_rps in rps_tuple, 'invalid user1 input'\n", " \n", " if user0_rps == user1_rps:\n", " # tie\n", " return -1\n", " \n", " \n" ] }, { "cell_type": "code", "execution_count": 39, "id": "f9ed76cb", "metadata": {}, "outputs": [ { "ename": "AssertionError", "evalue": "", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[39], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# paper beats rock\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m evaluate_rps(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpaper\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mrock\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m evaluate_rps(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mrock\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpaper\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# scissors beats paper\u001b[39;00m\n", "\u001b[0;31mAssertionError\u001b[0m: " ] } ], "source": [ "# paper beats rock\n", "assert evaluate_rps('paper', 'rock') == 0\n", "assert evaluate_rps('rock', 'paper') == 1\n", "\n", "# scissors beats paper\n", "assert evaluate_rps('scissors', 'paper') == 0\n", "assert evaluate_rps('paper', 'scissors') == 1\n", "\n", "# rock beats scissors\n", "assert evaluate_rps('rock', 'scissors') == 0\n", "assert evaluate_rps('scissors', 'rock') == 1\n", "\n", "# ties\n", "assert evaluate_rps('scissors', 'scissors') == -1\n", "assert evaluate_rps('rock', 'rock') == -1\n", "assert evaluate_rps('paper', 'paper') == -1\n" ] } ], "metadata": { "celltoolbar": "Slideshow", "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.10.6" } }, "nbformat": 4, "nbformat_minor": 5 }