Wednesday, January 13, 2016

Day 4 - churning

Day for was all about nested loops and basic functions.  Although I already have a good handle on basic function definitions, I learned some good lessons on making code more concise...as well as the perils of such.  For example: suppose you want to collect the name, age, and city of origin of a user, and store that in a list.  You might write a function such as:

def user_info():
    name = raw_input("Q1 - What is your name?")
    age = raw_input("Q2 - What is your age?")
    city = raw_input("Q3 - What is your city?")
   
    return [name, age, city]
 A shorter way is to use:
 def user_info():
     return [raw_input("Q1..."), raw_input("Q2..."), raw_input("Q3...")]

The exercise was intended to emphasize refactoring code to make it cleaner.  Once I'd run through the basics, though, I went to look at edge cases such as: What if someone puts in numbers in the city name "Bost0n" or writes out their age (when your code expects integers)?  Embedding the 'raw_input' functions in the returned array makes it impossible to do any error checking immediately after data is entered.  You could write a separate "cleaning" function to catch errors in the array, and to prevent that data from contaminating other functions.  More useful, though, is to immediately detect problems in the entered data and to prompt the user to correct their entry until they get it right.

I chose the latter path, and created two short "error checking functions", one to screen names, and one to screen integers.

>>>while age.isdigit() == False:
      ....age = raw_input("Please enter your age using numbers.")

To screen the name answers, however, I went to Stack Overflow and searched for methods of detecting punctuation and/or numbers in a string. (I knew I could do it by iterating through the string and testing each character, but that's pretty inefficient.)  Instead, I chose the regex function in the linked example and modified it for my purposes

def only_letters(input_string):
   """Returns 'False' if any character other than lowercase letters a to z are in the string."""
    match = re.match("^[a-z]*$", input_string.lower())
    return match is not None
while only_letters(name) == False:
   name = raw_input("Please use only letters in spelling your name")

The drawback of this approach is that I didn't write the regex function, and I couldn't explain very well how it works.  Also, names with apostrophes would be flagged as inappropriate, and it would not accept unicode or non-english-standard-letters.  By this point, though, I'd also added in functionality to include an arbitrary number of people for data collection, each with their own dictionary entry, using their name as a key (although I could have used a unique number as the key), and a print function to display the collected information neatly.

User 1:    Name: Jane    Age: 44    City: Boston
User 2:    Name: Bob    Age: 33    City: Seattle

So, that was my disappearing day.  There were other things: researching the inability of my error_checker script to work properly as an imported module, working through some other 'extra credit' exercises, trying to follow a recursion exercise...plus a long awaited trip to the supermarket to pick up some groceries.

2 comments:

  1. You could use a "like" function and then have it check for duplicates that way using wild cards. Not sure how to work around the Unicode problem though.

    ReplyDelete
    Replies
    1. I know there is an answer to the unicode problem, but handling non-standard characters is a whole new field of problems. Some day.

      Delete