Search

Using The Python String Format Method: Format Specifications Part 2

In an earlier post, I showed how to use field names and conversion fields to format values in replacement fields. Today, I will continue that discussion by showing how to use format specifications, the optional and last feature of replacement fields, in the python string format method.

The format specification for python string format method
 

The format specifications represent how the value in the replacement field should be presented. It includes details such as the width of the field, its alignment, padding, conversion etc. Each value type is given its own specification. Also note that each format specification can include nested replacement fields but the level of nesting should not be deep.

You use a colon, :, to denote the start of a format specification. The format specification has 8 flags and I will denote each of them in their order of precedence. Note that each of the flags are optional.

  1. The fill flag
  2. This flag is used as the first flag. Use it to denote what you want to use to fill the space in the presentation of the value of the object. Any character can be used as the fill character and if it is omitted, it defaults to a space. Note that a curly brace cannot be a fill character except the curly brace is in a nested replacement field. The fill character kicks in when the value of the object cannot fill the specified width of the replacement field otherwise it doesn’t apply. So, you use it with other flags.

  3. The align flag
  4. The represents the alignment of the value of the object. You could either right align, left align, center or cause a padding to fill the available space. The different options are presented below:

    < Used for left alignment of the value in the available space. The default for most objects
    > used for right alignment of the value in the available space. The default for numbers.
    = Forces a padding to be placed after the sign but before the digits. Only valid for numeric types. If you precede the field width (explained below) with 0, then this becomes the default.
    ^ forces the value to be centered within the available space.

    To make the alignment option meaningful, you must specify a minimum field width. Here are some examples. They all come with minimum field width of 20.

  5. The sign flag
  6. This is only used for numeric values. The various options are:

    + Use a sign for both positive and negative values.
    - Use a sign only for negative values (this is the default behavior)
    Space Show a leading space for positive numbers and a minus sign on negative numbers.

    Here are some examples.

  7. The alternate flag, #.
  8. Use this flag when you are doing value conversion and you want the alternate option to be specified. It is valid for integers, floats, decimal and complex types. We will come back to this when we get to the conversion flag and show how the alternate forms can be specified.

  9. The grouping flag.
  10. The grouping flag specifies the character to be used as a thousands separator. It has two options:

    _ Use this as a thousands separator for the integer types when ‘d’ is specified as the type flag (to be explained later) and floating point types. When the type flag for integer types is either ‘b’, ‘o’, ‘x’, or ‘X’, the separator is inserted after every four digits.
    , Use a comma as the thousands separator. You could use the ‘n’ type flag instead if you want a locale aware separator.

    Now some examples. I included the third example with ‘b’ as a type flag. ‘b’ as type flag means convert value to base 2. This will be explained below under type flags.

  11. The precision flag
  12. The precision flag is a decimal number that indicates how many digits should be displayed “after” the decimal point for a floating point value that has the type flag ‘f’ or ‘F’, or before and after the decimal point for a floating point value that has the type flag ‘g’ or ‘G’. Note that there is no precision for integer types. If the value is a non-numeric type, then this indicates the maximum field size of the replacement field.

    Now for some examples. Notice how it truncates the string type, s, when the precision is smaller than the number of characters.

  13. The type flag
  14. The type flag determines how the data should be presented. The type flag is specified for string types, integer types, and floating point types.

    For string types: The available options are...

    s The default type for strings and may be omitted
    None The same as ‘s’

    For integer presentation types: The options are...

    b Outputs the number in binary format
    c Converts the value to the corresponding Unicode character before printing.
    d Output the number in base 10 before printing.
    o Octal format. Output the number in base 8 and print.
    x Hex format. Output the number in base 16 using lower case letters for digits above 9
    X Hex format. Output the number in base 16 using Upper case letters for digit above 9.
    n Decimal format. The same as ‘d’ but it uses locale aware setting to insert appropriate thousands separator for the locale.
    None Same as ‘d’

    Note that except for ‘n’ and None, you can use any of the options above in addition to the floating point types below for integers. That is, you can have a mixture of both integers and floating points.

    Now, let’s use some examples.

    When discussing the alternate flag, #, I stated that there are times when you want alternate conversion forms to be specified. For example, for binary, octal and hexadecimal outputs the alternate flag, #, will result in an output of ‘0b’, ‘0o’, and ‘0x’. Let’s show this with examples.

    The alternate flag can also be applied to floats and complex numbers.

    Now finally, the options for floating point presentation types are:

    e Exponent notation. Print the number in scientific notation using the exponent, e, to denote it. The default precision is 6.
    E Exponent notation. Print the number in scientific notation using the exponent, E, to denote it.
    f Displays the number in fixed point notation. The default precision is 6.
    F Fixed point notation, just like ‘f’ but converts nan to NAN and inf to INF.
    g This is the general format. Uses fixed point or scientific format depending on the magnitude of the number.
    G General format, but in uppercase.
    n Same as ‘g’ but is locale aware in inserting appropriate thousands separator.
    % Percentage. Multiplies the number by 100 and displays it in fixed format, ‘f’, with a percent sign (%) following it.
    None Similar to ‘g’ except that fixed point notation when used has at least one digit past the decimal point.

    The following examples uses precision 2 then the default 6.

I hope you get creative in using this format specifications. They are very helpful when representing values. Note that python’s literal string formatting method, f-strings, are similar to the python string format method described here. You can interchange the two.

Using The Python String Format Method Like A Pro Part 1

How you format your text is important in text processing and python is not left out, giving you several options to make your output appear presentable. I decided to delve into the issue of python formatting in today’s post while reading some code. I appreciated the way the author applied python string formatting. So, I decided to devote two posts to string formatting because I believe my readers would be interested in it.

python string format method makes output presentable
 

In python you format your output using the format method of the string class. What is also called the python str.format method (or python string format method) to differentiate it from the python literal f-strings. A format string contains two types of features that would have to be sent to the output: literal text and replacement fields. Replacement fields are surrounded by curly braces, {}, and refers to objects that have to be formatted, while literal text refers to whatever you want to leave unchanged in the output. So, what we are interested in are replacement fields.

To give you an idea of what replacement fields are, read and run the following code:

You will see that in the string part of the python format method in the code above, there are two curly braces and they serve as replacement fields whose values are provided by the parameters, name and age, of the python format method. We are going to be discussing how you can format your output based on the replacement fields and parameters.

The syntax of the python string format method

The syntax of the python string format method is: template.format(p0, p1, k0=v0, k1=v1) where template refers to the string you want to format. As I said before, the template consists of both literal text and replacement fields. Replacement fields are denoted by whatever is in curly brackets, {}. The arguments p0 and p1 refers to the positional arguments while k0 and k1 refers to the keyword arguments. Positional and keyword arguments are used to insert values into the replacement fields in the template. We will cover all these and give you ideas on how to use them.

