One step further on the way of Python: don’t count to get, just get.
A common anti-pattern used by Python beginners is the “range len” pattern. I’m pretty sure you already encountered this anti-pattern in the past, and there is even a high probability that you have done it yourself. I did too !
Anti-pattern
So let’s see an example of the anti-pattern:
for i in range(len(text)):
print(text[i])
Analysis
This seems pretty straightforward, but try to ask yourself, one line at a time: “What do we need? Why? How?”
1. for i in range(len(text)): What do we need? We need the length of the text. Why? To get the upper limit of the range. How? By calling the length function and sending the result to the range function, then sent to the for loop to iterate over the range.
Let’s move to next line.
2. print(text[i]): What do we need? We need the text and the index. Why? To get the letter located at that index to print it. How? By using the index on the text string to get the value of the corresponding letter.
Was our previous hypothesis true? No, the only read information that will get outside our block of code is the letter value. We needed the index to get to the letter value.
Anti-patterns are obvious, but wrong, solutions to recurring problems.
Budgen, D. (2003). Software design
So we don’t “need” the index. What we need is the letter. Was that obvious with the for loop code? No, we had to make assumptions, then read the implementation. And the implementation was in opposition to the for loop statement: We don’t need the index.
What to do?
So, the next question you need to ask yourself is the following one: “Can I get rid off the index as it’s just an intermediary value?”
If you can reduce the number of intermediary steps between the input and the output of a block, you will make the code more simple, less convoluted, faster to grasp, more meaningful.
How to do it?
In Python, for loops are designed in a way that it “only” asks the next value a data-structure can provide. range(len(text)) will provide all the indexes from 0 to len(text)-1, one at a time, and the for loop will store that index into the variable i. But a string, a list, a dictionnary or any other iterable types can be used in for loops! The for loop will ask the next value at each iteration, and the iterable will provide it.
This means that this code works:
for character in text:
print(character)
Analysis of the new pattern
Again: “What do we need? Why? How?”
Line 1 for character in text: What do we need? The text. Why? To get each character. How? By iterating over each letter with the for loop.
Let’s move to next line.
Line 2 print(character): What do we need? The character. Why? To print it. How? Duh, with the print function!
Yes, if this new code is not the first thing that comes in the mind of beginners, we have to admit that its explanation is quite… simple. Even more, you can almost read it in plain English, and it makes absolute sense: For each character in the text, print it.
![# Junior for i in range(len(text)): print(text[i]) # Senior for character in text: print(character)](https://thewayofpython.com/wp-content/uploads/2023/05/for-in-range.png)
Leave a Reply