Search

Python Decision Control Structures: The Python if else Statement - Part 1

 

decision making in programming in python

We all need to make decisions. We decide on what to eat, what to wear, what to learn, or where to work. Computers also make decisions; at least, the decisions we code. You designate what decision you want a program to make using control structures in your code.

A control structure is a block of programming that analyses one or more variables and then decides on what to do next based on the parameters given by the variables. Another word for control structures is flow of control. Given conditions and parameters, this is the decision making construct in any program.

There are three types of control structures or control flow. They are the sequential, the selection, and repetition control structures.

  1. Sequential control Flow
  2. This is when you execute statements one after the other in the order they appear in the program. Provided there are no syntax or semantic errors, the statement will run from the first to the last statement.

    Here is the flow chart for the sequential control flow. 

    python sequential control flow chart
     

  3. Selection Control Flow
  4. This involves choosing between two or more alternative paths, based on the evaluation of the conditional statement.

    Here is a typical flowchart. 

    python if else statement control flowchart
     

    Selection control flows are usually implemented as python conditional statements and could be a python if statement, python if else statement, or python if elif else statement.

  5. Repetition control flow
  6. This involves repeating a series of statements several times based on the evaluation of a conditional statement.

    Here is a typical flowchart. 

    python while and for loop flowchart
     

    Repetition control, or sometimes called iteration control, flows are usually implemented in python using the while and for loops.

Apart from the sequential control flow, the selection control flow which makes use of conditional and the repetition control flow which makes use of loops all consist of a condition to be evaluated and a body of statements. You use the python syntax for defining blocks of code to help python interpret your statements appropriately. This involves using the colon character to delimit the beginning of a block of code that acts as the body for a control structure. If the body is just a one-line statement, you can place it on the same line with the condition being evaluated and just after the colon. Or you could decide to place it on a separate line. But if the body is more than one line, you use python’s principles of indentation to place it on a separate line after the colon. Using indented blocks to designate the body helps python to interpret the code as a group of statements belonging to the same control flow. You should already be familiar with python’s principle of indentation. But let me just give some examples with a python while loop.


# using a while loop to show block indentation
while n < 5:  #use colon to show block of code comes next
    # indent the block of code in body by 4 spaces
    print(n)
    n += 1

In any program, you could end up using one, two or all of the control flows. In this post, we will discuss about the selection control flow, while in the next part we will discuss the repetition control flow.

Python implements the selection control flow using conditionals.

Conditonal statements.

Conditional statements in python, also known as the python if statement, if else statement, or if elif else statement, are a way for one to execute a chosen block of code based on the run-time evaluation of one or more Boolean expressions. You usually write the conditional or python if statement in the following way:


if first_condition:
    first_body
elif second_condition:
    second_body
elif third_condition:
    third_body
else:
    fourth_body

Each condition is a Boolean expression that evaluates to True or False, and each body consists of one or more statements that are executed conditionally. On the success of the first condition, the body is executed and no other condition is evaluated after that. But if it fails, the next condition is evaluated for whether it will succeed or fail. When any condition succeeds, all other conditions are discarded and only the body of the condition that succeeds is executed. If none of the conditions succeed, the else body is executed. Note that precisely only the body following a successful conditional will be executed, and sometimes none at all if there is no else statement.

In the example code above, I used two elif statements. You can use any number of elif statements, including zero.

Note that when you want to evaluate a conditional in the if statement, you are evaluating it based on whether it resolves to True or False. In some cases, if you are not evaluating the Boolean expression based on a specific value but on whether the variable has value, you don’t need to evaluate for True or False because every variable is already True when it has a value. You only write out the variable name.

For example, don’t do this:


if fruits == 'True':
    print('Fruits variable has a value')                

Rather you produce more optimized code if you write it like this, omitting the test for True:


#I removed the test for True
if fruits: 
    print('Fruits variable has a value')                

The elif and else statements in conditional constructs are optional. Let’s illustrate all with examples.

  1. Where only the python if statement is used.
  2. 
    if hungry:
        eat_food()
    
  3. Where the python if else statements are used.
  4. Some call this the python if then else statement which is a correspondence to other programming languages like java.

    
    if hungry:
        eat_food()
    else:
        sleep()
    
  5. Where only the python if elif statements are used.
  6. 
    if hungry:
        eat_food()
    elif tired:
        rest()
    
  7. Where all three statements, if elif else statements, are used.
  8. This looks like a case switch statement in python; a throwback from java.

     
    if hungry:
        eat_food()
    elif tired:
        rest()
    elif bored:
        watch_tv()
    else:
        sleep()
    