The replacement fields have three optional features: field names, conversion fields that are preceded by an exclamation point, !, and format specifications. Today’s post will cover how to specify the field names and conversion fields while the next post will be on format specifications.

The field names in the string replacement fields.

The replacement field starts with an optional field name. The field name refers to the object whose value is to be inserted. The object is specified in the parameter of the format method. The field name is either a number or a keyword.

  1. Where the field name is a number:
  2. An example to illustrate this is below:

    
    name = 'Michael'
    age = 29
    print('Hello, you name is {0} and your age is {1}'.format(name, age))
    

    You can see that in the template above, there are two curly braces or replacement fields. The first has the number 0 and the second has the number 1. The curly brace with 0 refers to the first positional argument which is found as a parameter to the format method and here this is the variable, name, while the curly brace with 1 refers to the second positional argument which is the variable, age.

    If you so desire, you can choose to leave out the numbering of the curly braces and python will insert them on your behalf. Like this:

    
    name = 'Michael'
    age = 29
    print('Hello, you name is {} and your age is {}'.format(name, age))
    
  3. Where the field name is a keyword.
  4. The python string format method provides for instances where you can specify keyword arguments as parameters and the replacement fields requires you to specify the keywords. An example is below:

    print('Hello, you name is {name} and your age is {age}'.format(name='Michael', age=29))

    You can see now that I have inserted the keywords into the curly braces because the parameters are keyword arguments.

    Using keywords as arguments is super powerful. It gives you the ability to change the ordering of the parameters in the replacement fields. For example, instead of following the ordering of the positional arguments, I could order the replacement fields as it suits my fancy:

    Check out the code above and the one before it. See how I interchanged the ordering of the keyword arguments in the replacement fields. We could try another example to show you how powerful this is.

    print('In {country}, there are {number} million people speaking {language}.'.format(language='English', number=300, country='USA'))

    Now, let’s insert it into the embedded python interpreter so you can run it:

    With keyword arguments you are not constrained to any sort of ordering. You choose how you want it to be. You can check out this post if you want a refresher on positional and keyword arguments.

    Note: What if you want to have the brace as a literal text in the template? Simple, just double brace it.

    print('This is doubling the braces {{{name}}} for {name}'.format(name='Michael'))

    I doubled the braces for the first replacement field. Let’s run it to see how it would appear on the embedded interpreter.

    When you run it, you will notice that braces now literally appears in the output.

    Now, what if your parameters are lists or an object with attributes whose value you want to show on output? The next two sections below will show you how.

  5. Where the parameter to format is a list.
  6. To make the output appear as you want it to, you can specify the parameter as a keyword argument or a positional argument. Look at the code below and see how. First, I specify it as a keyword argument. That means, you need to implicitly specify the list in the parameter and index it in the replacement field. But if you want it as a positional argument, you need to specify the index as parameter.

    What python does when you specify it either way is to call the __getitem__() method of the list. I discussed about this method in an earlier post on sequences.

  7. When the object has attributes with values.
  8. When the object in the parameter has an attribute whose value you want to format, you can directly call the attribute in the replacement field. The code below shows how in the method get_fruit. What the 0.index and 0.fruit does is call the getattr() function of the object, self, in order to get the required value. In the code below I created a fruit class with a class attribute, index, so that whenever a fruit is created it is tagged with an index (instead of creating a list) and then the index is incremented to tag the next fruit.

Be creative. Play with your own objects to test how format calls attributes from the replacement field.

I think that’s all for field names. After the field names come an optional conversion field.

Syntax of the conversion field

The conversion field is optional, but if specified, it is preceded by an exclamation point, !, to differentiate it from the field name. It causes type conversion before any formatting of the replacement fields takes place. But one may ask – doesn’t every object have a default __format__() method? Yes, they do. But the creators of python realized that sometimes you want to force a specific string representation of an object.

There are three types of specifiers for the conversion field: !s, !r, and !a specifiers.

  1. The !s specifier:
  2. The !s conversion specifier gives you a string representation of the object in the replacement field. What it does is call str() on the object in the replacement field, converting it to a string. This is the default string formatting.

  3. The !r specifier
  4. You can use this when you want the true string representation of an object to be specified, and not just outputting it as a string. This representation contains information about the object such as the type and the address of the object. This specifier calls the repr() method of the object.

  5. The !a specifier
  6. This specifier also outputs the true string representation of an object but it replaces all non-ascii characters with \x, \u or \U. This specifier calls the ascii() method of the object. It works like the !r specifier if you have no non-ascii characters in the object.

Here is an example illustrating all three types. Notice how the object type appeared in the output for !r and !a.

As another illustration, you can compare the output of the !s and !r in a string with quotes showing or not showing.

In my use of the conversion fields, I have found that making them optional has served me well. So, they just come in for special cases of formatting.

Now, the third and last feature of the replacement field option is the format specifier which is explained in this post. This is where the real juice of replacement fields are stored.

Light Trapping Nano-Antennas That Could Change The Application Of Technology

Travelling at a speed of 186,000 mi/s, light can be extremely fast. Even Superman, the fastest creature on Earth, cannot travel at the speed of light. Humans have shown several times that they can control the direction of light by passing it through a refractory medium. But is it possible to trap light in a medium and change its direction just as you can trap sound in an echo device? Before now that possibility was theoretical but new research has shown that this could be practical. Since light is useful for information exchange and so many applications, the ability to control light, trap it or even change its direction could have several applications in science and technology.

outline from light trapping device
 

In a recent paper published in “Nature Nanotechnology”, some Stanford scientists who were working at the lab of Jennifer Dionne, an associate professor of materials science and engineering at Stanford University, have demonstrated an approach to manipulating light which has been successful in its ability to significantly slow the speed of light and also change its direction at will. The researchers structured silicon chips into fine nanoscale bars and these bars were used to trap lights. Later, the trapped light was released or redirected.

One challenge the researchers faced was that the silicon chips were transparent boxes. Light can be trapped in boxes but it is not so easy to do if the light is free to enter and leave at will just as you find in transparent boxes.

Another challenge that was faced by the researchers was in manufacturing the resonators. The resonators consist of a silicone layer atop a wafer of transparent sapphire. The silicon layer is extremely thin and it has the ability to trap lights very effectively and efficiently. It was preferred because it has low absorption in the near-infrared spectrum which was the light spectrum that the scientists were interested in. This region is very difficult to visualize due to inherent noise but it has useful applications in the military and technology industry. Underneath the silicone layer is a bottom layer of sapphire which is transparent and the sapphire are arranged in wafers. Then a nano-antenna was constructed through this sapphire using an electron microscopic pen. The difficulty in etching the pattern for the microscopic pen lies in the fact that if there is an imperfection then it will be difficult for it to direct light as the sapphire layer is transparent.

