On Feb 8, 12:42 pm, J <seaworthyjer...@gmail.com> wrote: > What are your thoughts on this module I created? > Here are a few steps to illustrate some good basic Python idioms worth learning:
Step 1: Replace many-branched if-elif with dict While translating characters in a string is a special case that usually warrants using str.translate, a more general-purpose technique to learn is to define a dict that captures the various branching options, and then use the selecting value as a key to access the desired branch. Here is a dict containing your branches: LEET_LETTERS = { "e" : "3", "E" : "3", "a" : "4", "A" : "4", "i" : "1", "I" : "1", "t" : "7", "T" : "7", "s" : "5", "S" : "5", "o" : "0", "O" : "0", "b" : "8", "B" : "8", } Now you can implement leet() using access to the LEET_LETTERS mapping. Here are 3 different versions, that illustrate the usual options when accessing entries from a map: 1. Look before you leet, uh, I mean "leap" (check for key existence before using) 2. Better to ask forgiveness than permission (just use the key and handle the exception that gets raised if the key is not found - an homage to Grace Hopper) 3. Slightly different strategy, using dict.get() method instead of key/ indexing into the dict def leet1(string): outlist = [] for letter in string: if letter in LEET_LETTERS: letter = LEET_LETTERS[letter] outlist.append(letter) return "".join(outlist) def leet2(string): outlist = [] for letter in string: try: letter = LEET_LETTERS[letter] except KeyError: pass outlist.append(letter) return "".join(outlist) def leet3(string): outlist = [] for letter in string: outlist.append( LEET_LETTERS.get(letter,letter) ) return "".join(outlist) You can test each in turn without changing your test code, just assign leet to each of these variants in turn: leet = leet1 print leet("Hello You Beautiful Sweet World!") I'm partial to option number 3, so let me show you a few other helpful tips. By the way, you can do this if you are doing any kind if if-elif, such as: if a=="0": fn_1() elif a=="1": fn_100() elif a=="7": fn_greater_than_five() ... Instead you would write: # note: values are the methods only, no ()'s fns = { "0" : fn_1, "1" : fn_100, "7" : fn_greater_than_five } if a in fns: # get desired function from fns map, and call it fns[a]() Step 2: dict construction instead of {} syntax LEET_LETTERS is so space-consuming, sometimes it is easier to use the dict constructor with a list expression of list comprehension. That is, instead of the built-in syntax P{}'s to define a dict, you can use the dict constructor and pass a list of (key,value) tuples. LEET_LETTERS = dict( [("E","3"), ("e","3"), ("A","4"), ("a","4"), ...] ) Well, my fingers are tired and I'm bored already, how about if we could just list the two strings of key and value characters, and some how build the tuples by pulling an item from each list one at a time. Fortunately, that is what Python's zip() function does: LEET_LETTERS = dict( zip("eEaAiItTsSoObB", "33441177550088") ) (I've listed the key-value pairs one above the other to illustrate how the mapping will work, but of course, that isn't required.) Now if I want to add another leet-speak letter (like "6" for "G"), I just add the two characters on the end of the two strings. Step 3: Use list comprehension instead of explicit list.appends using for loop As was already mentioned in another post, ''.join (list_of_characters_to_join_together) is preferred to final += next_letter_to_add_to_final. But there is also a nice short and clean way to build up the list besides explicitly calling append in a loop. Instead, use a list comprehension. To do this, you convert: outlist = [] for letter in string: outlist.append( LEET_LETTERS.get(letter,letter) ) to: outlist = [ LEET_LETTERS.get(letter,letter) for letter in string ] In fact, Python is so smart, you can skip the list entirely, and just pass that expression inside the brackets (called a generator expression) directly to ''.join: final = ''.join( LEET_LETTERS.get(letter,letter) for letter in string ) Just a "list" is not desired variable name since it masks the built-in list type, I avoid "string" as a name since there is a commonly-used string module. How about just plain "s"? Here is the final version of leet - we even got rid of the variable final, and just return the value that would have been assigned to it: LEET_LETTERS = dict( zip("eEaAiItTsSoObB", "33441177550088") ) def leet(s): return ''.join( LEET_LETTERS.get(c,c) for c in s ) Soon you'll be writing Python just like all the cool kids! -- Paul -- http://mail.python.org/mailman/listinfo/python-list