Learn Python Series (#8) - Handling Tuples

in #utopian-io6 years ago (edited)

Learn Python Series (#8) - Handling Tuples

python_logo.png

What Will I Learn?

  • You will learn how to create tuples,
  • access them,
  • iterate over them and
  • return them.
  • Also you will learn, that tuples are immutable, sometimes causing the need for some workarounds
  • and that there are use cases when precisely the tuple immutability is very convenient.

Requirements

  • A working modern computer running macOS, Windows or Ubuntu
  • An installed Python 3(.6) distribution, such as (for example) the Anaconda Distribution
  • The ambition to learn Python programming

Difficulty

Intermediate

Curriculum (of the Learn Python Series):

Learn Python Series (#8) - Handling Tuples

In this Learn Python Series episode we will be reviewing the built-in Python data type tuple. You will learn how to create tuples, access them, iterate over them and return them. Also you will learn, that tuples are immutable, causing the need for some workarounds in case you still need to change the contents of a tuple, but you'll also learn that there are use cases when precisely the immutability is very convenient.

In two previous episodes we've been discussing handling lists, and a tuple is somewhat similar to a list, in that they are sequences of data as well. However, tuples are immutable, where lists are not.

Creating tuples

Creating a tuple using () and ,

A tuple consists of a series of comma separated values. Output tuples are wrapped in parentheses (), although that's not a necessity for defining input tuples. For example, the following notations are all correct:

# An emty tuple created with parentheses
tup_x = ()
print(type(tup_x), tup_x)
# <class 'tuple'> ()

# A tuple created without using enclosed parentheses
tup_y = 1, 2, 3, 4
print(type(tup_y), tup_y)
# <class 'tuple'> (1, 2, 3, 4)
# ... but the output of this tuple does have
# wrapping parentheses

# Please note the trailing comma
# meaning tup_z is NOT a string but a tuple
tup_z = 'Hello',
print(type(tup_z), tup_z)
# <class 'tuple'> ('Hello',)
<class 'tuple'> ()
<class 'tuple'> (1, 2, 3, 4)
<class 'tuple'> ('Hello',)

Nota bene: Please note that in case a tuple needs to be constructed that only has one item in it, using only parentheses is not enough: the trailing comma needs to be added in order to construct a tuple. For example:

int_1 = (1)
print(type(int_1), int_1)
# <class 'int'> 1

tup_1 = 1,
print(type(tup_1), tup_1)
# <class 'tuple'> (1,)
<class 'int'> 1
<class 'tuple'> (1,)

Creating a tuple from a sequence of values is also called tuple packing and the reverse operation when the tuple is on the right hand side of an assignment, is also possible and is called sequence unpacking. Please note that in order to unpack a tuple sequence, on the left side side must be as many variables as there are elements contained in the right hand side tuple.

For example:

# tuple packing, creating a tuple from a series
my_tuple = ('Hello', 'there', 'everybody')
print(type(my_tuple), my_tuple)
# <class 'tuple'> ('Hello', 'there', 'everybody')

# The other way around, unpacking a tuple
word1, word2, word3 = my_tuple
print(word1)
print(word2)
print(word3)
# Hello
# there
# everybody
<class 'tuple'> ('Hello', 'there', 'everybody')
Hello
there
everybody

Creating a tuple using tuple()

You can also create a tuple using the tuple() method, which actually converts an iterable to a tuple (unless no argument is passed to tuple() which constructs an empty tuple). Like so:

empty_tup = tuple()
print(type(empty_tup), empty_tup)
# <class 'tuple'> ()

tup_a = tuple([1, 2, 3])
print(type(tup_a), tup_a)
# <class 'tuple'> (1, 2, 3)

tup_b = tuple('Hello')
print(type(tup_b), tup_b)
# <class 'tuple'> ('H', 'e', 'l', 'l', 'o')
<class 'tuple'> ()
<class 'tuple'> (1, 2, 3)
<class 'tuple'> ('H', 'e', 'l', 'l', 'o')

Accessing tuple values

You can access individual tuple values via index and slicing using the [] square bracket notation, like so:

# Access via index
my_tuple = ('Hello', 'there', 'everybody', 'how', 'are', 'you', 'doing')
print(my_tuple[0])
# Hello

# Access via slice
print(my_tuple[2:len(my_tuple)])
# ('everybody', 'how', 'are', 'you', 'doing')
Hello
('everybody', 'how', 'are', 'you', 'doing')

Nested tuples

Tuples may consist of a sequence of compounded data types, such as lists, dictionaries, and other tuples as well. Because of that, a tuple could be nested inside another tuple.

Creating a nested tuple

To create a nested tuple, simply list the variables of the existing tuples in a comma separated sequence, like so:

# Nesting 3 tuples into one new tuple
tup_a = (1,2,3)
tup_b = (4,5,6)
tup_c = (7,8,9)
tup_tot = tup_a, tup_b, tup_c
print(tup_tot)
# ((1, 2, 3), (4, 5, 6), (7, 8, 9))
((1, 2, 3), (4, 5, 6), (7, 8, 9))

Accessing a nested tuple

In order to access the values contained inside a nested tuple, please keep in mind that each of the nested tuples contains its own identity, and that the "outer tuple" doesn't "care" for what's contained inside its direct elements.

The size (length) of tup_tot is 3 because it contains 3 tuples:

print(len(tup_tot))
# 3
3

To access, for example, the first (index 0) element of the outer tuple, use a single squared bracket notation:

print(tup_tot[0])
# (1, 2, 3)
(1, 2, 3)

And to access, for example, the first (index 0) element of the first inner tuple, use a double squared index notation:

print(tup_tot[0][0])
# 1
1

Iterating over a nested tuple

Iterating over a nested tuple, is like "peeling off" an onion: for each "element layer" use another for loop and execute your code. A very simple double for loop example:

for tup in tup_tot:
    for i in tup:
        print(i, end=' ')
        
# 1 2 3 4 5 6 7 8 9 
1 2 3 4 5 6 7 8 9 

Using a tuple as a return value

In Python, strictly speaking, a function can only return one value. But that value could be a tuple, and therefore a comma-separated list of multiple values. The returned value can be assigned to one variable, of type tuple, or it can be unpacked as multiple variables as long as the variable count is the same as the amount of values the packed tuple contains. For example:

# A simple function returning a tuple
def odd_even_splitter(my_nums):
    odd = []
    even = []    
    for num in my_nums:
        if num%2 == 0:
            even.append(num)
        else:
            odd.append(num)
    return odd, even


# the `result` variable is a tuple 
# that contains 2 list elements
result = odd_even_splitter(range(10))
print(type(result), result)
# <class 'tuple'> ([1, 3, 5, 7, 9], [0, 2, 4, 6, 8])


# unpacked, `odd` and `even` are both lists
odd, even = odd_even_splitter(range(5,15,3))
print(type(odd), odd)
# <class 'list'> [5, 11]
print(type(even), even)
# <class 'list'> [8, 14]
<class 'tuple'> ([1, 3, 5, 7, 9], [0, 2, 4, 6, 8])
<class 'list'> [5, 11]
<class 'list'> [8, 14]

Some tuple immutability workarounds

As mentioned, tuples are immutable, meaning you can't change them:

  • you cannot add elements to a tuple, there is no append() or insert() or extend() method like lists have;
  • you cannot remove elements from a tuple, there is no pop() or clear() for example;
  • you cannot modify values on existing tuple elements, tuples do not support item assignment.

There are however workarounds by (temporarily) changing a tuple to (for example) a list or to create a new tuple from one or more other tuples.

Tuple concatenation

Using the + operator, a new tuple can be formed by concatenating ("glueing") multiple tuples. For example:

# Forming a new tuple from tuple concatenation
tup_left = (1,2,3)
tup_right = (4,5,6)
tup_tot = tup_left + tup_right
print(tup_tot)
(1, 2, 3, 4, 5, 6)

Tuple repetition

Using the * operator, a new tuple can be constructed by repeating its elements.

# Forming a new tuple from tuple repetition
tup_base = ('a', 'b', 'c')
tup_tot = tup_base * 4
print(tup_tot)
# ('a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c')
('a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c')

Tuple slicing

If you want to remove elements from a tuple, you can create a new tuple and slice the elements you want removed from the original tuple, like so:

tuple_orig = ('a', 'b', 'c', 'd', 'e')

# Remove the 'a' from the tuple via slicing
# and creating a new tuple:
tuple_sliced = tuple_orig[1:]
print(tuple_sliced)
# ('b', 'c', 'd', 'e')
('b', 'c', 'd', 'e')

Tuple-to-list conversion

Since lists, as opposed to tuples, are mutable, and have many methods to use on them, it's possible to convert a tuple to a list, then apply the list methods you need, and finally convert the list back to a new tuple.

# Suppose we have a tuple and
# another element we want to insert in the middle
tuple_base = ('a', 'b','d', 'e')
extra = 'c'

# first convert the tuple to a list
temp_list = list(tuple_base)

# then insert the element
temp_list.insert(2, extra)

# And convert back to a tuple
tuple_new = tuple(temp_list)
print(type(tuple_new), tuple_new)
# <class 'tuple'> ('a', 'b', 'c', 'd', 'e')
<class 'tuple'> ('a', 'b', 'c', 'd', 'e')

The reversed() function

The built-in Python function reversed() takes any type of data sequence, including a tuple, and returns an iterator object with the tuple elements in reversed order.

tup = (1,2,3,4,5)
rev = reversed(tup)
for el in rev:
    print(el, end=' ')
5 4 3 2 1 

Of course in order to reverse the order of a tuple and have a new tuple, you can either wrap the above mentioned reversed() method inside another tuple. Please note that trying to use conversion to list and on that use the reverse() list method would not work because the reverse() list method doesn't return a value, which you can then (obviously) also not convert back to a tuple.

# Converting the `reversed()` iterator to a tuple
tup = (1,2,3,4,5)
rev = tuple(reversed(tup))
print(type(rev), rev)
# <class 'tuple'> (5, 4, 3, 2, 1)
<class 'tuple'> (5, 4, 3, 2, 1)
<class 'NoneType'> None

Why prefer using a tuple over a list or a string?

Hopefully, it's now clear that different kind of sequences data types (tuples, lists and strings) can be used interchangeably. But since lists "seem" more flexible, being mutable, than tuples, why use a tuple?

  • first of all, tuples allow for "returning multiple values", and returning a tuple of values is syntactically easy to do as well. Personally I find returning tuples very convenient in lots of use cases. Returning a list or a dictionary (that include multiple values) is an option as well but can be more tedious to construct;
  • second, since dictionaries allow immutable data types as their key in case you want to use a sequence as a dictionary key, then lists are a No-Go. (However, using a tuple as a dictionary key causes a bit of problems when converting a dictionary to JSON, as we'll see later on in the Learn Python Series);
  • and third, in case you are using a function that takes a sequence as an argument to a function, using tuples guarantees the order (in case that guarantee is a necessity).

What did we learn, hopefully?

That tuples are another built-in sequence data type, and are somewhat like lists but immutable, meaning you can't easily change the tuple element values. That immutability aspect is sometimes very convenient and there are therefore some use cases where using tuples is prefered over using lists.

Thank you for your time!



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

Thank for an amazing explenation. I am getting back up to speed.

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

Hey @scipio I am @utopian-io. I have just upvoted you!

Achievements

  • Seems like you contribute quite often. AMAZING!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

Thank you @utopian-io ! Beep! Beep!

Well written. Sent me back to your earlier installments in this tutorial.

Cool! There are already 9 Learn Python Series episodes published and many more will follow!

Coin Marketplace

STEEM 0.16
TRX 0.13
JST 0.027
BTC 60841.72
ETH 2603.92
USDT 1.00
SBD 2.56