{"id":334,"date":"2021-05-15T17:18:04","date_gmt":"2021-05-15T16:18:04","guid":{"rendered":"https:\/\/glennrowe.net\/programmingpages\/?p=334"},"modified":"2021-05-31T12:14:33","modified_gmt":"2021-05-31T11:14:33","slug":"tuples","status":"publish","type":"post","link":"https:\/\/glennrowe.net\/programmingpages\/2021\/05\/15\/tuples\/","title":{"rendered":"Tuples"},"content":{"rendered":"<p>A Python tuple is an ordered, immutable set of data items. By\u00a0<em>ordered<\/em>, we mean that the items in a tuple are stored in a definite order, not necessarily that they are sorted. By\u00a0<em>immutable,<\/em> we mean that the elements of a tuple cannot be altered or deleted, and the tuple itself cannot be extended or contracted.<\/p>\n<p>It might seem that a tuple is just a crippled version of a <a href=\"https:\/\/glennrowe.net\/programmingpages\/2021\/05\/11\/lists-the-basics\/\">list<\/a>, but in fact, it appears from documentation that tuples and lists are intended to be used in different applications. Although Python is dynamically typed, so that data of different types can be mixed together within both lists and tuples, a list is primarily intended to be used for collections of data of the same type, much like an array in other languages. A tuple, on the other hand, is primarily intended to store a collection of related items, such as the name, date of birth and nationality of a person. Thus a tuple might be used to store data on one particular person, while data for all persons in a group might be stored as a list of tuples. Viewed in this way, a Python tuple is similar to a struct in C# or C++ (although data in structs <em>can<\/em> be altered, so the comparison isn&#8217;t entirely accurate).<\/p>\n<p>A tuple can be defined by listing the data fields separated by commas and (optionally) enclosed in parentheses. Open a Python <a href=\"https:\/\/glennrowe.net\/programmingpages\/2021\/04\/21\/installing-visual-studio-for-python\/\">PowerShell<\/a> and try the following:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup = 1, 2, 3\r\ntup<\/pre>\n<p>You&#8217;ll get (1, 2, 3) printed out. When displaying a tuple, the elements are always enclosed in parentheses, but the parentheses are optional when defining a tuple. Thus, we could have typed <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup = (1, 2, 3)<\/code> instead of the first line above.<\/p>\n<p>To create a tuple with a single element you can type either <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup = 1,<\/code> or <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup = (1,)<\/code>. The trailing comma is needed to tell Python that you want a tuple and not just a primitive int.<\/p>\n<h2>Accessing tuple elements<\/h2>\n<p>Although a tuple is immutable, we can access (in a read-only sense) its elements using the same subscripting and slicing syntax that we introduced in the discussion <a href=\"https:\/\/glennrowe.net\/programmingpages\/2021\/05\/11\/lists-the-basics\/\">lists<\/a>. Try the following in the PowerShell:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup = tuple(x for x in range(12))\r\ntup\r\ntup[6]\r\ntup[0:8]\r\ntup[8:0]\r\ntup[1:5:2]\r\ntup[::-1]\r\n\r\n<\/pre>\n<p>The first line uses the tuple constructor to create a tuple by using a\u00a0<em>generator<\/em>. This is similar to <a href=\"https:\/\/glennrowe.net\/programmingpages\/2021\/05\/12\/list-comprehension\/\">list comprehension<\/a> that we looked at earlier, but in the case of tuples, we need to explicitly use the constructor name rather than just enclosing the generator in parentheses. That is, <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup = (x for x in range(12))<\/code> won&#8217;t give you a tuple (try it!). It&#8217;s not an invalid statement though; rather it returns a generator object, which isn&#8217;t of much use here.<\/p>\n<p>Returning to the above example, line 2 produces the tuple (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11). Line 3 produces the seventh element <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup[6]<\/code>, which is 6 here. Line 4 returns a tuple consisting of elements 0 through 7 (remember that the &#8216;end&#8217; index is the index\u00a0<em>after<\/em> the last one included), so we get (0, 1, 2, 3, 4, 5, 6, 7). The expression <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup[8:0]<\/code> gives an impossible index range, so it returns an empty tuple <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">()<\/code>.<\/p>\n<p>Next, <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup[1:5:2]<\/code> starts at <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup[1]<\/code> and proceeds to <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup[4]<\/code> in steps of 2, so we get (1, 3). Finally, <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup[::-1]<\/code> starts at the end and proceeds backwards through tuple in steps of 1, so it returns the tuple in reverse order: (11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0).<\/p>\n<p>It&#8217;s important to note that, in all the cases where we used a slice (that is, one or two colons), the expression returns a\u00a0<em>new <\/em>tuple containing the desired elements. The original tuple is unchanged.<\/p>\n<h2>Joining tuples<\/h2>\n<p>Tuples can be joined using the + operator. Consider:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup = tuple(x for x in range(12))\r\nxup = tuple(x for x in range(12, 20, 2))\r\ntup\r\nxup\r\nyup = tup + xup\r\nyup\r\nyup += xup\r\n<\/pre>\n<p>This generates tup as the same tuple as before: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), and xup as the tuple starting at 12 and ending at 19, in steps of 2, so we have xup = (12, 14, 16, 18).<\/p>\n<p>The statement <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">yup = tup + xup<\/code> generates a new tuple consisting of xup joined onto the end of tup, so we have yup = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18).<\/p>\n<p>The last line might come as a surprise. It\u00a0<em>is<\/em> a valid statement, and if you print out yup afterwards, you&#8217;ll get (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 12, 14, 16, 18), so it seems that yup has been modified by appending another copy of xup. However, this statement doesn&#8217;t actually violate the immutability of tuples. What the statement <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">yup += xup<\/code> is doing is effectively the statement\u00a0 <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">yup = yup + xup<\/code>. The right-hand side generates a new tuple which is the concatenation of yup and xup, and then this new tuple is assigned to the variable yup. In other words, yup now points at a brand new tuple and the old version of yup is lost. Immutability is preserved.<\/p>\n<h2>Packing and unpacking<\/h2>\n<p>The statement <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup = 1, 2, 3<\/code> that we started with is an example of\u00a0<em>packing<\/em> data into a tuple. Tuples allow their contents to be\u00a0<em>unpacked<\/em> into individual variables as well. Consider:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup = 1, 2, 3\r\na, b, c = tup\r\na\r\nb\r\nc\r\n<\/pre>\n<p>Line 2 unpacks tup into 3 separate variables, so we have a = 1, b = 2 and c = 3 afterwards. Unpacking requires that the number of variables on the left-hand side exactly matches the number of elements in the tuple.<\/p>\n<h2>Tuples and lists<\/h2>\n<p>You can convert a tuple into a list and vice versa by using the corresponding constructor. For example:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tup = 1, 2, 3\r\ntupList = list(tup)\r\ntupList[1] = 9\r\ntup = tuple(tupList)\r\ntup\r\n<\/pre>\n<p>We create the tuple (1, 2, 3) and convert it the list <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">tupList<\/code>. Since lists are mutable, we can change its element 1 to 9, and then convert it back to a tuple, which now reads (1, 9, 3). Although this sort of thing is possible, it&#8217;s probably not the best program design, since it indicates that you&#8217;re not using the right data type (tuple vs list) in the first place.<\/p>\n<h2>Exercise<\/h2>\n<p>Write a program that asks the user to input a sequence of shopping items where each item has a name and a price. The data for each item should be stored in a tuple, and the program should maintain a list of these tuples. When the user enters &#8216;quit&#8217;, the program should then calculate and print the total cost of the items in the list.<\/p>\n<p>The cost of each item should be in the usual format of pounds and pence, or dollars and cents, so the numeric value of the cost will require 2 digits after the decimal point. Use the <a href=\"https:\/\/glennrowe.net\/programmingpages\/2021\/04\/28\/decimals\/\">Decimal data type<\/a> to store the cost.<\/p>\n<span class=\"collapseomatic \" id=\"id69f3265659ffc\"  tabindex=\"0\" title=\"See answer\"    >See answer<\/span><span id='swap-id69f3265659ffc'  class='colomat-swap' style='display:none;'>Hide answer<\/span><div id=\"target-id69f3265659ffc\" class=\"collapseomatic_content \">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">from decimal import *\r\nshopList = []\r\nwhile True:\r\n    item = input('Enter item\\'s name and price separated by a comma, or \\'quit\\': ')\r\n    if item == 'quit':\r\n        break\r\n    itemData = item.split(',')\r\n    itemTup = itemData[0], Decimal(itemData[1])\r\n    shopList += [itemTup]\r\ncost = Decimal('0.0')\r\nfor tup in shopList:\r\n    cost += tup[1]\r\nprint('Total cost =', cost)\r\n\r\n<\/pre>\n<p>After reading in the data on line 4, we check for &#8216;quit&#8217;. If we&#8217;re still adding an item, we split the input string on the comma on line 7, then store the two parts of the data in a tuple on line 8. Since a <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">Decimal<\/code> requires a string argument to store the value without roundoff error, we can pass <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">itemData[1]<\/code> directly to the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">Decimal<\/code> constructor. We then add <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">itemTup<\/code> to <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">shopList<\/code>, but note that we need to enclose <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">itemTup<\/code> in square brackets <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">[itemTup]<\/code> so that the tuple gets added as a single element to the list <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">shopList<\/code>. If we omitted the brackets, the individual elements of <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">itemTup<\/code> would be added to <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">shopList<\/code>, and not the tuple.<\/p>\n<p>After the user enters &#8216;quit&#8217;, control passes to the for loop on line 11, where we add up the costs of the items.<\/p>\n<\/div>\n<h2>Named tuples<\/h2>\n<p>Since one of the main uses of tuples is the creation of structured data types for storing data fields of mixed, but fixed, types, having to refer to the individual data fields by their index number can lead to obscure program code that is hard to read. There is a special type of tuple called the\u00a0<em>namedtuple<\/em> available in the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">collections<\/code> module. We won&#8217;t go into great detail here, but will give a simple example of how you can define and use a named tuple.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">from collections import *\r\nEmployee = namedtuple('Employee', ['name', 'age', 'nationality'])\r\nempList = []\r\nwhile True:\r\n    empData = input('Name, age, nationality (or quit): ')\r\n    if empData == 'quit':\r\n        break\r\n    empData = empData.split()\r\n    emp = Employee(empData[0], int(empData[1]), empData[2])\r\n    empList += [emp]\r\nprint('Employees\\'s names:')\r\nfor x in empList:\r\n    print(x.name)\r\n    \r\n\r\n<\/pre>\n<p>Line 1 imports the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">collections<\/code> module, which includes the definition of <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">namedtuple<\/code>. On line 2, we define a namedtuple called <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">Employee<\/code> (the object to the left of the =). The constructor for namedtuple takes 2 arguments. The first is a string which is the name of the data type (which we&#8217;re calling <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">Employee<\/code>). The second argument is a list of strings which define the names of the data fields in the tuple. Here, we&#8217;re storing the name, age and nationality of each employee. Note that, due to dynamic typing, we do\u00a0<em>not<\/em> define the data types of these data fields.<\/p>\n<p>The <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">while<\/code> loop on line 4 allows the user to enter the name, age and nationality of a number of employees. We&#8217;re not doing any error checking on the input, but in a real application you would, of course, need to do this.<\/p>\n<p>On line 9, we create an <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">Employee<\/code> namedtuple called <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">emp<\/code>, and store the name, age and nationality in this tuple. Line 10 adds the tuple to the master list <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">empList<\/code>. Note that we want each entry in <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">empList<\/code> to be a tuple, so we need to enclose <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">emp<\/code> in brackets, as <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">[emp]<\/code>. Otherwise, each element within <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">emp<\/code> would be added to empList as a separate item, and the namedtuple would be lost.<\/p>\n<p>Line 12 loops over the entries in <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">empList<\/code> to print out only the employees&#8217; names. Note that on line 13 we can refer to the data field by using its label &#8216;name&#8217; rather than having to use the index notation [0]. This makes the code clearer and easier to read.<\/p>\n<h2>Exercise<\/h2>\n<p>Rewrite the shopping list program from the first exercise so that it uses a namedtuple to store the name and cost for each item.<\/p>\n<span class=\"collapseomatic \" id=\"id69f326565a0fa\"  tabindex=\"0\" title=\"See answer\"    >See answer<\/span><span id='swap-id69f326565a0fa'  class='colomat-swap' style='display:none;'>Hide answer<\/span><div id=\"target-id69f326565a0fa\" class=\"collapseomatic_content \">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">from decimal import *\r\nfrom collections import *\r\nItem = namedtuple('Item', ['name', 'cost'])\r\nshopList = []\r\nwhile True:\r\n    item = input('Enter item\\'s name and price separated by a comma, or \\'quit\\': ')\r\n    if item == 'quit':\r\n        break\r\n    itemData = item.split(',')\r\n    itemTup = Item(itemData[0], Decimal(itemData[1]))\r\n    shopList += [itemTup]\r\ncost = Decimal('0.0')\r\nfor tup in shopList:\r\n    cost += tup.cost\r\nprint('Total cost =', cost)\r\n\r\n\r\n<\/pre>\n<p>The changes from the first version are:<\/p>\n<ul>\n<li>importing the collections module on line 2<\/li>\n<li>defining the Item namedtuple on line 3<\/li>\n<li>creating an Item tuple on line 10 to store the data for a single item<\/li>\n<li>using the name &#8216;cost&#8217; of the data field rather than its index number on line 14<\/li>\n<\/ul>\n<\/div>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A Python tuple is an ordered, immutable set of data items. By\u00a0ordered, we mean that the items in a tuple are stored in a definite order, not necessarily that they are sorted. By\u00a0immutable, we mean that the elements of a tuple cannot be altered or deleted, and the tuple itself cannot be extended or contracted. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-334","post","type-post","status-publish","format-standard","hentry","category-python","entry"],"_links":{"self":[{"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/posts\/334","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/comments?post=334"}],"version-history":[{"count":9,"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/posts\/334\/revisions"}],"predecessor-version":[{"id":351,"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/posts\/334\/revisions\/351"}],"wp:attachment":[{"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/media?parent=334"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/categories?post=334"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/tags?post=334"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}