So I have outlined four different ways the conditional construct can be used. Note that only the if statement is required; the others are optional.

One other thing I need you to know about the block indentation so you don’t run into problems. When you have code you want to specify that is not included in the body of the conditional construct, you need to take back your indentation by 4 steps. For example, if after the else block below I want my program to shift control to another activity which does not lie in the conditional construct, i.e do_next_activity(), my indentation goes back 4 steps.


if hungry:
    eat_food()
else:
    sleep()
# this is not part of the conditional construct
# it goes back 4 steps in indentation    
do_next_activity() 

From above, do_next_acitivity() goes back 4 steps and is not part of the indentation for the conditional constructs. It does not participate in the indentation.

Lastly, we have python nested if statements.

Python nested if statements.

We may nest one control structure within another, and to do this successfully, we rely on the indentation to make our intent clear to python. Let’s take our if statement a bit further and nest it.


if hungry:
    if food_exists:
        cook_food()
    else:
        buy_food()
    eat_food()
do_next_activity()                                   

You can now see that we have a nested if statement within another if statement. All you need to do is to be careful about making sure your indentation is correct.

We can illustrate the nested conditional construct above with a traditional flowchart. That makes for easy understanding.

python decision making flowchart

In the next post, I will discuss on the repetition control flow which consists of the while and for loops.

The Python Length Function: A Quintessential Size Measuring Tool

There is a built-in function in python that is versatile. It can be used to measure the number of items or length of any object. That function is the python length function. It is denoted as len(s). It is a quintessential tool. I have found it useful on so many occasion and I believe you have been using it without giving a second thought to how important it is to your programming work. In this post, I will describe the objects it can be used for and some of the benefits of the python length function.

 

python length function

The syntax of the python length function.

The syntax of the built-in python length function is len(s) where s, the argument, can be any sequence or a collection. A sequence as you must know is any object that is either a string, byte, tuple, list, or range. A collection can be either a dictionary, set, or frozen set. We will be showing how the length function can be used for each of these. As we already are aware, the function returns the number of items of an object passed to it, but if you fail to pass it an object or you pass it an invalid argument, it will return a TypeError.

I have noticed that many beginners associate a sequence with python lists and so they think that the python length function only calculates python list size. Well, in these examples, I want you to think of other objects as sequences.

Examples of its use on sequences.

Here are some examples of its use on sequences and collections.

  1. First, on strings and byte objects.
  2. Notice that they correctly returned the same number of items when the len function was called on them.

  3. Also, on lists, tuples, and range, see how it works.
  4. And finally on collections like python dictionaries, sets, and frozensets.
  5. You will notice that I was converting from the dictionary to set and frozensets. I wanted the examples to be correspondent. Note that frozensets are immutable while sets are mutable.

Now, let’s go to the application of the python length function. That’s the fun part.

Application of the python length function.

There are several uses of the python length function. As we have already described, it gives the length of an object. But its usefulness gives performance optimization when you are writing code. In the examples above, I give instances where the object length is extremely useful and how the len function is used in those instance.

  1. Used as argument to the range function.
  2. When using the range function you need to pass it an integer argument for it to compute a range. When you want to iterate over the items in a sequence and this is based on the length of the sequence, then the len function comes in handy to provide the integer argument that the range needs. The range items can then be used as indices to the sequence. Let’s show with an example:

  3. When object length is required for conditionals.
  4. There are times you want to compare objects based on their length. The python length function comes in handy in this case. Here is an example.

These are two common examples I have seen in code where the python length function is widely used.

Using the python length function in user defined objects.

Often, we might want to use the len function to find out the number of items a user defined object contains, especially when the underlying data structure of the user defined object is a sequence. You need to implement the __len()__ special method to be able to do this. When you call len(sequence) on an object, under the hood, it calls the __len__() special method of that object. So, this gives us the ability to just define a __len__() method for our user defined objects and they would behave like sequences and collections when it comes to using the python length function.

So, here is some code.