The experiment would be a failure if the box of silicon allowed the leakage of light. There should be no possibility of that. Designing the structure on a computer was the easy part but the researchers discovered the difficulty lay in the manufacturing of the system because it has a nano-scale structure. Eventually they had to go for a trade-off with a design that gave good light trapping performance but could be possible with existing manufacturing methods.

The usefulness of the application

The researchers have over the years tinkered with the design of the device because they were trying to achieve significant quality factors. They believed that this application could have important ramifications in the technological industry if it was made practical. Quality factors are a measure of describing the resonance behavior involved in trapping light and in this case it is proportional to the lifetime of the light.

According to the researchers, the quality factors that were demonstrated by the device was close to 2,500 and if you compare this to similar devices, one could say that the experiment was very successful because it is two times order-of-magnitude or 100 times higher than previous devices.

According to Jennifer Dionne at Stanford University, by achieving a high quality factor in the design of the device, they have been able to place it at a great opportunity of making it practical in many technology applications. Some of these applications include those in quantum computing, virtual reality and augmented reality, light-based Wi-Fi, and also in the detection of viruses like SARS-CoV-2.

An example of how this technology could be applied is in biosensing. Biosensing is an analytical device used for the detection of biomolecules that combines a biological component with a physicochemical component. A single molecule is very small that essentially it is quite invisible but if light is used as a biosensor and passed over the molecule hundreds or even thousands of times, then the chances of creating a detectable scattering effect is increased, thereby making the molecule discernible.

According to Jennifer Dionne, her lab is working on applying the light device on the detection of Covid-19 antigens and antibodies produced by the body. Antigens are molecules produced by viruses that trigger an immune response while antibodies are proteins produced by the immune systems in response to the antigens. The ability to detect a single virus or very low concentration of multitudes of antibodies comes from the light – molecule interaction created by the device. The nanoresonators are designed to work independently so that each micro-antenna can detect different types of antibodies simultaneously.

The areas of application of this technology is immense. Only the future can predict the possibilities when other scientists start experimenting with what was discovered. I think this innovation is a game changer.

Materials for this post was taken from the Stanford University website.

A Concise Guide To Python Loops

In a post this week, while discussing control flow in python, I wrote about repetitive control structures in python which consist of the python while and for loops. But I received some text message where a reader said my post was not concise enough; that I left off some features of python loops. I agreed with him. This was because my focus was just in showing how control structures work in python and not on showing all the features of python loops. So, in this post, I have decided to write a concise guide on python loops.

python while loop and python for loop
 

As I said earlier in the other post, when you want to repeatedly iterate over some block of code you use loops. In python, you can either use a python for loop or a python while loop. After showing examples of both loops, I will then concisely explain what situations both loops can be used that makes them similar and different.

The python for loop

In order to be more concise and cover all situations, I will use the syntax of the documentation reference in defining a python for loop.


for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

This python for loop syntax states that a for loop is denoted by the “for” keyword. Also, on evaluation of the iterable that would be used in the for loop, expression_list, an iterator is created consisting of all the items to be used in the looping construct. Then for each iteration, the target_list is bound to each of the items in the expression_list iterator, and it will be used in the suite which is the block of code that is to be repeated. A python for loop can have an optional else clause. The else clause, when denoted, is called when the loop has completed all its iterations.

Now a picture is worth a thousand words. Let’s illustrate the syntax above with an often used syntax:


# please note that the else clause is optional
for variable in iterable:
    block of code to execute
else:
    block of code when for clause ends    

Just as in the documentation’s syntax, the variable is assigned each item in the iterable during an iteration until the iteration ends. Most times, the variable is used in the block of code to execute.

Let’s show how the iteration works using a python for loop example with an iterable, this time a list, and printing out each iteration of the list to show how they are passed to variable.

When you run the code above, you can see that each item in the list is printed out in the block of code. This is because for each iteration, the item variable is bound to the first fruit, then the next fruit, and so on subsequently.

What if for each iteration we want to do something with the items, like multiply each item in the sequence. Here is code that shows you how.

You can see that the python for loop iterates through each of the numbers and prints them out.

Now, let’s show how the often ignored else clause can be used. When the loop finishes its iteration we can specify an else clause with a block of code that will be executed. The else clause in a for loop is similar to the else clause in a try statement and not to the else clause in an if statement.

I told you this promises to be a concise guide. So, I will show one more example of the use of an else clause. What if we had a for loop that when a condition is satisfied, it breaks out of the loop but has to execute another block of code after it breaks out of the loop. For example, imagine having some numbers in a range, like 1 to 10, and writing a function that states whether each number is a prime or a composite. A prime does not have a factor between 2 and the number, except 1 and the number itself. So, using this property we will factor all the numbers from 2 to that number and use the result of remainder division to state whether a number is a prime or a composite. I will use two loops for this example. See how the else clause is used to achieve this effect.

Notice that the else block is triggered when the second for loop goes to completion because the number is not a composite number. Anything that is not a composite is prime. But if it is a composite number, we break out of the loop to the outer enclosing loop to start another outer iteration.

There is something I introduced in the above code which I have not talked about. That is, using the python range function in a for loop to iterate over numbers. Yes, the range and for loops come in very handy when you want to iterate over numbers in python for loops. Use them at your convenience. The syntax of a range function is: range(start, stop[, step]). The start is the number to start the iteration from. The stop is the number at which to stop the iteration. Stop is not included in the iteration. The step signifies how you pick the numbers, maybe you want to pick every second number from the start of the range etc. When there is only one argument to the range function, it is understood to refer to the stop. The default for start, which is 0, is assumed, and the default for step, which is 1, is assumed. When there are two positional arguments, it is understood that the first is the start and the second is the stop. Then the default for the step, 1, is used. Note that you cannot make step to be zero or it will give a ValueError. To illustrate, let’s use examples.

The range function is a handy tool to use with the for loop when you are dealing with numbers. You use it to create a sequence of numbers to be used in the iteration directly, as we did in the for loop above. Or you can use it to create a set of integer indices that can be used on the sequence itself. Let’s show an example of using it to create indices for use in the iterable. Here you create the argument for the range using the length function called on the iterable. I discussed about this in an earlier post on how powerful the length function is. Now, for an example.

Item variable above are integers created by the range function as indices to the fruits list.

Finally, before I end the discussion on for loops, I have to tell you that for loops can be nested. I showed an example in the loop above that looks for prime numbers. But another example of a nested for loop would not be bad.

I promise to be concise, right? So, let’s take on python while loops.

What are python while loops?

The while loop or while statement is used for repeated execution of a block of code as long as an expression is True. Here is the syntax of a python while loop according to the documentation:


while_stmt ::=  "while" assignment_expression ":" suite
                ["else" ":" suite]

You can see from the above that you begin the while loop with the while keyword and this is followed by the expression you want to evaluate for whether it is True or False. Note that the expression must be a Boolean expression. As long as the expression is True, the while loop will continue executing the statements in the suite or block of code. Also, notice that a while loop also has an optional else clause. This else clause can be used to signify block of code you want to run when the while loop finishes running or when the expression evaluates to false.

