In the previous passage of our cycle, we started talking about loops, which are how a program repeats a set of instructions. Executing a set of instructions multiple times is called an iteration. Iteration in programming is common. Computers are often used to automate repetitive tasks. Repeating identical or similar tasks without making mistakes is something computers do well and humans do poorly.

The more impatient readers are probably already waiting to cover the "for" loop, definitely the "number one" loop in any programming language. Before that happens, however, we'll sort out our knowledge of variables. We will discuss the assignment instruction and the rules for updating the variable value. Next, we'll look at Python's data types and introduce the concept of compound data. By the way, we'll find out how lists work — a type of data that would be a shame not to know. Without this knowledge, it would be difficult to cover not only the "for" loop, but also other important elements of programming. So … let's get to work.

Variables — how they work

We've already dealt with variables, remember? The variable is the name (label) you assign to an object, such as a list, or to user input:

a=['dog', 'cat', 'rabbit']     # variable assigned to the list

a=input()     # variable assigned to the input

Thanks to the assignment, we can then refer to the assigned element just using the variable name:

print(a)     # prints the contents of the list or the input provided by the user

To use the simplest of the simplest examples, a variable can be assigned to a number.

x=1    # is probably the simplest variable assignment you can think of

However, it is not as banal as it may seem at first. And it plays a very, very useful role in programming. Why? Well, because a variable can dynamically take different values: x = 1, x = 2, x = 3, etc. — that is, change the value. And this, without a doubt, will be useful to every programmer (including you)…

Updating variables

In Python, to create a variable, you simply assign a value to it. To make an assignment, use the "=" operator.

x=1    # we assigned the value 1 to the variable x.

This simple way of creating variables — by assigning values — is called creating variables on the fly. In many (more conservative) programming languages this is not allowed, and variables — to use them — must first be declared at the beginning of the program.

You can also assign a new value to a variable at any time:

x=1    # variable x is assigned the value 1

x=2    # now variable x is assigned the value 2, which replaces the previous value of this variable

Assigning a new value to a variable is called "reassignment" or "value update". We often update the value of a variable in such a way that the new value of the variable depends on the old one.

So instead of writing:

x=1

x=2

you write

x=1

x=x+1

which has the same effect (the value of the variable changes from 1 to 2)

x=x+1    means: get the current value of x, add one, then update x with the new value.

This way of updating a variable's value is generally more flexible than the previous one. You can apply it to any initial value of x (not necessarily 1).

x=8

x=x+1 (now the value of x will be 9)

Updating a variable by adding 1 is called incrementing a value; subtracting 1 is called decrementing the value.

Updating variable values versus loops

As you may have noticed, updating a variable's value works great for loops. For example, we used
i=i+1 in our while loop script which outputted the numbers 0 through 4.

In computer science, the act of repeating the same operation in a loop a predetermined number of times (or until a certain condition is met) is called iteration.

Increasing (or decreasing) the value of a variable in a loop multiple times is extremely useful in programming, it allows you to build sequences of numbers, recalculate sets of elements and perform many other useful operations.

Indexes

In programming languages, the variable we denote with a letter i is very often the so-called index. In a moment we will explain what this "index" is.

We need to start  again from Python data types. We said before that Python allows you to use three types of data: text, numbers, and Boolean data. Soon we will see that there are more data types in Python[1].

First, a trivial observation. The text data, expertly referred to as str (from the word string), differs in a certain way from numbers. How are they different? Well, they can be broken down into individual components: characters.

Be careful: digits, like letters, are characters. Combination of digits: e.g. 25 can represent a number or a two-element string. In Python, we distinguish a string from a number by enclosing the characters in an apostrophe: '25'

The characters can be letters, digits, and special characters, such as "underscore" or "asterisk"[2]. Consecutive characters that make up the string can be numbered:

As you can see, the string game_01 consists of seven characters. In the table, we have numbered them in the bottom row. Numbering of the elements of a sequence is called indexing, and the number assigned to the element is called its index.

Question: Why have we numbered the characters in the string from 0 to 6 — and not from 1 to 7? Well, it's such a fairly specific Python requirement to number elements from zero, frankly a little annoying.

Contrary to strings, numerical data (numbers) cannot be broken down into constituent elements (for example, the number 345 is not a simple composition of the elements 3–4‑5)[3].

What is the conclusion?

The observation that the string — as an element — consists of smaller sub-elements: characters, is a very important observation.

In Python, data consisting of an ordered sequence of smaller elements is called a sequence.

Strings represent a type of data called a sequence.

A sequence is an ordered collection of elements. Sequential types are qualitatively different from numeric types because they are compound data types — that is, they are made up of smaller pieces.

An ordered collection means that the order of its elements is significant (that is, it cannot be changed unintentionally).

Many interesting operations can be performed on the sequences:

  • calculating the length of the sequence, ie the number of elements it contains;
  • numbering elements (so-called indexing);
  • referring to a single item in the sequence — or to several selected items;
  • searching for items in sequence, delete items or add new ones.

The numbers don't want to be worse

A single number (as said) cannot form a sequence. However, you can create a sequence of numbers in Python. The command (function) range is used for this.