In the Fruits class, I set the initial items to be the empty list, that is, when a fruit object is instantiated, it does not contain any fruit. Then, we need to add fruits to the basket. Before adding fruits, I defined an add_fruit method which first checks that the fruit you are adding is an instance of a string. All fruit names are strings by default. Then if that comes through, I add the fruit to the list of items. Then, we implemented the __len__() special method in order to calculate the length of the list after fruits are added. Without implementing this special method, we could not use the python length function with the f1 object which is an instance of the Fruits class.

One way of thinking about the built-in python length function is that it is calling on the implementation of the __len__() special method of the object passed as argument. You could think of it as acting as this:


def len(x):
    return x.__len__()

I believe you have all you need to use the quintessential python length function. Be creative. Go write some code using this python length function.

An Innovative AI-powered Computer Vision And Gesture Recognition System

How does the brain interpret what we see and how can computers be made to mimic the natural workings of the human brain when it comes to sight? That is the question that computer vision technologies seek to answer. Today, many technologies use computer vision in artificial intelligence, or AI. This AI rely on neural networks and they have to process a large amount of data in a very short space of time. Many AI-powered computer vision systems have been introduced into the market and they are being used in hi-precision surgical robots, as health monitoring equipment and in gaming systems. Heard of the Google computer vision, or Google cloud vision API? Those are examples. But engineers want to go beyond these computer vision applications. They want the AI-powered computer systems to recognize human gestures so as to complement its visual capabilities. That is why gesture recognition technology has become a hot topic in computer vision and pattern recognition.

artificial intelligence computer vision and gesture recognition system
 

The drive to create AI systems that recognize hand gestures came from the need to develop computer systems and devices that can help people who communicate using sign language. Early systems tried to use neural networks that incorporate the ability to classify signs from images captured from smartphone cameras while this data is converted from pictures to text. They were systems that involved computer vision with image processing. But AI systems have grown more advanced and more precise than those humble beginnings. Today, many systems seek to improve on this visual-only AI recognition system by integrating input from wearable sensors. This approach is known as data fusion.

Data fusion is the process of integrating more data sources into computer systems that make these systems more reliable and accurate than if the data was coming from a single source. AI-powered computer vision systems incorporate date fusion using wearable sensors that recreates the skin’s sensory ability, especially the somatosensory functionality of the skin. This has resulted in the ability of computer systems to recognize a wide variety of objects in their environment and increase their functionality and usefulness. But there are still challenges which hamper the precision and the growth of these data. One of these challenges is that the quality of data from wearable sensors are low and this is as a result of the fact that wearable sensors that have been produced are bulky and sometimes have poor contact with the user. Also when objects are visually blocked or there is poor lighting, the ability of these AI-powered systems are reduced. One area that has been troubling to engineers is how to efficiently merge the data coming from the visual and the sensory signals. Therefore, this has led to information that is inefficient, resulting in slower response times for gesture recognition systems.

In an innovative approach that is said to solve many of these challenges, a team of researchers at the Nanyang Technological University, Singapore (NTU, Singapore), have created an AI data fusion system that drew its inspiration from nature. This system uses skin-like stretchable sensors made from single-walled carbon nanotubes. This is an AI approach that closely mimics the way the skin’s signals and human vision are handled together in the brain.

How the NTU artificial intelligence gesture recognition system works

The NTU bio-inspired AI system was based on the combination of three neural network approaches. The three neural networks that were combined are: 1. a convolutional neural network which is an early method for visual processing, 2. a multi-layer neural network which was used for early somatosensory information processing, and 3. A sparse neural network which fuses the visual and the somatosensory information together.

Therefore combining these three neural networks makes it possible for the gesture recognition system to more accurately process visual and somatosensory information more efficiently than existing systems.

The lead author of the study, Professor Chen Xiaodong, from the school of Material Science and Engineering at NTU says that the system is unique because it drew its inspiration from nature and tries to mimic the somatosensory–visual fusion hierarchy which is already existing in the human brain. According to him, no other system in the gesture recognition field has undertaken this approach.

What makes this system particularly accurate in data collection is the fact that the stretchable skin sensors used by the researchers attach comfortably to the skin and this makes the data collection process not only more accurate but makes it to deliver a higher-quality signal which is vital for hi-precision recognition systems.

The researchers have published their study in the scientific journal “Natural Electronics”.

High accuracy even in poor environmental conditions