The common syntax for python while loop used by many authors is:


# the else clause is often not used. Optional
while condition_is_true:
    body_of_code
else:
    body_of_code    

This is the flow of control of a while loop. First, the condition is checked whether it is True. If it is False, the while loop is not executed but flow of control moves to the next statement in the code. If the condition is True, the body of code in the while loop is executed until it becomes False.

Note that if the body of code in the while loop is executed and the condition does not become False during the time the loop is running, you will enter an infinite loop. That is, a loop that never ends. If you enter an infinite loop, just press CTRL+C on your machine and it will stop execution of the loop. But you can prevent infinite loops.

How to prevent infinite python while loops.

To prevent infinite loops occurring in your python while loops, you need to use a counter at the condition or Boolean expression. Then you have to initialize the counter before the while loop and increment or decrement the counter in the body of the loop.

Now, let’s do all this with some examples. First, showing the use of a counter in the condition of the loop to test for True.

Let’s take some points from the code above. But, first I will encourage you to run it to see that it works. First, before the loop we initialized the counter to 1, our starting number. Then we used the counter to test for the condition that we have not gone beyond the last number, 5, by saying we want counter to be true when it is less than 6. Then in the body of the while loop we incremented the counter so that on each iteration the counter keeps moving towards 5 and when it moves beyond 5 to 6, the condition becomes False so we exit out of the loop. What if we had not incremented the counter in the body of the loop? We would have entered an infinite loop. If we had not initialized the counter before the loop condition, we would have gotten a NameError exception. I want you to test these two error conditions on your own machine.

Now, if we do not want to use a counter, we could use a variable that is bound to a Boolean value in the condition of the while loop. We need to initialize the variable also before the while loop is entered. Then in the body of the while loop we change the switch for the variable so that the condition can become False when we want the loop to stop execution. Here is an example.

Notice that I am doing the same calculation but this time using a variable that is bound to a Boolean value. We initialized the variable before the while loop and makes sure it is True in the condition. Then in the body of the loop, when our condition is satisfied and we want the loop to stop execution, we switched the variable so that the condition becomes False.

There are two more statements about loops that need to be considered. The python break and continue statements. But I don’t want to repeat myself. Programmers aim to reuse code, so I would encourage you to go to the post on control flow where I discussed break and continue statements in loops. I believe I was very concise in explaining those concepts in that post. You can find the explanation at the end of the post.

Now finally, the similarities between for loops and while loops along with their differences.

Similarities and differences between python while and for loops.

First, their similarities. The basic similarity between a while loop and a for loop is that you can end either loops early via a break statement. Whenever you call a break statement on either loop, it stops execution of the loop enclosing the break statement.

There are three differences I have noticed between the two loops:

A python for loop has a finite number of iterations and you can know how many iterations it will perform. A while loop might have an infinite number of iterations and you might not be able to count how many iterations it will go through.

Although both loops can use a counter, the counter for a while loop must be initialized before the loop and then incremented or decremented in the body of the loop.

You can rewrite a python for loop using a python while loop but you might not be able to rewrite a while loop using a for loop except in some cases.

So, I can now rest in peace. That is my concise guide to loops in python.

Happy pythoning.

An Unstructured, Random Python Cipher That Seems Unbreakable

Today, we will be cracking codes with python. While researching on this post, I came up on an article about Caesar’s cipher. Caesar’s cipher is a means of encrypting messages using a mapping from the original alphabets to the encrypted alphabets with the original alphabets shifted by some keys either to the left or the right to produce the encrypted alphabets. The author said that Caesar’s cipher, which was one of the earliest forms of cryptography, could be broken by a brute force method. I said to myself: “That’s cool. It could be broken because Caesar’s cipher has a key with a structure. What about if the key has no definite structure?” So, I decided to write a program that is inspired by Caesar’s cipher but with a random key that has no structure. Rather than use the python chr and ord functions, I decided that a better way for my concept to work was to randomize a translation table. But to have a random translation table, I needed to first create it.

 

keys to a cipher in python

How do you create a translation table that has no structure when mapping from source to destination strings and is random? Well, before I begin explaining how, I should explain the functions we are going to use. The functions are python’s randint, maketrans and translate functions.

The python randint function.

The python randint function is a random number generator in python and one of the methods of the python random module. It generates a random integer each time it runs. To use it, you have to import the python random module. The syntax of the randint function is random.randint(a, b) where randint generates integers between a and b inclusive. If you want an indepth coverage of the python randint function and other functions of the python random module, you could do well to read it up on an earlier post. So in my solution today, I will be using the randint function to generate python random numbers.

The next function is the maketrans function.

What is the python maketrans function?

Python has two types of maketrans functions - the static byte.maketrans method and the static str.maketrans method. The earlier belongs to byte objects and the latter to string objects. Both are used to make translation tables for mapping characters.

  • Bytes.maketrans:
  • The syntax is bytes.maketrans(from, to). It will map each python character in the from string of bytes to its equivalent python character in the to string of bytes while making a translation table to be used by the python translate function. From and to must be bytes objects with the same length. To create a translation table that maps ‘a’ to ‘e’, ‘b’ to ‘f’, and ‘c’ to ‘g’, in bytes, we could write the following code:

    
    original = b'abc'
    end = b'efg'
    translation_table = bytes.maketrans(original, end)
    

    When we have a translation table, the work of doing the actual translation is nearly complete.

  • Str.maketrans:
  • The syntax is str.maketrans(x[, y[, z]]) where y and z are optional arguments. When using the python str.maketrans function you are making translation tables that maps python characters or Unicode ordinals to other python characters, Unicode ordinals or None. Note that Unicode ordinals are mappings of characters as integers. For example, ordinal 97 is character ‘a’ while ordinal 98 is character ‘b’.

    When only x is used as the argument in the python str.maketrans method, you must supply a dictionary to str.maketrans method to make a translation table. Note that all translation tables are dictionaries that maps the source to the destination. Here is an example:

    Like before, we are mapping ‘a’ to ‘e’, ‘b’ to ‘f’, and ‘c’ to ‘g’. In the translation table, the Unicode ordinals for the characters are used to identify the characters.

    What if you specify two parameters to maketrans i.e x and y. When you do so, both x and y must be python strings of equal length. You need to specify a string that contains the keys in order for maketrans to properly understand how to create the translation table. Maketrans will create a translation table mapping characters in x, the source, to characters in y at the same index. An example is below:

    If you want some characters to be mapped to None in the translation table, then you have to specify the third argument, z, when calling str.maketrans. Any character in z is mapped to None. Here is an example where d is mapped to None. Any character mapped to None is deleted during the translation of the actual message.

