Loops in Python
Loops in Python
Hi, and welcome back to Python 101. In the third chapter of this course, we will have a look at how to control the flow of the program using loops. The programs in this chapter are a little more complex than we have encountered before. At the same time, they will give you a sense of doing meaningful stuff with Python. So brace yourselves. Let's look at the topics we will wrap up in this chapter:
- Programs you'll be able to compose by the end of this chapter: String Palindrome, Highest Common Factor, Caesar Cipher.
- The while loop: while loop, infinite while loop
- The for loop: for loop, using builtin range() function
- Exiting loops prematurely: break, continue
- Else clause in loops
- Nested loops: loop within a loop
- A Few General Things: generating random numbers using randint() & randrange()
- On the agenda in next chapter
Let's have a look at the kind of programs you will be able to comprehend and compose yourself by the end of this chapter...
#1 String Palindrome
## Determine whether a given string is a palindrome or not. You are not allowed to use the builtin reversed() function. ## A string is a palindrome if it is spelt the same way backwards as it is spelt forwards e.g. 'malayalam', 'step on no pets', 'level'. ## THOUGHT PROCESS: Prompt the user for a string -> assign it to a variable, cast if necessary -> set a flag with a default value -> iterate over first half of word and set the flag to False if any pair of corresponding characters from the beginning and from the end are not the same(keep in mind that first and last character indexes are 0 and ( length - 1 ), respectively) -> Break from the loop if any mismatch occurs -> output the conclusion ## INPUT enteredString = input("Please enter a string to be tested: ") isPalindrome = True ## starting with a True flag, will switch it to False if any mismatch in corresponding positions occurs. ## LOGIC # Comparing characters from the first half of the word with those in the second half, and if any pair of characters in corresponding positions from the beginning and from the end do NOT match, set the flag to False. ## PSEUDO CODE / ALGORITHM # With a for loop, iterate over each character in the first half of the word using indexes # Check if character at position x is NOT equal to character at position (length of word - x - 1) # Set flag to False as soon as the above condition is satisfied # Break from the loop for characterPosition in range(0, len(enteredString) // 2): if enteredString[characterPosition] != enteredString[len(enteredString) - characterPosition - 1]: isPalindrome = False break ## Outputting Conclusion if isPalindrome: print("'" + enteredString + "' is a palindrome.") else: print("'" + enteredString + "' is not a palindrome.")
#2 Highest common factor
## Compute the highest common factor of two positive integers ## Highest common factor is the greatest common divisor of two numbers e.g. 10 for 20 & 30, 5 for 5 & 25, 25 for 50 & 75 ## THOUGHT PROCESS: HCF will be less than or equal to the smaller of the two numbers and greater than or equal to 1, since 1 is a factor of every number. So we initialize the HCF variable to the smaller of the two, and loop backwards to one and as soon as we find a number which evenly divides the two numbers, we declare it our hcf. ## INPUT firstNumber = int(input("Enter the first number: ")) secondNumber = int(input("Enter the second number: ")) ## LOGIC # Starting from the upper limit of the highest common divisor i.e. the minimum of the two numbers, check whether it properly divides the two numbers. If not, decrement the number by 1 and repeat the process. As soon as the while loop finds a number which properly divides the two numbers, the current value of hcf variable is the true value of hcf, and it doesn't execute the loop anymore. ## PSEUDO CODE / ALGORITHM: # Initialize hcf to the smaller of firstNumber & secondNumber # While hcf does not evenly divide firstNumber or hcf does not evenly divide secondNumber do # Decrease the value of hcf by 1 # Report hcf as the greatest common divisor of firstNumber and secondNumber hcf = min(firstNumber, secondNumber) while firstNumber % hcf != 0 or secondNumber % hcf != 0: hcf = hcf - 1 ## OUTPUTTING CONCLUSION print("The greatest common divisor of", firstNumber, "and", secondNumber, "is", hcf)
#3 Caesar Cipher
## Implement a Caesar Cipher that shifts all the letters in a given message by an given number of places. ## Example of Caesar Cipher: 'Hello' becomes 'Khoor' when characters are shifted by 3 places. 'Can you read this?' becomes 'Kiv gwc zmil bpqa?' when characters are shifted by 8 places. 'Can you read this?' becomes 'Zxk vlr obxa qefp?' when characters are shifted by 3 places in the backwards direction. ## Julius Caesar was a Roman dictator who came up with a clever way of passing confidential information to his generals without having to worry about it falling into the wrong hands. He shifted each letter in the message by a fixed shift value i.e. if the shift value was 3, a became d, f became i and so on. He would leave the numbers and other characters untouched. His generals would only need the shift value to decode their emperor's message. Later on, this cryptography technique came to be known as the Caesar Cipher. ## THOUGHT PROCESS: Prompt the user for the message to encrypted and the number of places each character should be shifted by in the encrypted message -> initialize the encrypted message to an empty string -> begin a for loop to process each character in the entered message -> branch the control into three code blocks, to process uppercase, lowercase and non-alphabet characters separately -> for uppercase and lowercase characters, calculate the position of the character by subtracting Unicode value of the first letter i.e. 'a' or 'A' from the Unicode value of the character -> calculate its new position by adding the shift value and obtaining the remainder on dividing by 26 -> convert the new position into character form using the builtin chr() function -> append the new character to the encrypted message -> for non-alphabet characters, append them to the encrypted message without shifting -> output the encrypted message. ## INPUT message = input("Enter the message you want to encrypt: ") shiftValue = int(input("Enter the places you want the characters to be shifted by: ")) ## PSEUDO CODE / ALGORITHM: # Initialize the newMessage to an empty string # Using a for loop, process each letter in the following way: # Determine whether it's lowercase or uppercase using an if statement, proceed accordingly: # using ord(), determine its position in the alphabet(0-25) # calculate its new offset by adding the shiftValue and getting the remainder on dividing by 26(for taking care of shiftValue > 26) # convert the position to character by using chr() # append the new character to the newMessage # If the character is not an alphabet, append it to newMessage as it is, without shifting. newMessage = "" for character in message: if character >= "a" and character <= "z": position = ord(character) - ord("a") position = (position + shiftValue) % 26 newCharacter = chr(position + ord("a")) newMessage = newMessage + newCharacter elif character >= "A" and character <= "Z": position = ord(character) - ord("A") position = (position + shiftValue) % 26 newCharacter = chr(position + ord("A")) newMessage = newMessage + newCharacter else: newMessage = newMessage + character ## OUTPUTTING RESULT print("\nHere is the encrypted message: \n\n" + newMessage)
The while loop executes a sequence of statements until a given condition becomes false. Let's see what we mean by that, I'll walk you through the example later.
>>> a = 4 >>> while a > 0: print(a) a = a - 1 # Press return(Enter) twice after this line to let the interpreter know you are done with the body of the while loop 4 # Output of while loop 3 # Output of while loop 2 # Output of while loop 1 # Output of while loop
So what did we did we just do? You would have guessed it already, but here is how it went: we declared a variable a and set it to the value of 4. Then, we told the interpreter that while a is greater than 0, execute the following statements. We print the value of a and then decrement it. The interpreter does just what we expect it to, it executes those two statements 4 times, reducing a by 1 each time.
Here's how you would use the while loop in a situation that makes more sense.
## Short program to keep prompting the user for password till he/she enters the right password. # The right password is the ever so secure word 'letmein' password = "" # empty variable used in the while condition while password != "letmein": password = input("Enter password: ") # statement to execute after the while loop print("Access granted") ## SAMPLE RUN: Enter password: evil Enter password: mandark Enter password: mojo-jojo Enter password: letmein Access granted.
Granted, you would like to limit the number of tries a user gets, but you get the point, right? Okay, so that was while, but that's not all there's to it. We'll return to it later with break, continue and using else in loops.
Infinite while loop
Have a look at the following statements:
# Case 1 a = 10 while a > 5: print("Stuck in an infinite loop.") # Case 2 while True: print("Hi")
In both these cases, since there is no statement in the body of the while that will make the condition false, the loops will run endlessly and you will see a series of statements being printed onto the screen. This is known as an infinite loop. You can exit an infinite loop by pressing Ctrl + C in Windows, or Cmd + C if you are on a Mac. Infinite loops are not necessarily evil, as long as you know how to use them to your advantage, which is exactly what we will cover in the break subsection of the Exiting a loop prematurely section, below.
The other kind of loop in Python, is the for loop. A for loop goes over each element in a sequence (be it a string, a range, a dictionary, a list, a tuple or a set) one by one, gives the element an alias of what we specify, and executes the indented statements by replacing the occurrences of the alias with the element. Doesn't sound convincing, does it? Trust me, you'll get what I mean in an instant by the following example:
sampleString = "sequence" for letter in sampleString: print(letter) ## UPON EXECUTION s e q u e n c e
Note that the alias may or may not be used in the body of the for loop, it may only be used as a loop counter, like this:
for letter in "sequence": print("Hi") ## UPON EXECUTION Hi Hi Hi Hi Hi Hi Hi Hi
Using range() in for loop
For a more sensible program that employs for loop, we need to look at the builtin range() function. The range(1, 10) function gives us an immutable sequence of numbers from 1 till 9 i.e. it does not include the upper bound. Immutable, as we discussed while going over strings, means that you cannot alter a range using indexes.
>>> range(1, 5) range(1, 5) >>> type(range(1, 5)) <class 'range'> >>> range(5) # When called with only a single argument, a range spanning from 0 to the specified number is created. range(0, 5) >>> r1 = range(0, 5, 2) # When a third argument is specified, it indicates the step size i.e. difference between each element in the sequence. In this case, the range will consist of 0, 2, 4. The default value for step size is 1. >>> r2 = range(5, 0, -1) # produces a range from 5 to 1 >>> >>> >>> # Using range() in a for loop >>> myRange = range(1, 5) >>> for number in myRange: print(number) 1 2 3 4
Let's combine the range(), len() and for loop to achieve something non-trivial.
myString = "rendezvous" for characterPosition in range( len(myString) ): print("Letter at index", characterPosition, "of", myString, "is", myString[characterPosition]) ## UPON EXECUTION Letter at index 0 of rendezvous is r Letter at index 1 of rendezvous is e Letter at index 2 of rendezvous is n Letter at index 3 of rendezvous is d Letter at index 4 of rendezvous is e Letter at index 5 of rendezvous is z Letter at index 6 of rendezvous is v Letter at index 7 of rendezvous is o Letter at index 8 of rendezvous is u Letter at index 9 of rendezvous is s
Sometimes, you want to stop a loop in the middle of the loop body, based on a condition. Say, for some weird reason, you don't want the interpreter to print any Es on the screen while iterating over a string, this is how you would do it:
for letter in "sequence": if letter == 'e': continue print(letter) print("done.") ## OUTPUT s q u n c done.
And for another weird reason, you want the interpreter to break out of the loop as soon as it encounters a q, here's how you would do that:
for letter in "sequence": if letter == 'q': break print(letter) print("done.") ## OUTPUT s e done.
What was that all about? You'll know in an instant. Let's look at what break and continue from scratch.
The break statement takes the control out of the loop and onto the statement that follows after the loop.
while predicate: for alias in sequence: while loop body for body loop if predicate: if predicate: --------------- break ---------------- break | while loop body | for body loop | | ---> more statements after while loop ---> more statements after for loop
The continue statement skips the current iteration and begins the next iteration i.e.
---> while predicate: ---> for alias in sequence: | while loop body | for body loop | if predicate: | if predicate: --------------- continue ---------------- continue while loop body for body loop more statements after while loop more statements after for loop
So, break statement takes the control out of the loop and onto the next statement after the loop, when a certain condition is met, and the continue statement skips the current iteration, and takes the control to the top of the loop. Have a look at those two "sequence" programs again, they should make sense to you now.
The else clause in loops is executed in those situations when the break statement is not encountered by the interpreter. This could be because of two reasons: either you don't specify a breaking condition or if the breaking condition is never met. For example,
myRange = range(1, 5) # we know that 5 is not included in this range for num in myRange: if num == 5: break else: print("Value is", num, "not 5.") else: print("5 is not in the range!") ## UPON EXECUTION Value is 1 not 5. Value is 2 not 5. Value is 3 not 5. Value is 4 not 5. 5 is not in the range! myRange = range(1, 5) for num in myRange: if num == 4: # changed the if condition so that the break is executed and else is not. break else: print("Value is", num, "not 5.") else: print("5 is not in the range!") ## UPON EXECUTION Value is 1 not 5. Value is 2 not 5. Value is 3 not 5.
So, the takeaway here is that if you specify an else clause to a while or for loop which contains a break statement, then either the break is executed or the else clause.
Any of the loops (for and while), branches (if) can be nested i.e. you can use a loop inside a loop, a loop inside a branch, a branch inside a loop and so on. We have already seen in action in the Exiting loops prematurely using break and continue, where we nested an if statement within a for loop. Let's view another couple of examples.
# PRINTING A NUMBER AS MANY TIMES AS THE VALUE OF THE NUMBER for i in range(1,6): for j in range(0,i): print (i, end = " ") ## OUTPUT 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5 # A little formatting will help "prettify" the output for i in range(1,6): for j in range(0,i): print (i, end = " ") print() # as good as pressing an enter/return key after each iteration of inner loop ## OUTPUT 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5 ## ANOTHER EXAMPLE OF NESTED LOOPS: Printing prime numbers lying within an interval 0 to 50. ## Primes are integers greater than one with no positive divisors besides 1 and itself. Negative numbers are excluded. for number in range(0,51): # testing all numbers in range 1 to 50 if number > 1: # prime numbers are greater than 1, the smallest prime number is 2. for i in range(2,number): # testing all numbers in range 2 to (number - 1) if (number % i) == 0: # if the number has any factor other than itself(since 1 is already taken care of by the if statement in the beginning), then break out of the inner for loop break else: # if the number doesn't have any factor other than itself, print it as a prime. print(number) break ## TRY EXECUTING IT.
If you are into printing patterns, nested loops is what you should search online for. Nalini, at djangoSpin, is really proficient at pattern printing. So, comment below if you need help on pattern printing.
Here are a few handy things you will find helpful.
Generating Random numbers using randint() and randrange()
While we are on the subject of numbers and ranges, I think I'll just sneak this little how-to here. randint() takes two numbers as arguments, say 5 and 50, and every time you call this function, it will give you a random number for you to play with. randrange(), on the other hand has multiple ways in which it can be called. We will discuss the simplest way to call it, that is, using just one argument. When you specify only a single argument to randrange(), it will return a random number lying between 0 and 1 less than the number you specified, much like a range. Let's see these live:
>>> import random >>> random.randint(5, 50) 43 >>> random.randint(5, 50) 7 >>> myRandomNumber = random.randint(5, 50) >>> myRandomNumber 15 >>> >>> >>> >>> >>> random.randrange(50) 21 >>> random.randrange(50) 35 >>> myRandomNumber = random.randrange(50) >>> myRandomNumber 28
So what is the first statement about? The import statement, does what you would expect it to: it will bring in code from a Python file and access any functions in it. In this case, there is a module called random.py in Lib directory in your Python installation directory, and we access two of the functions defined in it i.e. randint() and randrange().
The way we have accessed these two functions is also intriguing. We have used here what is called the dot notation. Dot notation is analogous to possessive nouns in English. For example, Matthew's book indicates that the book belongs to Matthew. Similarly, random.randint() denotes that the randint() function belongs to the module called random.
Suffice it to know this much about modules. We will cover them at length in one of the subsequent chapters.
This chapter was smaller than the previous two, but we looked at one of the most important concepts in programming languages: looping. Try the 3 programs yourself, and have a go at the DIY section below. Be sure to play with loops yourself, you'll gain a better understanding of Python if you practice regularly.
In the next chapter, we will undertake the other half of variables: data structures i.e. lists, dictionaries, sets and tuples. More feel-good stuff is waiting on the other side. Till then!
- Given the below encrypted message and the fact that characters were displaced by 10 places going forward, decrypt the message by using the Caesar Cipher script.
'Iye’fo nombizdon dro wocckqo. Myyv. Xyg qy sxdy iyeb Zidryx sxcdkvvkdsyx nsbomdybi. Iye’vv coo k nsbomdybi xkwon Vsl, oxdob sd. Vymkdo dro psvo ’drsc.zi’, yzox sd gsdr iyeb pkfybsdo dohd onsdyb. Kpdob iye rkfo coox dro myxdoxdc yp dro psvo, dizo sx iyeb sxdobzbodob ’swzybd drsc’. Mywzkbo dro dgy dohdc. Coo kxidrsxq pkwsvskb?'
P.S. If you try to decrypt the above message on repl.it, you will get a UnicodeDecodeError. To get rid of that, replace the apostrophes by manually entering them from your keyboard. You will get no such error in IDLE.
- Devise the famous game of Guess the Number. Ask the player to guess a number between 1 and 100 in 7 tries. After each incorrect guess, advise the player to aim lower or higher, and tell the player how many tries he is left with.
HINT: Here's a pseudo code for the program, yours might differ:
Generate a random number between 1 and 100 and store it in a variable Initialize two variables, one for keeping track of the number of tries, and the other for the entered guess, to 0. While True Prompt the user for input, assign it to the guess variable If the guess is equal to the random number Break out of the loop after congratulating the player Else i.e. if the guess is not equal to the random number Increment the tries variable If the tries are less than 7 If guess is greater than the random number Ask the player to aim lower. Tell him the number of tries he is left with Else i.e. if the guess is lower than the random number Ask the player to aim higher. Tell him the number of tries he is left with Else i.e. if the tries are equal to 7 Break out of the loop after revealing the number
[ Solution ]
- In the Nested Loops section, we saw a program to print prime numbers in an interval of 0 to 50. Your task is to make it interactive. Prompt the user for the upper bound and display all the prime numbers within 0 to the number entered. [ Solution ]
- Write a Python script to output a conversion table for Celsius to Fahrenheit temperatures. Ask the user to input lower bound and upper bound of Celsius temperatures. Using range() and a for loop, output the corresponding Fahrenheit readings. Formula: f = 32 + ( (9/5) * c). [ Solution ]
- Object Oriented Python
- Design Patterns in Python
- 50+ Handy Standard Library Modules
- 60+ Handy Third Library Modules
- 50+ Tips & Tricks for Python Developers
- 50+ Know-How(s) Every Pythonista Must Know