As a proof of concept the bio-inspired AI system was tested using a robot that was controlled through hand gestures and then the robot was guided through a maze. It was discovered that the AI system was able to guide the robot through the maze with zero errors, compared to the six recognition errors from another visual recognition system. It then seems evident that this bio-inspired AI system is more accurate and efficient.

Also it was tested under noise and unfavorable lighting conditions. Even under this unfavorable conditions the bio-inspired AI system still maintained its high accuracy. When it was tested in the dark, it worked efficiently with a recognition accuracy of over 96.7%.

The authors of this study said that the success of their bio-inspired AI system lies in its ability to interact with and complement at an early stage the visual and somatosensory information it was receiving even before any complex interpretation is carried out. This makes it possible for the system to rationally collect coherent information with low data redundancy and low perceptual ambiguity with better accuracy.

Promise of better things to come

This innovative study shows a promise of the future. It helps us to see that humans are one step closer to a world where we could efficiently control our environment through a gesture. Applications that could be built for such a technology are endless, and it promises to create a vast amount of opportunities in Industry. Some examples include a remote robot control over smart workplaces along with the ability to produce exoskeletons for those who are elderly.

The NTU team are aiming to use their system to build virtual reality (VR) and augmented reality (AR) systems. This is because their system is more efficiently used in areas where hi-precision recognition control is required such as in the entertainment and gaming Industries.

Material for this post was taken from a press release by the Nanyang Technological University, Singapore.

Python List And Sequence Comparisons And Sorting Based On Lexicographic Orders

According to the documentation, comparing sequences is done based on lexicographic order. That is just a way of saying that comparisons between sequences are done based on their position in dictionary order if alphabets, and if they are integers, based on their position in the number line. Comparisons could be done using the lesser than operator, <, the greater than, >, operator, or the equal to, ==, operator. It really gets interesting when you are dealing with sequences that have a mix of both alphabets and numbers. These comparisons and many other comparisons are what we will be discussing in this post. We will also show that the python list sort method and python sorted function are based on comparisons.

Colorful drinks sorted like python lists
 

Note that these comparisons are Booleans. That means, they give you True or False when these items are compared.

Let us compare two lists in python and see how the comparison works on sequences. When objects are to be compared, they must be of the same type. If they are of different types, python will return a TypeError.

  1. When the two python sequences are of the same length and type.
  2. The code above compares n and m which are python sequences of numbers. You can see that they both only differ in their last items in the python list. I just used this example to show you that when python compares two sequences of the same type each index is compared to the corresponding index until a mismatch is found, and then based on the lexicographic order, one could be found to be greater than, lesser than, or equal to the other. In the code above, n was lesser than m because index 2 in n, which is 3, is lesser than index 2 in m, which is 4. Indices start from 0.

  3. When the two python sequences contain items of different types
  4. When the two sequences being compared have items of different types, python will return a TypeError. Note the code below.

    When run, the above code returns a TypeError because string and integer types cannot be compared.

  5. When the two sequences are the same length and contain the same items of the same type.
  6. When you run the code, you would realize that they compare equal. What python does is walk through each item and compare them index to index. In this case, all the items compare equal. But what if one list is shorter than the other and all the items compare equal. What does python decide? See the code below.

    When the code above is run, you would see that python takes the shorter of the two sequences as the lesser one when they compare equal, index for index. It now uses the len function to decide on the equality or non-equality of the two sequences.

I have used python lists in these examples, but you can use any sequence like a python string, tuple, or range.

Comparison of user defined objects

Can we take this notion of comparison to user defined objects? Yes, of course. You can provided your user-defined object has the appropriate comparison method. Or in other words, provided it implements the __lt__(), __gt__(), or __eq__() special methods. If that is the case, you are good to go. Here is an example of how comparison could be done on user defined objects.

When you run the code above, you can see that objects of the Length class can compare themselves even though they are not sequences.

This ability to overload native methods and python operators gives a programmer great power. That power comes with enormous responsibility. One of such power is the ability to use the concept of comparisons to carry out sorting. Python has two functions to do that, and they are the built-in python sorted function and the list.sort function that comes with the python list class. These two functions work based on the concept of comparison to sort items in sequences. We would be using the built-in sorted function since it is generic.

The python sorted function

The sorted function creates a new sorted list from any iterable. By default, it sorts based on lexicographic order and in ascending fashion. Take the following code for example.