So, I believe you now understand how to create translation tables and you know that the translation tables uses the Unicode ordinals for the characters. Therefore, instead of specifying characters, you could just write out the Unicode ordinals if you know them.

The next step is to do the translation. You use the python translate function to do the actual translation.

How to use the python translate function.

To do the actual translation from the translate table, you use the python translate function. There are two types of python translate functions, the bytes.translate and str.translate, but I suggest you stick to just str.translate because most of the messages you will be translating will be python strings.

The syntax for str.translate is str.translate(map) where str is the message you want to translate and map is the translation table you will be using to do the mapping of the characters in the message. Notice from above that the translation table is a dictionary of Unicode ordinals to Unicode ordinals, strings, or None.

What the translate function does is to take each character in the message, look for its corresponding key in the translation table. If it exists, it replaces that character in the message with its value in the translation table. If the character does not exist in the translation table, the character in the message is left as it is. If in the translation table the character is mapped to None, it is deleted in the message.

Now, that’s a mouthful. Let’s illustrate all the above with examples.

First, let’s translate a message containing the characters in the source above. For example, supposing our message is ‘abccbaaaab’, how would it be translated?

When you run the above you would notice that ‘abccbaaaab’ is translated to be ‘efggfeeeef’ since we are replacing all ‘a’ with ‘e’, all ‘b’ with ‘f’ and all ‘c’ with ‘g’.

Let’s take another example where some characters in the message do not appear in the translation table and also some characters in the translation table are mapped to None.

If you look closely at the code, you will notice that the message has four characters but the translation has just three characters. ‘a’ and ‘b’ were translated as per the translation table to ‘e’ and ‘f’ respectively. In the translation table, ‘d’ is mapped to None so in the translation it is removed. While there is an ‘e’ in the message but there is no key ‘e’ in the translation table so the ‘e’ character is left as is, untranslated.

So, we have what it takes for us to do our unstructured, random python cipher.

This is the source code. You can run the code before understanding the logic stated below just to see how it works. Run it more than once and see that each time you get a different encryption scheme.

This is the logic behind the code. We will first create our source string for the translation table. That will be all the lower case alphabets. We will then cast this source string to a list and use it as a list of values we are going to use for the destination string or replacement string. Since all the alphabets are 26 characters, we enter a loop in line 7 which will create a replacement string 26 times. For each iteration of the loop, we will create a random index between 0 and 25. The index variable serves as an index to the values_list which will be used to create the replacement strings or destination strings. When we have a random index, we will then check if that index has a value in the values_list (line 9). If it has a value, we place that value in the destination_list, adding it as a stack. That means the first value will be the replacement for ‘a’ in the source string. After placing that value in the destination_list, we then substitute its corresponding value in the values_list with None; to tell the code that we have come to that index. Each time that the index gets a value in the values_list that is None (we have already used it), it moves one step in the values_list modulo 26, looking for an unused value in the values_list until it finds one. When it finds one, it stops looking (lines 12 -19). This step of stepping through the values_list looking for a value makes the arrangement of the replacement strings unstructured or without any pattern. That makes it difficult to use a mathematical formula to crack the code. I was thinking about this when I wrote a blog post on the unbreakable code and internet security that describes one-way functions. One-way functions are unbreakable codes; they are functions that go one way and cannot be reversed. Making my replacement strings unstructured mimics this behavior.

When the destination_list is completely populated, we then convert the list to a string (line 20). So, right now, we have our source and destination or replacement strings which makes it possible to create the translation tables for encryption and decryption. (Lines 24 – 28). With the translation tables created, we do the actual encryption and decryption using a specified message and voila, it works. (Lines 31 – 36)

You will notice that each time you run the code, you will get a different encryption scheme because the translation tables are randomized. That makes it difficult to break. What anyone using the code would have to do is to run it once, save the state of the translation tables in a database and use the translation tables for encryption and decryption. The weak point of my code is protecting the translation tables from hackers laying a hold on it, otherwise I think it would be very difficult to hack this scheme.

I challenge anyone to hack it without peeking at the translation tables.

If you want the source code for the unstructured, random python cipher, you can download it here.

Using Python Lambda, All, And Any Functions To Verify A Food Menu

It was recently reported that the Russian opposition leader, Alexei Navalny, was in coma from suspected food poisoning. That was a disturbing news that made me start thinking of how to create a function that verifies a menu for good and bad foods. I did some thinking and decided that the right functions to use for the verification process were the python all, any and lambda functions.

verifying menu using python lambda, all and any functions
 

But before I start describing the verification process, let us talk a little about these functions.

The Python All Function

The Python all function will return True if all the elements in an iterable are True or if the iterable is empty. The syntax for the python all function is all(iterable). If you want to know what an iterable means, you can check out this post on iterables.

Let us take some examples to demonstrate how it works. We will use a python list for the python all examples.

As you can see when you run the example above, all the elements need to be True or it needs to be an empty list for the python all function to return True.

Note that on a dictionary, the function works on the keys of the dictionary. You can make out examples of your own and try them out.

Also, on numbers, when the number is 0, it is evaluated to be False as a Boolean expression in python and True on all other numbers.

The Python Any Function

The python any function will return True if any element of the iterable is True and will return False if none of the elements is True. For an empty list it will return False. The syntax of the any function is any(iterable).

Here is a python any function example using a python list.

You can try it out on another iterable like a string or dictionary. In dictionaries, the python any function iterates through the keys.

One more python function you need to know about for us to write this code beautifully are python lambda functions.

What are python lambda functions?

Python lambda functions are anonymous python functions which are created with the lambda keyword. They can be used to replace function objects but are restricted in syntax to a single expression. Lambda expressions are just semantic sugar for a normal function definition. They also have scopes like normal functions through which they reference variables.

The syntax of a lambda function or lambda expression is “lambda parameters: expression”. The expression is first followed by the lambda keyword, parameters represent what is passed to the function and the expression is the code that you want to implement in the function. The parameter and expression are separated by a colon.

Given the attributes of python lambda functions above, let me demonstrate how we can create one. For example, if we want to write a single expression that cubes some numbers. Instead of resorting to a normal function, since it is a single expression, we can use a lambda expression inside another function, this time, the python map function. This is an example of a python function inside another function.


cubed = list(map(lambda x: x ** 3,  [1, 2,3,4]))
print(cubed)

You can see from above that the lambda function is used inside the map function and cubes each of the numbers in the list. The lambda function contains just a single expression, x ** 3.

Now that we have all we need to carry out the menu verification program, let’s begin.

The menu verification program

So, we want to write a program that when given a list of recommended foods we want to verify each of the menu for the day whether that menu should be accepted or not. For a menu to be accepted, all the foods have to be in the recommended_foods list and none of the foods should be in the junk_foods list. So, let’s have a go at a menu and see what happens as we write the code.

Elegant, not so? Be creative. Try out your own food test for the recommended and junk foods. Use the all, any, and lambda functions to test out your skills in python.

