{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Lecture 3\n", "\n", "- Learn about collections of variables: data structures \n", "\n", "- Learn about _objects_ \n", "- Learn about _methods_ which allow you to do things to _objects_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Data Structures\n", "\n", "Now that we know about variables, it would be handy to group them together in some way. In Python there are many ways to do this: **lists, tuples**, **dictionaries**, and **sets**, among others. These group arbitrary variables and/or values together, (e.g., strings and integers and floats) in containers.\n", "\n", "We'll go through some of the various data structures, starting with **lists**.\n", "\n", "### Lists \n", "\n", "- Lists are denoted with [ ] and can contain any arbitrary set of elements, including other lists!\n", "\n", "- Elements in the list are referenced by an index number (**index**). Similar to the strings we encountered in the last lecture, the indices begin at 0. Remember that this is different from what you may be used to, which would be that the first element is index 1; in Python, the first element is **index** 0.\n", "\n", "- You can count from the end to the beginning by starting with -1 (the last item in the list), -2 (second to last), etc. \n", "\n", "- Lists have _methods_ that allow items to be sorted, deleted, inserted, sliced, counted, concatenated, replaced, added on to, etc.\n", "\n", "\n", "Let's take a look at some examples: \n", "\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['a', 2.0, '400', 'spam', 42, [24, 2]]\n" ] } ], "source": [ "mylist=['a',2.0,'400','spam',42,[24,2]] # defines a list\n", "print (mylist) # prints the list\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But if we want to print out the third **element** in list we use **index** number 2: " ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "400\n" ] } ], "source": [ "print (mylist[2]) # print the third element in the list (starting from zero)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And similarly, to print the fourth **element** we use **index** number -1:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[24, 2]\n" ] } ], "source": [ "print (mylist[-1]) # print the last element\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But if you want to print, say, the last three **elements**, you can't do this: " ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['spam', 42]\n" ] } ], "source": [ "print (mylist[-3:-1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is because the slice **list[begin:end]** means from **index = begin** up to and _not including_ **index=end**. To actually slice out the last three **elements**, you can do it this way:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['spam', 42, [24, 2]]\n" ] } ], "source": [ "print (mylist[-3:])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unlike strings, you can change list **elements** \"in place\". By \"in place\" we mean that you don't have to assign it to a new variable name; the list gets change \"in place\":" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['a', 26.3, '400', 'spam', 42, [24, 2]]\n" ] } ], "source": [ "mylist[1]=26.3 # replaces the second element\n", "print (mylist)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To delete, for example, the 4th **element** from a list, you can use the command **del**:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['a', 26.3, '400', 42, [24, 2]]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "del mylist[3] # deletes the fourth element \n", "mylist" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Like strings, you can slice out a chunk of the middle of a list and assign it to another variable:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[26.3, '400']\n" ] } ], "source": [ "newlist=mylist[1:3] # takes the 2nd and third values and puts in newlist\n", "#note it takes out up to but not including the last item number \n", "print (newlist)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Making copies of lists behaves in ways you might not expect if you are coming from other programming languages. We will learn more about copies of lists in later lectures, but here are some pro tips for now. \n", "\n", "You can assign a list to another variable name like this: " ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "mycopy=mylist\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**mycopy** is now a _copy_ of **mylist**. But it is inextricably bound to the original, so if I change one, I change the other. This type of copy is known as a _shallow copy_. " ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['a', 26.3, 'new', 42, [24, 2]]\n", "['a', 26.3, 'new', 42, [24, 2]]\n" ] } ], "source": [ "mylist[2]='new'\n", "print (mylist)\n", "print (mycopy)\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "See how _mycopy_ was changed when we changed _mylist_?\n", "\n", "To spawn a list that is an independent object (a _deep copy_), you can do this: " ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['a', 26.3, 'new', 42, [24, 2]]\n" ] }, { "data": { "text/plain": [ "['a', 26.3, 1003, 42, [24, 2]]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mycopy=mylist[:]\n", "# now try changing mylist... \n", "mylist[2]=1003\n", "print (mycopy) # if there are two things to print, use 'print'\n", "mylist # otherwise only prints the last one" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "See how _mycopy_ stayed the way it was, even as _mylist_ changed? \n", "\n", "There are more ways to make shallow and deep copies of Python objects which we will explore further in Lecture 10." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Objects in Python\n", "\n", "An object in Python is a collection that has _attributes_ and _methods_. The list variable _mylist_ is an example of an object - a _list_ object. In fact they are **classes** which we will learn more about in later lectures, but I just wanted to mention them here. \n", "\n", "So what is so special about _objects_? Python objects have _methods_ which allow you to do things to the object. Methods have the form:\n", "\n", "**object.method( )**\n", "\n", "or \n", "\n", "**object.method(argument1, argument2,...)**\n", "\n", "Here, **argument1** is something that can get passed into the method. \n", "\n", "Let's look at a few examples starting with the **.append( )** method for lists (which appends something (the **argument**) to the end of a list). " ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['a', 26.3, 1003, 42, [24, 2], 'why not?']\n" ] } ], "source": [ "mylist.append('why not?') \n", "# append() is a method of lists that appends the argument 'why not?' to the list\n", "print (mylist)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**.count( )** is another method. Let's see what it does: " ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2\n" ] } ], "source": [ "mylist.append('why not?') \n", "print (mylist.count('why not?') )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The method **.count( )** returns the number of times the **argument** occurs in the list. \\[NB: the **argument** is the stuff inside the parentheses of the method - in this case 'why not?'.\\] \n", "\n", "Another very handy list method is the **.index( )** method. It returns the **index** of the desired argument in the list. For example, if we wanted to know what the index of the element, 42, is in _mylist_, we would type: " ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3\n" ] } ], "source": [ "print (mylist.index(42) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These are just a few of the methods for lists. To view all of the methods for a list object, see:\n", "https://docs.python.org/tutorial/datastructures.html" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Making lists\n", "\n", "For example, we could make this list: \n", "\n" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['naughty', 'nice']\n", "['naughty', 'nice']\n" ] } ], "source": [ "santas_list=['naughty','nice']\n", "print (santas_list)\n", "# and check it twice\n", "print (santas_list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### More useful lists: \n", "\n", "Earlier, we made a list by defining a variable with square brackets. We added to that list with **append( )**. Another way to generate a list is to use **range( )**, which is one of the python _built-in functions_ we mentioned in Lecture 2. The function **range( )** is a _list generator_ and can be used to generate a list of integers between two numbers, the _start_ and _end_, where each number is separated by a specified interval. You can make a lisa from the generator like so: **list(range(start,end,interval))**. Note that **range**, like **list** slicing, goes up to but does not include _end_. " ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[2, 6, 10, 14, 18]\n" ] } ], "source": [ "# creates a list from 2 to 20 (not including 20!) at intervals of 4\n", "numlist=list(range(2,20,4)) \n", "print (numlist)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tuples\n", "\n", "**Tuples** are another important object in Python that are similar to lists, but have important differences. They are denoted by parentheses ( ) and consist of values separated by commas. \n", "Like lists, they can contain different elements, but unlike lists, the elements cannot be changed in place. Their primary use is to pass information into and out of programs as we shall see in the coming lectures. \n", "\n", "\n", "Similar to both lists and strings, you can slice, concatenate, etc. For more see: \n", " \n", " http://docs.python.org/tutorial/datastructures.html#tuples-and-sequences\n", "\n", "Here is one way to generate a tuple: \n" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(1234, 2.0, 'hello')\n" ] } ], "source": [ "t = 1234, 2.0, 'hello'\n", "print (t)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or, the other way around:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1234\n", "2.0\n", "hello\n" ] } ], "source": [ "a,b,c=t\n", "print (a)\n", "print (b)\n", "print (c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can access an element in a tuple by using the index number, exactly like a list." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1234" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But, you can't change it: " ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "'tuple' object does not support item assignment", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mt\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'haha'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mprint\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" ] } ], "source": [ "t[0]='haha'\n", "print (t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sets\n", "\n", "There are more data structures that comes in handy and one is the _set_. They are denoted with curly braces { }. A set \"contains an unordered collection of unique and immutable objects.\" \n", "\n", "You can create _sets_ in several ways. The first would be the use the python built-in **set( )** function on a list: " ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{42, 'ocelot', 'spam'}" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S1=set(['spam','ocelot',42])\n", "S1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice how the order changed. \n", "\n", "Also, notice what happens if we violate the \"unique\" part of the definition:\n", "\n" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'ocelot', 'spam'}" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S2=set(['spam','ocelot','ocelot'])\n", "S2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Only one of the ocelots made it into the set. [By the way, \"ocelot\" is another Monty Python joke - look it up if you like.] \n", "\n", "Sets contain immutable objects, but they themselves can be changed. For a more complete list of methods see: \n", "\n", "https://www.python-course.eu/python3_sets_frozensets.php\n", "\n", "\n", "But here are a few:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'ocelot', 42, 'spam'}\n", "{'ocelot', 42, 'chocolate', 'spam'}\n" ] } ], "source": [ "# add\n", "print (S1) \n", "S1.add('chocolate')\n", "print (S1)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "set()" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# clear \n", "S2.clear() \n", "S2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "See how S2 is now just an empty set object _set( )_.\n", "\n", "Now let's try copying **S1**. " ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'ocelot', 42, 'chocolate', 'spam'}\n", "set()\n", "{'ocelot', 42, 'chocolate', 'spam'}\n" ] } ], "source": [ "# copy\n", "S2=S1.copy()\n", "print (S2)\n", "S1.clear()\n", "print (S1)\n", "print (S2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "the **.copy( )** method for sets does not work like copying lists - it made an independent object **S2** which did not clear when **S1** got cleared. \n", "\n", "**.difference** is another handy method - it can be used to find what is different about two sets. " ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{42}" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# difference\n", "S1=set(['spam','ocelot',42])\n", "S2=set(['spam','ocelot'])\n", "S1.difference(S2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But - you say - you want to know what is the **same** in two sets. For that, use the **.intersection** method. " ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'ocelot', 'spam'}" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# intersection\n", "S1.intersection(S2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is a nice short cut for this:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'ocelot', 'spam'}" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S1&S2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, you can define a set just using curly braces:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{42, 'Ni', 'spamalot'}" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S3={42,'spamalot','Ni'}\n", "S3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "'Ni' is another joke from Monty Python and the Holy Grail where there were some characters calling themselves the \"Knights who say Ni!\". \"42\" is not from Monty Python, but from the Hitch Hikers Guide to the Galaxy - but people who like Monty Python also like the Hitch Hiker's Guide. By the way, \"42\" is the answer to \"What is the meaning of life, the universe, and everything?\". Now you know. " ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "### Assignment #1\n", "\n", "- Create a jupyter notebook. \n", "- Rename the notebook (under File menu) with the format YourLastname_FirstInitial_HW_01. For example, **Cych_B__HW_01**\n", "- Save the notebook (click on the disk icon in the menu bar)\n", "- Create a markdown block in which you will describe what the notebook does. \n", "- Make a code block that creates a list called _planets_\n", " - append all the planets to the list.\n", " - make a deep copy of your _planets_ list (with a different name). \n", " - print the element at **index** 2 in your _planets_ list. \n", " - set the element at **index** 2 in your copy to 'X'\n", " - print the element at **index** 2 in both lists (_planets_ and your copy)\n", " - append the element that you just changed to the end of your copy.\n", " - use the help function to find out what the _built-in_ function **len()** does.\n", "- Make another code block that creates a list called, e.g., _numList_, using **range( )** that has 8 values starting with 1. \n", " - print out your new list\n", " - Create a **set** from each of the three lists (_planets_, your copy of _planets_ and your new list of numbers. \n", " - Find the elements in common between the two planets lists _planets_ and your copy. \n", " - find the elements in common between _planets_ and your new numbers list. \n", "\n", "Your notebook must have the correct name, be fully commented and run as expected to receive full credit. \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.6.7" } }, "nbformat": 4, "nbformat_minor": 1 }