When you run it, it sorts the list of fruits in dictionary or lexicographic order. The underlying mechanism at work is a comparison of each of the fruit items. That is why you could change the order of the sort. The sorted function has a reverse keyword argument that you can use to do that. By default, reverse is False but you can switch it to True to sort in reverse lexicographic order. Let’s do it.

After running the above, you can see that when I set the reverse argument to True, it sorted the items in the fruits list in reverse order.

There is also another keyword argument that is useful when you have items in a tuple or a nested list and you want to specify which order to sort the items. For example, if we have a list of tuples comprising names and ages, how do we sort the list such that the ages takes more prominence in the sorting order before the names? This is best defined using the key keyword argument in the sorted function. In the code below, I would use a lambda function to specify what the key should be. Lambda functions are anonymous functions. The lambda function will sort or compare the items in the python list based on their ages.

As you can see, ‘David’ who is 20 years old comes first in the list, followed by ‘Rose’ who is 25, then by the two other students, ‘Michael’ and ‘Daniel’ who are both 32. But there is a problem with the sorting. The sorting is not yet complete. If Daniel and Michael are both 32 and compare equal for ages, then naturally we should expect Daniel to come before Michael in the sorted list. That’s right. So, let’s add one more power to our key. This time, we would tell the key argument to first compare by age, and if ages are equal, to compare by names. The code below shows how it is done. The only difference from the above code is that I added x[0] to the statement in the lambda function and that makes it possible because for each item in the list, x[0] is for names while x[1] is for age. To make them compare equal, I then cast the key for age to a string.

Here is the code.

We now have a well sorted list where ‘Daniel’ comes before ‘Michael’.

Let’s take this a bit further and give more power to sort any object, not just custom data structures like sequences. We could extend this power to our custom Length class that we described earlier. Let us be able to sort any sequence that has Length objects.

This is somewhat simple because I have already given Length objects the power to compare themselves. Remember, sorting depends on comparison. So, having this power, we can do sorting on length objects.

The only functions added to the code above for the Length class is the __str__() special method. This gives us the ability to print out the values of the objects, as well as the sorted function.

So, I encourage you to use this power with responsibility. Python gives you lots of power to do all sorts of things with your objects, even to compare and sort to your desire.

Do Face Masks Really Protect Against Covid-19 As Claimed?

Public health officials have launched a protracted campaign to make us believe that wearing a face mask prevents the spread of Covid-19, the latest pandemic. But is this true? That was the question on the mind of a Duke physician, Eric Westman, who was a champion for people putting on masks. He wanted to be sure that he was recommending the right prevention technique to people and businesses. So he decided to carry out a proof-of-concept study. A proof-of-concept study is a study that aims to test whether a technique or method is really as effective as claimed. Also it is used in science as a testing phase to verify the feasibility of a method, a technique or even an idea. When scientist carry out an investigation in science, they start with an idea like this.

face mask like this are good against pandemics
 

Doctor Westman was working with a non-profit and he needed to provide face masks to people. He was also skeptical about the claims that mask providers were making about how effective their marks were against a pandemic like covid-19, so he went to a chemist and physicist at the University, Martin Fischer, Ph.D. and asked him to carry out a test on various face masks. The test they did was based on both surgical masks used in medical settings and cloth face masks. They also carried out tests on bandanas and neck fleeces used by people who claim they can prevent the spread of covid-19.

Fischer’s line of work usually involves exploring the mechanisms involved in optical contrast while doing molecular imaging studies. He was intrigued by the doctor’s challenge so he set out to help him. For the study he used materials that were freely available; something that can easily be bought online. These materials include a box, a laser, a lens, and a cell phone camera.

From the study it was reported that it proved positive and showed that face mask were effective at preventing the spread of Covid-19. They recently published their scientific study article in the journal “Science Advances”. Despite this being a low cost technique, it helped to prove that face mask prevent droplets coming out of the mouth while speaking, sneezing or coughing from being transmitted from one person to another. They reported that while carrying out the study they could see that when people speak to each other, cough, or sneeze that molecules of droplets are passed from one person to the other. They also confirmed that it is not all masks that are effective at preventing the spread of droplets. Some face coverings were seen to perform better than others in preventing the spread of droplets.