Happy pythoning.

Generating Power Through Python Generator Functions And Iterators

In my post on python iterators, I mentioned that one limitation of using python iterators in user defined objects is that they do not allow you to have more than one pass at the iterator when you have encountered the StopIteration exception. To conveniently overcome that limitation and give you programming power, the creators of python decided to design an object that is not only an iterable and iterator, but is also a function that yields values. That object is a python generator.

Python generators are like this steel frame
 

In this post, I will describe what a generator is and the advantages conferred on your programming when you use generators.

What are python generators?

Python generators are a special class of python functions that make the task of writing iterators very simple. While regular python functions will compute a value and return it, a python generator will return an iterator that returns a stream of values. To get up to speed with iterators, you can read up this post on python iterators. In regular functions you use a return statement to return a value, but in python generators you use a yield statement to indicate each element that is to be returned in a series.

The simple definition of a generator is any function that contains a yield keyword.

Let’s illustrate this with examples.

For example, take the function of computing the factors of a number.


def factors(n):
    ''' returns all the factors of n as a list '''
    results = []
    for k in range(1, n+1):
        if n % k == 0:
            results.append(k)
    return results

In the function, factors, given a number we divide it by every number between 1 and that number. Whenever any number divides it without a remainder, that number is a factor and we store that number in the results list. At the end of the iterative division, we return the results list containing all the factors of the given number.

I want you to notice the following deficiencies of regular functions like this. 1. We had to populate the results list with all the numbers, waiting until everything was complete and then store all the values in memory. That takes up time and memory space. 2. When the function returned its results, all the variables used in the namespace of the function were garbage collected or thrown away. We can not get them again unless we call the function another time. 3. We cannot pause and resume the function if we want to.

What if we had a function that has the ability to overcome the deficiencies above and has the ability to be iterable? That is where a python generator comes in. Now, let’s use a generator to compute the factors of a number this time around. Take note of where the yield keyword is placed in the generator function.


def factors(n):
    for k in range(1, n+1):
        if n % k == 0:
            yield k

Note that in the generator function, the return statement has been replaced by a yield statement. Also, we do not need to populate the results with all the factors like we did with the regular function but since the generator function produces an iterator that iterates through the values, we yield each of the factors as needed to the iterator. What this means is that since a python generator function produces a generator iterator, we could use the generator function in a for loop.

Take the following code as an example.

Notice that the generator function produced a gen_iterator that was itself an iterable since it implements the __iter__() and also the __next__() method. The for loop was only automatically calling on those methods and yielding the results from the generator iterator which yields the results from the generator function.

A python generator function can contain more than one yield statement and it yields the values following each yield statement in turn. Taking a cue from our generator function, we can optimize it with more than one yield statement owing to the fact that the quotient of a division of a number by a factor is also a factor, and also by testing values up to the square root of the number.

Notice that while the first iteration yielded the factors in sequential order, this second implementation although it is more optimized, did not. It just goes to show that a generator function remembers where it was in the scheme of things when it yields a result and resumes operation from where it left off. This goes to show that the big difference between a yield and a return statement is that when the return statement is executed, all variables are discarded from the function, but when the yield statement is executed, the state of execution of the generator is suspended and all local variables in the namespace is preserved. It then resumes execution from where it stopped on another invocation of the generator when the caller calls the __next__() method of the generator iterator.

In the code example above, I asked the for loop to call the __iter__() and __next__() methods of the generator iterator automatically. I would like you to see a visual demonstration of how this works. I would use a command line invocation of a python generator function for this. For example, say we have a generator function that generates ints up to a given number. Let us see how it would be doing this with yield.

 

a command line example of python generator

You can see from the command line screenshot above that when we called ints_gen(3) in order to yield 3 integer values, it created an iterator. We know that iterators are defined by the __next__() method. So, when we call the next function on the iterator, it yields each of the 3 integers one after the order until it gets to the end and then raises StopIteration exception which every python iterator raises on getting to the end of their iteration. This is just a simplification of how the generator function works with an intermediate generator iterator.

One thing to note too is that generator functions can also have a return statement. They do not preclude a return statement. A generator function with a return statement will raise StopIteration exception when control flow goes to the return statement, ending all processing of values.

User defined classes with generators.

According to the documentation, writing your own user defined classes that act as generators can be a messy issue. You can make a workaround by reflecting on the fact that generator functions produce iterators, and the __iter__() method also produces iterators. So, what you do is make the class you want to have a generator to be an iterable that implements the __iter__() method and let it yield its results. Here is a python generator example as a workaround.

Happy pythoning.

Using A Python Iterator To Get Data

In the last post about python iterables, we discussed what it means to be an iterable – being able to participate in the for loop and implementing the __iter__() method to create iterator objects. There is another related concept in python that takes this ability to participate in python for loops a bit further. The concept of being an iterator. This is very important because people often get confused about what it means to be a python iterable from being a python iterator.

fractals are like python iterators
 

In fact, you are basically enabling your object to participate in python for loops or to be used to retrieve a stream of data when you implement the __iter__() method (make an object an iterable) but that is not enough because as I showed you in the user defined class in the last post, you need to implement one more method, the __next__() method to complete the process. So why you need the __next__() method is because __iter__(), which makes your object an iterable, just returns an iterator object but implementing __next__() makes it possible for you to access the elements in the iterator object and defines that object as an iterator. So, with this we are ready to define what it means to be an iterator.

What it means to be a python iterator

To be a python iterator, an object just needs to implement the __next__() method. This method helps the object to remember its state when returning the next value in the iteration, update its state so that it can point to the next value, and signals when there are no more elements in the stream by raising the StopIteration exception. That is it. An iterator is just able to remember what it is doing while retrieving a stream of data.

Python recommends that any object that implements the __next__() method should also implement __iter__() method and when doing so return the object itself. So, this makes it that python iterators are also python iterables. Remember that fact because that is where many persons get confused. We covered this in the post on iterables.

In summary, iterators are like iterables that participate in for loops or in functions like map, zip etc which need iterables and remembers where it is when retrieving items from the object.

Now that we have a definition, let’s take examples. Several built-in datatypes support iteration like lists and dictionaries, so we will use them for examples.

See what happens when you call iter() (which invokes the __iter__() method) and then next() (which invokes the __next__()) on a dictionary object which we will use as our loop in python example.

As you can see from the code above, the dictionary looped through its keys when it was used as the argument to the next method.

You can do the same thing above with any native python iterable. They were built to act as iterators.

Python has made it that when you carry out a python for loop the process of calling iter(object) and next() is automated so that you really don’t realize what is happening under the hood.