range(n)    # generates a sequence of numbers from zero to n‑1

Lest it look too "rose-colored", the sequence generated by range cannot be printed "straight ahead"; we'll (almost always) use range in a loop and only then will it work properly. If you don't use a loop, but still  want to see the effect of range on the screen, wrap the range command with list()

print(list(range(6)))

Output: [0, 1, 2, 3, 4, 5]

range is a great tool and we'll be using it frequently. range does not necessarily start counting from zero, and the increment does not have to be "1". You can easily modify this function to, for example, count from 8 to 28 in "every two" increments, and even to count "backwards"[4].

String of characters? It is not enough!

Let's recall once again: string is a sequence of single characters. Single — we emphasize!
(also remember that in Python we put them in quotation marks).

For example, the word 'hello' consists of 5 characters: h, e, l, l, o. And the phrase 'hello boy!' consists of 10 characters (including space and exclamation mark).

Probably everyone is asking themselves now: sequence — great thing… But a sequence of single characters? It's terribly limiting. Why not a sequence of whole words? Why not even a sequence of multi-word phrases? Why not a sequence of numbers? Why not a sequence of whatever we want?

Exactly. Why not? Python does not condemn us to string as the only type of sequence. You can create any sequence of items. Such a sequence is called a list.

Lists

Lists are the most flexible and most popular form of the Python collection. A list is any sequence of items. The elements of the list can be numbers, text, logical values. List items can be variables. Finally, a list item can also be another list.

We mark the list with square brackets, and separate the elements with commas.

L_01 = [125, 250, 500, 1000]  # the list we named L_01 contains numbers

L_02 = ['Espresso', 'Americano', 'Macchiato', 'Cappuccino', 'Cafe Latte']
# the list we named L_02 contains the names of coffee drinks

L_03 = [90, [125, 250, 500, 1000], 'house']   # L_03 list contains three elements, each of a different type; the first item is a number, the second item is a list, and the third item is a string.

List is a data structure in Python, which is a modifiable, ordered sequence of elements. Elements of a list can be added, removed or altered. List allows you to store related data "in one place", and compact the code. List allows you to perform the repeated operation on its elements. That is why lists are great for working with many related values simultaneously.

Slicing

Slicing is a technique that allows you to access parts of a sequence, such as strings and lists.

To access a single element in a sequence, enter the index number of that element in square brackets.

a[i]

However, if you want to access more than one element, use an additional colon.

Let's demonstrate access to selected parts of the chain  a='abcdef'

print (a)         # 'abcdef' (whole string)

print (a[3])      # 'd' (fourth element in the string)

print (a[3:])     # 'def' (from the fourth element to the end)

print (a[:4])     # 'abcd' (from start to element 4, excluded)

print (a[2:4])    # 'cd' (from element indexed 2 (included) to 4, excluded)

print (a[-1])     # 'f' (negative indexing)

print (a[-3:-2])  # 'd' (negative indexing with interval)

Comment: remember that indexing starts from zero (the first element is indexed 0, the second: 1, etc.) when indicating a range, the closing number is excluded (does not fall into the range)

for example, a [:4] indicates that these items are selected:  0, 1, 2 and 3

we start reverse indexing at ‑1 (not zero) – as shown in penultimate line of our example.

Exercise

Let's practice similar access to sequence fragments, but this time using a list instead of a string.
Here is the list of wine names that we will use in the exercise: ['Cabernet Sauvignon', 'Chardonnay', 'Merlot', 'Pinot Noir', 'Riesling', 'Chianti', 'Syrah', 'Zinfandel']

L = ['Cabernet Sauvignon', 'Chardonnay', 'Merlot', 'Pinot Noir', 'Riesling', 'Chianti', 'Syrah', 'Zinfandel']

print (L)

print (L[3])

print (L[3:])

print (L[:4])

print (L[2:4])

print (L[-1])

print (L[-3:-2])

Output:

['Cabernet Sauvignon', 'Chardonnay', 'Merlot', 'Pinot Noir', 'Riesling', 'Chianti', 'Syrah', 'Zinfandel']

Pinot Noir

['Pinot Noir', 'Riesling', 'Chianti', 'Syrah', 'Zinfandel']

['Cabernet Sauvignon', 'Chardonnay', 'Merlot', 'Pinot Noir']

['Merlot', 'Pinot Noir']

Zinfandel

['Chianti']

Note: Slicing parameters — determining the beginning and end of the interval — are called start and stop. In addition, you can define the value of the third parameter, which is called step. Take a look at the appendix to this study.

Mutative access

By the phrase "mutative access" we mean the access with ability to modify the accessed object.

Let's think. Until now, the access to sequence elements (a list or a string of characters) in question was a "read only" access. That is, we could read the selected item(s). What if we wanted to change the value of selected elements? That is, modify elements?

For example, you conclude that the third item on your wine list should be 'Muscat' — instead of the current 'Merlot'. How do you make a change?

Just type:

L[2]='Muscat'    — and it's done.

After making this instruction, the L‑list looks like this:

['Cabernet Sauvignon', 'Chardonnay', 'Muscat', 'Pinot Noir', 'Riesling', 'Chianti', 'Syrah', 'Zinfandel']

Let's try a similar action on a string:

a='abcdef'

a[2]='h'

Result:

Traceback (most recent call last):

  File "<pyshell#1>", line 1, in <module>

    a[2]='h'

TypeError: 'str' object does not support item assignment

In short, Python "threw out " an error. Why? The justification can be read in the error message:
'str' object does not support item assignment — that is: The 'str' type object does not support the operation of assigning [value] to an item.

This means that you cannot exchange characters in the string. Once created, the string must remain unchanged. However, you can replace the entire string if you wish

x = 'hwllo'   # variable x is a string in which you entered the letter w by mistake

x = 'hello'    # assign the new, corrected string to the variable x

The conclusion is that lists are a more flexible tool than strings, because you can modify them — replace selected elements in them. Or to put it in a more "advanced" language: in Python, lists are mutable data types, while strings are immutable ones.

Some useful tools

Here are a few selected tools that are useful for working with sequences.

The len function

The len function returns the number of elements in the sequence:

a='bike'

len(a)   # output: 4

b=[12, 14, 16]

len(b)  #output: 3

The in operator

The in operator indicates whether a given element appears in the sequence

a='bike'

'i' in a # output: True

'z' in a # output: False

b = [12, 14, 16]

20 in b # output: False

14 in b # output: True

"Index" function (command)

The index function indicates where the searched element is located in the sequence: The syntax (notation) for this function is as follows:

sequence_name.index(element)

Examples:

a='bike'

b=[12, 14, 16]

a.index('i')  # Output: 1

b.index(16)   # Output: 2

Note: If an item is repeated several times in sequence, index returns the lowest index found:

a='balikiki'

a.index('i') # Output: 3

If the element is not present in the sequence, index returns an error. To avoid this, use the in operator first to determine if the element is in the sequence, and then use the index command to determine its position.

Summary

Sequences are ordered sets of elements. An example is a list that is a collection of any items, separated by commas. A sequence can also be a word whose successive elements are letters. You can also generate a sequence of numbers by using the range function.

Python — transparently to the user — numbers the elements of a sequence. The element number is called its index and is usually marked with the letter i. You can "retrieve" the index of any element at any time.

You can perform many interesting sequence operations with indexes.

Appendix: Slicing – extended version

In its extended form, the slicing notation looks like this:

S[start:stop:step]   

where: S — any sequence; while the start, stop and step parameters are optional — that is, you can omit their values, and then Python will provide a default value instead.

start: number of the element from which the slice begins, included[5] (the default value is zero, i.e. "from the beginning of the chain");

stop: number of the element ending the slice, excluded (not specifying this parameter means: elements to the end of the sequence);

step: specifies the value of n, when repeatedly every n‑th element from the sequence is taken (default value is 1). When you specify a step value = 2, Python will pick every second element from the sequence. When you enter the step value = 3 — every third element etc.

Ok, so it seems you can omit start and stop – if you wish – leaving only step parameter?

Right, that's true. When you do not want to enter "start" or "stop", but only "step", you write: S[::step]

 Here are some examples:

  • S[::2]  means "default start index, default stop index, step size is two—take every second element".
  • S[::3]  means "default start index, default stop index, step size is three—take every third element".
  • S[::-1] means "step size is negative— take each element starting from the end, moving backwards".
  • S[::-2] means "step size is negative— take every second element starting from the end, moving backwards".
  • S[2::2] means "start index of two, default stop index, step size is two—take every second element starting from index 2".
  • S[2::-2] means "start index of two, default stop index, step size is "minus two"—take every second element starting from index 2, moving backwards".

Let’s have a look at those examples in a Python shell:

>>> s = 'hello world'

>>> s[::2]

'hlowrd'

>>> s[::3]

'hlwl'

>>> s[::-1]

'dlrow olleh'

>>> s[::-2]

'drwolh'

>>> s[2::2]

'lowrd'

>>> s[2::-2]

'lh'


[1] let us emphasize that it is not our goal to have a comprehensive overview of data types in Python and we only refer to selected types; If you are interested in a more comprehensive classification, please visit https://www.journaldev.com/14036/python-data-types 

[2] for a long time computer languages used a character set called ASCII. Currently, the most common is the Unicode set, which contains many more characters than ASCII

[3] numbers cannot be easily broken down into digits, at most they can be described by a formula 345 = 3x102 + 4x101 +5x100

[4] see  https://thepythonguru.com/python-builtin-functions/range/

[5] the terms "included" and "excluded" are equivalent to the notions of open and closed intervals (or sequences) known to you from mathematics. The question is whether the "endpoints" of the interval (or the sequence) are included in it. For example, a sequence of natural numbers from 5 to 10 would contain the following numbers:

bottom end included, top end excluded: 5, 6, 7, 8, 9;

bottom end excluded, top end included: 6, 7, 8, 9, 10;

both bottom end and top end excluded: 6, 7, 8, 9;

both bottom end and top end included: 5, 6, 7, 8, 9, 10.