So how did the masks compare? They tried out the proof-of-concept study on various masks and compared their effectiveness. They found that the best masks were the N95 masks which were used in medical settings. They also found that surgical masks and masks made of polypropylene were equally effective in preventing the spread of droplet molecules. Face masks which were made from cotton allowed some molecules to pass through but were found to have good coverage. They could eliminate several droplets that were being passed when people were speaking. Overall it was shown that bandanas and neck fleeces should not be used at all or recommended as face covering. This was because they were ineffective in blocking the spread of droplet molecules.

When the physicist was asked if this was the final word on the subject, he replied in the negative. Therefore more studies need to be carried out because this is just a demonstration to show the effectiveness of various face masks. The study was done to help businesses see that they can carry out these tests themselves before investing on any type of face mask or face covering.

When asked on the benefits of the study, Westman, who was inspired to start it, said that many people and businesses have been asking him about how they could test all these face masks that were new in the market. So he decided to show that businesses could carry out the tests themselves with very simple materials. He said that the parts for the testing were easily purchased online and they were putting out this information to help others.

As they hoped, they have shown that various face coverings that were being promoted by public health officials were indeed effective in preventing the transmission of molecular droplets from one person to the other.

Although this is just a proof-of-concept and not a rigorous testing technique, one can confidently recommend the use of face masks to individuals and businesses because they really work in preventing the spread of covid-19. My advice to everyone is to stay safe, wear a face mask, and help stop the spread of covid-19. We will see an end to this soonest. Please, carry out social distancing and regular hand washing to prevent the spread of this current pandemic.

Material for this post was provided by the dukehealth.org website.

Application Of The Built-in Python Enumerate Function

python enumerate function
 

How many times have you ever wanted to loop through a list or tuple while keeping count of the number of times and you ended up doing it with a for-loop? For beginners, I think the answer would be many times. But that is not pythonic. For example, I notice this code often among many python programmers who are not aware of the existence of the built-in python enumerate function. They keep an antipattern consisting of a range over the length of a list while keeping a running total of how many times they have gone through the range object created.


fruits = ['mango', 'pawpaw', 'lettuce', 'orange', 'banana']
for i in range(len(fruits)):
    print(i, fruits[i])

Please, if you are doing this, it is harmful to your code and not pythonic because your code is not easy to read and is vulnerable to your making typing errors.

To prevent code like this, python has a nice function that does it elegantly called the python enumerate function.

The python enumerate function

The syntax of the python enumerate function is enumerate(iterable, start=0). This is a function that accepts an iterable as first positional argument with a start value for the counter to the iterable. The default for the start value is 0 but you can specify a starting value of your choice. When you enumerate an iterable, it gives you an enumerate object. The benefit of such an enumerate object is that it is an iterator with which you can use a for loop to return a count of the items in the enumerate object. We will get to that later. But let’s see how it works with an example of enumerate.

If you run the above code, you will find that the python enumerate function gives an enumerate object. Now, let’s loop over the enumerate object.

In the above code, I used the default start of 0 and you can see that when the counter was printed, the counter started from 0. We can tweak that feature to get a starting counter of our choice. Now for some examples of enumerate function.

So, you can see how powerful this little known feature in the python programming language is. The enumerate function gives all iterables an advantage the python dictionaries already have, which is an index notation that is compact and reliable.

So, the next question is: what can we do with the python enumerate function?

The simple answer is a lot.

Application of the python enumerate function

  1. Add a counter to a list or iterable
  2. .

    Just as in the example I gave above, there are lots of times we want to add a counter to a list or tuple, especially if it is a large list or tuple. This handy function makes it possible. You can use the counter as a key to get an item in the iterator that you want to use. For example, you have an extremely long list of cars and you want to be able to know them by number. You could use enumerate to give them a count value starting from any number and then retrieve each car based on the counter.

    For some example:

    What if we wanted to know the first, or third car?

  3. Convert to a list or tuple
  4. .

    We could convert the python enumerate object which is an iterator to a list or a tuple and use the handy functions of python lists or tuples. It is so easy to do. Just use the enumerate object as the argument to the list or tuple and it is easily done. When you have the enumerate object as a list, you can then use python list functions on them instantly.

    Here are some code examples.

    You can see from the above that I used the index of the cars_list list to get the last item in the list of cars, and then used the len function of the list to find out the number of cars in the list.

You can read about the rationale for the enumerate function from PEP 279 and its documentation at python.org.

Matched content