You should note that once the StopIteration exception is raised for an object, it must continue to raise that exception on subsequent calls to the next method. This is because in memory what you have is an empty container or iterator. To make the object start all over again and return the stream, you need to call iter method afresh if it is a container object like a list or dictionary, but if not, there is nothing to do but to use a python generator. This occasion is why you often do not see python iterators being used often because python generators come in handy to help you when you need multiple passes to a non-container iterator object. We will discuss python generators in the next post because they are interesting python functions, so just watch out for it.

User defined python iterators

Iterators that you define yourself in code just need to implement __iter__() which produces an iterator object and __next__() which helps you to traverse the elements in the stream of data. That’s just that; what I have been saying all along. I touched on this in the iterables discussion. This is some code that could be used to produce a user defined iterator that is based on the list datatype.

As I said before, one deficiency of iterators is that they only support one pass. If you attempt a second pass at them, they behave like empty containers. You can try it out and see for yourself. Because of this limitation on having only one pass, when I want to access the items in an object as a stream, I just use them as an iterable using python for loop. But when I want to be able to generate values, I use a generator.

Some things you can do with iterators is to materialize the iterator object as a tuple, list etc, do sequence unpacking on them, or even use the max and min functions on them.

Happy pythoning.

Python Iterables Are Not Just About Sequences

Lots of times when I read code, I see people thinking that python iterables are just about python sequences like python lists, tuples, or strings. The most culprit are python lists. When they want to create a custom class that is iterable, they would rather make the underlying data structure a list in order to make use of the methods that are supported by sequences. I want to use this post to make you understand that python iterables are not just sequences. Iterables include a whole lot of objects than just sequences.

 

First, what is an iterable?

The definition of a python iterable.

Basically, a python iterable is any object that you can loop over. The object can be a python sequence like lists, strings, tuples, bytes, or they can be python collections like dictionaries, sets, frozensets, or they can even be file objects. These are all objects that are capable of returning their members or elements one item at a time. If you so desire, you can define your own user defined objects and can make them an iterable. I will show you how in later examples of loops in python.

Also, on a practical level, you can define a python iterable as anything that can appear in a for loop. I really don’t need to give an example here but think of anything you have put on the right side of a for loop in your code and that object is an iterable. The list goes on and on. Also, anything that you can put as an argument to the zip and map functions are python iterables. Therefore, knowing how the for loop operates, we can give a technical definition of an iterable.

Technically, an iterable is any object whose class implements the __iter__() special method or if you want to specify sequence semantics, which implements the __getitem__() special method. You really need to implement __iter__() method for your iterable when you need a generalized python iterator. But if you want to play with a sequence type in your object, then all you need to do is implement the __getitem__() special method.

As I do to in all my posts, let’s illustrate the definitions above with examples. Let’s first give examples of python iterables that are not python sequences. We’ll be using the practical definition: ability to participate in python for loops.

First, we’ll show that python dictionaries are iterables. Using for loop directly on the dictionary, python iterates over the dictionary based on the keys, but it has a powerful method, items, that can help one to iterate over the keys and values at the same time.

File objects are also iterables. You can replace the ‘eba.txt’ file in the code below with any text file of your choice. All I wanted to show was that the file handling object, fh, is a python iterable since it can participate in a for loop.


with open('eba.txt') as fh:
    for line in fh:
        print(line)

Then finally what you must be familiar with, python sequences. All sequence types are iterables. But not all iterables are sequence types as we have noted above.

Python strings are iterable sequences.

Lists and tuples are sequence types and also iterable. In fact, all sequence types are iterable. They give examples of loops in python.

All the types above that are iterable are custom data types. What about user defined types? I said above that user defined types can be made iterable. How? By making them implement the __iter__() method or if you desire sequence semantics, the __getitem__() method. Let’s use the __iter__() method because later I will show you how to implement the __getitem__() method.

The Fruits class below uses a python list as the underlying data structure. We implemented the __iter__() method which returns an iterator object, itself. All implementers of this method will return themselves as iterator objects. To enable the for loop to access each of the items in the iterator object, we need to implement another method, the __next__() method. The __next__() method defines an object as a python iterator and iterators are also iterables. What the __next__() method below does is just to go through each of the items using their index, which is also a data attribute, and returning each of the items with that index. When it gets to the end of the list, it returns the Stopiteration exception to the python for loop which then stops asking for more items.

One thing I want you to note from above code is that all the built-in iterables implement the __iter__() method that is why when you explicitly call iter(object) on them, they will give you an iterator object. You can read on python iterators here.

Now, let me discuss on one special type of iterable and those are sequences.

What are sequences?

Sequences are iterables but they support looping through the items in the sequence using indices. So, everything you do with a python iterable, you can also do with a python sequence. That is why when you read code, you wonder if everyone thinks only sequences are iterables. For an object to be a sequence, it must implement the __getitem__() and __len__() special methods. I discussed using the __len__() special method on user defined objects in another post. So, all python sequences like lists, tuples, strings implement these two methods.

Let’s give an example of a user defined object that acts as an iterable by mimicking the sequence semantics. Here, the Fruits class implements the __getitem__() and __len__() methods.

This code is not different from the earlier user defined code except that this time it is implementing the __getitem__() method rather than the __iter__() method.

If you ask me, which should I use, the __iter__() method or the __getitem__() method for user defined objects? The answer is – it depends on what you want to do with your user defined objects. It is rare to see implementations of the __iter__() method because of the limitations associated with iterators and python has made it possible to produce iterators easily using generators. But it is common to implement the __getitem__() method if you want your object to behave like a sequence, or even a collection.

And if you want further functionality, you could make collections.abc.Sequence the base class for your class. When you do this, then you could be able to carry out further functionalities that sequences have like find out the count of an item, get the index of an item, find out if an item is in the object etc.

Let me give some examples. First, I imported the Sequence abstract base class from collections.abc. Then, I made it the parent class to my class, Fruits. I also implemented the __contains__() special method to be able to use the “in” operator on instances of the class. Here is some code that shows the added functionality of my new Fruits class that is separate from what the native Fruits class above could do.

We cannot end the discussion without noting how python iterables support lazy evaluation of values.

Lazy evaluation in python.

According to Wikipedia.org article on lazy evaluation strategy, this is a technique which delays the evaluation of an expression until the value is needed and which also avoids repeated evaluations. Python supports the lazy evaluation technique in iterables. For example, with the built-in python range function, we don’t need to explicitly produce all the values that are needed for the range but instead use them as when needed due to the lazy evaluation technique. This helps us to save memory. For example, take the following call to range to evaluate a million items. I decided I didn’t need to print the values beyond the 100th, so I decided to break the loop at the 101th item.


for i in range(1000000):
    if i == 101:
        break
    print(i)

If python did not use the lazy evaluation technique while producing the items, it could have produced a million items while I only required just the first 100.

Lazy evaluation is also seen when you are using the items or values functions of a dictionary. Python would only get the key or value based on when and whether you need them or not. It doesn’t just populate memory with all the keys and values. Here is a python iteration over dictionary keys and values.


