[Tutor] implementing rot 13 problems

Karim kliateni at gmail.com
Tue Mar 12 12:11:39 CET 2013


What can be said after this detailed lesson...Bravo!

On 12/03/2013 11:58, Steven D'Aprano wrote:
> On 12/03/13 16:57, RJ Ewing wrote:
>> I am trying to implement rot 13 and am having troubles. My code is as
>> follows:
>
> A few comments follow.
>
>
>>   def rot_text(self, s):
>>       ls = [i for i in s]
>>       for i in ls:
>>           if i.isalpha():
>>               if i.isupper():
>>                   if i <= 'M':
>>                       x = ls.index(i)
>>                       ls[ls.index(i)] = chr(ord(i) + 13)
>
>
> This is unnecessarily verbose and complicated.
>
> First problem, you use the name "i" to represent a character. 
> Generally you should avoid single character names, and prefer 
> meaningful names that explain what the variable represents. If you 
> must use a single character, then the conventional names include:
>
> x, y, z: numbers, particularly floats
> x: (rarely) an arbitrary value of no particular type
> i, j, k: integer loop variables (rare in Python)
> n, m: other integers
> s: string
> c: character
>
> Notice that "c for character" makes much more sense than "i for 
> character".
>
>
> You can, and should, create a list from the string using the list() 
> function, rather than a list comprehension that just walks over the 
> characters:
>
> ls = [c for c in s]  # No, too verbose.
> ls = list(s)  # Much better.
>
>
> You then loop over the list, again using "i for character". You can 
> combine all those multiple if statements into a single clause:
>
>       for i in ls:
>           if i.isalpha() and i.isupper() and i <= 'M':
>
> But wait! The call to isalpha() is not necessary, because if a 
> character is *not* alphabetical, isupper() will always return False:
>
> py> '9'.isupper()
> False
>
> So we can throw out the call to isalpha().
>
> Your code to rot13 the letter is, sadly, broken:
>
> x = ls.index(i)
> ls[ls.index(i)] = chr(ord(i) + 13)
>
>
> This might make more sense if I re-write it using more meaningful names:
>
> position = ls.index(char)  # This variable never gets used :-(
> ls[ls.index(char)] = chr(ord(char) + 13)
>
> The bit with chr() and ord() is fine. But what you do with it is 
> wrong. The problem is that index always returns the position of the 
> *first* copy of the item. So if your string is:
>
> 'ABA'
>
> the first time around the loop, your character is 'A'. ls.index('A') 
> will return 0, and the rot13ed version, 'N', will be shoved into 
> position 0. The second time around the loop, the character is 'B' and 
> the rot13ed version gets shoved into position 1. But the third time, 
> the character is 'A' again, index() will return 0 again, and the 
> rot13ed version gets shoved into position 0 instead of position 2, 
> giving you:
>
> 'NOA'
>
>
> The best way to fix this is to ignore index, and instead count which 
> character we're at each time:
>
>
> position = -1
> for char in ls:
>     position = position + 1  # Advance the count.
>     ... blah blah blah
>     ls[position] = chr(ord(char) + 13)
>
>
> But wait! Python has a function to do exactly this for us:
>
>
> for position, char in enumerate(ls):
>     ... blah blah blah
>     ls[position] = chr(ord(char) + 13)
>
>
>
>
> Have a go with that, and see how far you get.
>
>
>
>



More information about the Tutor mailing list