fruits_dict = {'mango': 1, 'orange': 3, 'pineapple': 7, 'melon': 4}
for key, value in fruits_dict.items():
    print(key, value)

Lazy evaluation saves time and memory space. This is one feature that is very powerful in python programming.

But if on the other hand, you do need all the values from the iterator that is created during lazy evaluation, you can just cast it to a list or tuple. For example, using the range earlier, If I really needed all the million items, instead of retrieving them one at a time, I can cast it to a list and get everything at once.


range_list = list(range(1000000))

You can read up the documentation glossary on iterables and use them to your pleasure. Happy pythoning.

Python Decision Control Structures: Python while And for Loops Part 2

python while and for loops decision
 

The last post discussed on the use of the python if else, and elif statements as part of a selection control structure. Today, the second part, we will discuss on repetition control structures using python while and for loops. These control flows are used when we want to reuse parts of some code a number of times based on a condition.

The looping constructs provided by python, the while and for loops, are distinct, yet sometimes they can be interchanged except in some cases. First, we will discuss the python while loop.

The python while loop.

A while loop helps one to carry out repeated execution of a block of code based on repeated testing of a Boolean condition.

The syntax of a while loop is as follows:


while condition:
    body

Just similar to the python if statement, the condition is a Boolean expression that evaluates to True or False, and the body is a block of code. The block of code can even be nested with other control structures. The while loops starts its execution by testing the Boolean condition. If the condition evaluates to True, the body of the loop is executed. After the execution of the body, the condition is retested again. If the condition evaluates to True again, another iteration of the body is done. This iteration is repeated as long as the condition evaluates to True. The moment it evaluates to False, the loop is exited and the flow of control transfers to the statement outside the python while loop.

To make sure that the while loop doesn’t run forever, it should come to a point where the condition will evaluate to False. To do this effectively, use a counter that you initialize before the loop and that is incremented or decremented inside the loop. If on the other hand you find that you didn’t do so and your loop runs forever, just press Ctrl+C to interrupt the process.

Here is a code that loops through a list of fruits and tells us whether our favorite fruit, which we have to input, is in the list of fruits. Please, pardon me that the list of recommended fruits is short.

Notice in line 5 that the python while loop is based on two Boolean expressions:

while j < len(fruits) and fruits[j] != fav_fruit:

The first Boolean expression checks to make sure we have not gone to the end of the list and the second checks by the index, j, to see if we have the fruit in our list. After the Boolean expressions, the body of the loop is just a one-liner that increments the index to the list, j. j is being used here as an index to the list to iterate through the list whenever the Boolean expressions evaluates to True; that means we have not found a match for favorite fruit in the list. There is some python if else statements after the while loop that is used as confirmation whether a match was found or not. You can see the post on python if else statements.

This code does not run forever; it terminates no matter what the user enters. Because either we will not find a favorite fruit on the list and get to the end of the list where the loop terminates or we will find a favorite fruit on the list and the loop then terminates.

Now, let’s go to the second looping structure: python’s for loop with some examples.

The python for loop.

When you want to iterate through a sequence of elements in an iterable, the for loop is more preferred to the while loop. It can be used on any structure that is iterable, whether a sequence or collection. Sequences are python strings, tuples, range, and bytes while collections are python dictionaries, sets, and frozensets. The syntax of a python for loop is:


for element in iterable:
    body

You often use the element variable in the body code; the reason why we are iterating through the iterable in the first place is to access the elements. Readers who are familiar with java programming language would realize that the python for loop is in some sense similar to the java “for each” loop.

To illustrate the way a for loop works, let us take a list of numbers, iterate through each of the numbers in the list and add them together to get a total sum.

In the code above, the variable num iterates through each of the numbers in the list of numbers in the for loop and then at the body code, it adds the numbers to total variable to give the total sum.

Let’s take another python for loop example of getting the biggest number in the list of numbers.

We first assigned biggest variable to an arbitrary number, this time 0, and then in the for loop num iterates through each of the numbers. Each time num gets the value of one of the numbers in the list. In the body of the for loop we compare num to the biggest each time and if num is bigger than the biggest, we assign that num to the biggest variable. This comparison happens each iteration through the list in the for loop.

We could achieve the above code using a while loop but we would need to use an indexing method. Indexing with for loops will be described below. But note that some collections like sets cannot be done using while loops because they cannot be indexed.

Now let’s implement a for loop using an index into the elements of the iterable.

Python for loops using an index

There are occasions where we might want to know where an element resides within an iterable. The traditional application of the for loop does not give us that benefit of location. But we can get that effect by indexing into the iterable using a python range function. The range function will generate a sequence of numbers that serve as the indices into the iterable or sequence. The syntax for the for loop is:


for element in range(len(iterable)):
    body

Note how the python length function provides the number that range will use to generate the indices for looping through the iterable. I have a post on the python length function. You can check it out to further understand the syntax above. Now, let’s take some illustrative example. Suppose we want to get the biggest number like we did above but using the indices in the loop, we could implement the code this way:

We eventually implemented the same code like before but instead of iterating directly through the numbers in the list, we used the indexing method to iterate through the numbers.

Note that the index variable above is an integer which is derived from the range of values generated by the range function.

I think we have basically covered the essential points for python while and for loops. But we will not close the chapter without talking about two important statements that have an influence on the iteration of a while and for loop – the python break and continue statements.

The python break and continue statements

Both of these statements interrupt the operation of a while or for loop but in different ways.

The break statement terminates the execution of the loop and transfers control to the next statement in the code. It is usually used to check for the trigger of a condition in the loop and when that condition is satisfied, the loop is terminated.

For example, let us say we want to loop through the list of numbers above to stop when we get a 9. This is how the code could be written. Watch how the python break statement was inserted into a control flow block.

If you run the code above, you will notice that the loop is iterating through each of the numbers until it gets triggered when num is 9. When this condition is reached, the loop terminates and the rest of the numbers are not referenced.

Use the break statement sparingly. It has great power.

The companion loop interruption statement is the python continue statement. The continue statement is usually employed when we don’t want a set of statements in the body of the loop to be executed when a condition is triggered. When triggered, control passes to the next item in the loop; the loop is not terminated.

An example will suffice.

I used a python while loop this time around. The Boolean expression in the while loop checks for when we have looped through all the elements in the numbers list. For each num we are looping, we first check if the number at that index is 0, if it is not zero, we use it to divide the numerator and print out the result, but if it is zero, we tell the program to ignore that number, don’t use it to divide the numerator, and move on to the next number in the loop using the continue statement. This is a very convenient way to program. That is why I love python.

Notice on line 6 and 10 that each time I increase the index by 1 so that the loop can proceed. This makes sure we do not find ourselves in an infinite loop that doesn’t end.

Take your knowledge to new heights. Experiment with the looping constructs introduced here. It’s a joyful thing programming in python.

Matched content