Sunday, January 31, 2016

w3d5 - 2 days late with a reality check on OOP

Well, that was brutal.

I left off Thursday evening with grand plans for a general card game constructor. I limped in to Sunday night with a functional blackjack game built with python classes.  The basic structures I outlined survived.  I learned some good lessons in debugging long scripts, step-wise validation of functional code, and yet another lesson on data structures.

On data structures and class variables: be cautious.  Using

class Player(object):
      def __init__(self, name='', data=[]):
             self.name = name
             self.data = data

looks to the naive as though it will save some key strokes when initializing instances .  As it turns out, each instance of Player has different name, but their self.data points to the same list.  E.g.:

>>>bob = Player(name='bob')
>>>jeff = Player(name='jeff')
>>>
>>>bob.data.append('yo')
>>>
>>>jeff.name
>>>'jeff'
>>>jeff.data
>>>['yo']

It recalls the points raised in this Stack Overflow thread on how to be a good programmer (specifically wscpy's answer highlighting the difference between how python stores integers or strings and how it stores(references) lists).

I have so much to learn about the stuff under the hood.

On debugging:

I have more lines devoted to test prints for individual functions (to monitor what various pieces of the script are doing) that I had in any program I wrote before I got to camp.  Still small relative to 'real' stuff, but still...

And also - even when you think you know what you're doing, test shit.  I might get that as a tattoo and save myself a ton of future pain.


Thursday, January 28, 2016

w3d4 - Making a blackjack game with OOP (classes in python)

Our week 3 capstone project is to build a blackjack game using classes.  After half a day, I'm about half way done. It would be faster, but I spent a lot of time (at the instructors urging) planning my approach.  Since I'd gotten pretty good with data structures in previous weeks, I naturally thought of doing the project with lists and dictionaries with a bit of class to hold the pieces together, so to speak.  Thinking in OOP is not a huge stretch, but it's not as natural...which is the point of this project, I suspect.

My goal is build not just a blackjack game, but any game that can be played with normal deck of cards (or multiple decks...).  It should accomodate Jokers and games other than black jack with a few modifications to the variables used to construct the deck, and with a unique Game.play().

The basic outline of my game is:

class Card
   properties: name(number, or face name, or Ace), suit, value, specialflag (for cards with special properties like the Ace), symbol (in case I ever get around to figuring out how to print the suit symbols)
   method: __repr__ override to print card.name + card.suit when "print card" is used

class CardGroup
   properties: container (to hold cards)
   methods: print cards (relies on card __repr__ override

class Deck(CardGroup) (Deck is a subclass of CardGroup)
   properties: suits (used in constructing a deck - any set of suits could theoretically be used)
                     name, value tuples - connects the card name with it's value.  All face cards in blackjack are worth 10, but hearts would be different, and in poker only name and suit would matter.
                      container (Deck and Hand are subclasses of CardGroup so their self.container needs to point to different things)

   methods: make deck (based on suit, value, name info), shuffle deck (just random.shuffle), draw_card to pop a chard off the end of the list of cards

class Hand(CardGroup)
   properties: container
  methods: add_card (takes the draw_card result from the Deck), play card (not yet implemented since blackjack doesn't use that method), evaluate hand (to decide the status of the hand - just adds the point value at present which undercuts universality for other kinds of games)

class Player
  properties - name, hand, money
  methods - draw starting hand, take turn (still working on how this and Game.play() interact, but should use polymorphism

class Dealer(Player)
  properties as above
  methods - as above, but 'take turn' will be a simple AI to replicate the rules of blackjack

class Game
  properties - players, deck
  methods - add player, add deck, take turn, get new deck, monitor progress/declare winner


So, yeah.  It's a bit of overkill.  It's fun to see how the classes interact, though.  It's also a hell of a confidence boost to see this coming together after the fiasco of trying to implement linked lists using objects.  More on that later...
 


Wednesday, January 27, 2016

w3d3 - Linked Lists and binary trees...now with classes!

I have to confess that today was...intense.  It's painfully clear that I know much less about how classes work than I thought.  It was honestly a good lesson in humility for me, and it was a reminder of how much work I have to do.

 Everything was working by the end of the day, even a little extension project on recursive pathfinding through a graph:

graph = {'A': ['B', 'C'],
         'B': ['C', 'D'],
         'C': ['D'],
         'D': ['C'],
         'E': ['F'],
         'F': ['A','C']}

where each key is linked by a one-way path to it's  corresponding nodes, which are in turn linked to other nodes.  Given a start and an end, can you find a path between.  I can get it to work for ONE path, and screen out loops (see that tricksome 'C' --> 'D' --> 'C'-->...) but not to collect ALL paths, or to find the shortest path.

The first task of the day was creating and modifying linked lists.  For linked lists, I could make a "Node" class with  'data' and  'next node' properties.  Using functions,  I could print out the nodes in order, add new data to the tail of the node, return data from a node, and insert a node between two others.  Do it classes, either within the Node class or in a separate "Linked List" class, though?  Nope.  Or, I should say, 'not yet'.  I will get this because I need to know classes better, to really understand how data is held.  I've seen some really elegant solutions online, and I'm debating continuing to try to write my own, or to look at a professional-grade one and try to reverse engineer it.

After linked lists came binary trees.  The concept is fascinating.  I love that a thing that looks so disordered at first glance holds such structured data.  I could get a basic recursive tree-reader function working after a lot of pain, dead ends...and mis-read directions.  The solution to printing out the data in a binary tree in order (least-to-greatest) using a recursive algorithm was painfully simple once discovered.  Getting there?  Very challenging.

I will say that I really love the concept of recursion. There's something really satisfying about defining a data-processing approach that takes in bites from a big pile until it's done.  Or better, than spawns copies of itself to check out branching paths and report back.

Working with classes + recursion ==> painful.  These are hard for me in part because it's a lot more laborious to prototype in the REPL using classes.  Simple functions I can do there easily, or to test out methods on default classes. (huh.  Maybe if I work on treating my created classes like the built in classes (string, list, hash, etc) I'm more comfortable with, the syntax will make more sense.).

Tomorrow is another day.  I'll set an alarm to wake up early and try the classes with linked lists project one more time.

Tuesday, January 26, 2016

W3D2 - Inheritance and Polymorphism, and pair programming

The interesting thing about pair programming is that even when partners are very mismatched, having to justify and explain can help the more skilled programmer really think through design decisions.  For the method to work well, the less skilled programmer has to be proactive about asking questions.  If they just sit back and lets the more skilled do all the work, they learn nothing from the exercise.

On the ostensible subject of the lesson - there were a few interesting new concepts.  One would be iterating through an array of instances of classes and calling an identically-named method for each.

As far as inheritance and polymorphism, though, the exercises made sense.  I'm sure there's a lot more to learn, but so far so good.

Week 3, day 1 - OOP and making my own hash

Part 2: OOP

The best part of today was learning how hash tables (aka dictionaries) work on a fairly basic level.  Essentially, the key of a dictionary entry {'key': 'value'} is converted to a number using a hashing function.  The essential elements of a hashing function are:  a prime number and a means of converting a text string to a number.  The prime can be of arbitrary size, but any reasonably sized dictionary would need a fairly large number.  The unicode values for letters in the key can be used as one way of generating a number.  When that number is divided by the prime, a semi-unique value is determined. (semi-unique because there will inevitably be a collision when two keys generate the same index).

One of the other interesting things about this project was building the hash as a class.  Doing so required overloading the __getitem__ and __setitem__ built-in methods.  I'd seen classes a bit in Learn Python the Hard Way and Code Academy, but I had no idea that built-in overload was possible.  So that was two lessons in one...

As a further extension, and third part of the lesson, I built a collision-handling mechanism whereby, instead of simply appending a value to the index, a key:value tuple was appended.  Then, when my class __getitem__ was called, the lookup method would iterate through the tuples looking for the matching key.


Monday, January 25, 2016

Week3, day 1 - recursive file indexer wrap up

First - I was able to wrap up the week two project:  a text file search script that assembles a list of text files in a given arbitrary directory tree using a recursive search, then indexes the words in the files such that a user can discover which files contain the word of interest.

I managed to complete my own objectives, and added in a list of words to ignore (e.g. 'the', 'a', pronouns, etc.).  Courtesy of stackoverflow, I was able to add in a function to open files using the default program for each file.  Since I'm working with only .txt and .csv, that's not a huge range of options.  The script looks for os before opening, since mac and windows use different commands.  Net result: I learned a bit about subprocess module, and more about the os module.

I also was able to re-use my entry validation module to ensure users were selecting valid options.

My stretch goal: index large files (e.g. whole books as text files, courtesy of the Gutenberg Project.  My goal is to collect the line number where a word appears in a file to make words reasonably findable.  My script should also have a function to provide a preview of the context of a word.


Friday, January 22, 2016

Week 2 is a wrap - a mini google

The 'capstone' project for week two is to create a miniature version of an indexed search engine for text files.  The basic version should:

1.  scan through a file structure and make a list of files and associated path names.
2.  read all the text files to create an array of words
3. create a dictionary of {'word1': {file1: path, file2: path}, 'word2: {}}

The list of files is produced using the recursive tool built earlier in the week.

At this point, I have a working version of the project that accepts only files with '.txt' in the name.

To do, in rough order of importance:

1. exception handling for words not in the dictionary that a user tries to look up.
2. remove punctuation and formatting from text before reading for the library.
3. validation on user input (did they type a word, or put in random characters)
4. ask user if they wish to open one of the files in  a text editor
5.  open and index other file types (e.g. csv)

All of that and general edits for readability and cleanliness.

I might be further along by now, but I took some time this morning (it was an unstructured work day) to refactor my budget app file-open function.  After the refactor, it now appends the data from an opened csv to the in-script dictionary (and gets the keys right).  Opening a csv file creates a dictionary with key names = column headers in the csv.

Also, I built a script to make temporary files in my practice file tree.  Each file is filled with a random number of words organized into lines.  Since the function uses the recursive file tree generated above, pseudo-text-files are scattered thoughout the sample directory tree.

And now it's after midnight on a day that started with the dawn.  More later.


Thursday, January 21, 2016

Week 2, Day 4 - Search and sort and more recursion

Today's exercises involved writing some basic search and sort functions using a binary search and bubble sort.  My solutions worked well and were done quickly. I'm not sure what else to say aside from "I know reasonably sized data sets would use other algorithms that use fewer operations (on average)"

Another exercise: given a string such as "2+3-4", perform the indicated calculation.  My solution based on a for loop through the string:
    1. put a digit in a 'temp' holding place
    2. store the operator in a second temp variable
    3. identify a second variable as 'y'
    4. look up the correct lambda function in a dictionary (e.g. {'+': lambda x,y: x+y}
    5. set the first temp variable to  = lambda(x,y)
    6. proceed
    7. return total

My small discovery for the day, though: give a set of 'infix' notation, perform the calculation with correct order of operations.  The hardest part (converting a string to proper notation) was given. So 4 x 6 + 7 would be shown as (7, 4, 6, x, +) .  The idea is that the two right-most numbers would be operated on by the 'x' and 7 + the product would be the answer.  Solving the small example would be simple.  For a list of unknown length however, I used a very small recursive function (again using a lookup table for the right lambda function.

def process_infix(array):
 
   if len(array) == 1:
      return array[0]
 
   total = lambda_lookup[array[-1]](array[0], process_infix(array[1:-1])
 
   return total

no for loop, no iterating through the string....and it used the recursive logic that I was struggling with yesterday.  I still have  a lot of learning to do on recursion, but I'll take my victories where I can.

Wednesday, January 20, 2016

Week 2 - Day 3: Lambdas, stack and more recursion

Lambda functions: I don't understand why I ever found these challenging.  Maybe it's just that I've done a lot more coding now.  Or, more likely, that I'm more used to thinking in symbols.  Or maybe it's that I'd spent a good bit of time trying to figure out javascript anonymous functions back in November and so the general idea of anonymous functions is less mysterious...

I should say, rather, that I understand the challenges given in class.  The hardest part of understanding something is knowing when to apply your learning to solve real problems in a messy world.  That's what makes the transition from school to the working world so hard.  There's no correlation between "What we read in chapter X" and "Here's a problem to solve!" where you can reasonably expect that the solution will test recently learned techniques.

The simple stack problems in class went well, too.  I really kind of like this one for error-checking closures in html.  The basic problem was "given a string of html open and close tags, determine whether the sequence is correct.  Funtion should return True (for ok strings) or False"  So "<div><h1></div></h1>" and "</div><div>" would be incorrect while "<div><h1></h1><p></p></div>" would be correct.

To be fair, one of the instructors suggested a lookup dictionary to test whether stack and string elements were matched.

It's somewhat "unpythonic" for having a dual-purpose if loop that builds a dyamic tag lookup dictionary as well as an array of all tags, and passing both together to the item-comparison function.  The lookup dictionary, however, is built dynamically based on the input string and running through the html string twice with two different functions would be wasteful.  The dynamic build means that the dictionary could be used for an xml file with unique tags.

Drawbacks:

- my script doesn't check the lookup dictionary to see if a given tag is already present.  That would be trivial to fix.

- the script assumes all the tags were entered properly with < and >.  That kind of typo would not be caught automatically

- worst, the script would not cope at all with self-closing tags in HTML 4.  But then, this isn't meant to be a very useful script beyond teaching stack.


Some problems I'm still struggling with: recursion.  I can get some simple recursion functions to work on my own (Fibonacci and factorial), but I'm still struggling with predicting how each function call affects those downstream.  Enough on that for now.

Tuesday, January 19, 2016

Week2, Day 2: Thoughts on complex software

So far I've made two largish bits of code: Meowpocalypse (a text based choose your own adventure I made before arriving at code school as an exercise in using classes) and this budget app.

The game is about 1000 lines long.  The budget app is about 500 lines with another 100 in an associated module I wrote that ensures input data.  In other words - big projects for a beginner, not so big for production.  They also don't have to interface with anyone else's code.

I've read about how big software programs work in that there can be far more lines of code than any one person can understand or, really, work with.  You have, in essence, enormous, highly complex blocks with, ideally, very simple interfaces.  Information is passed from block to block at the interface...but the internal workings  of the blocks is often opaque.  As a programmer, you may have no more than a general idea of what other people have made.  All you know is that data in a certain form is passed into the realm you can influence, and you must see that your code-minions pass it out to right place at the right time and in the right format.

I got a tiny taste of that in my own somewhat complex budget app.  Things that I hard-coded, like categories of information to collect, have a strong potential to break functions in other parts of the script.  For example: my app can open a csv and construct a dictionary from the data there-in.  Every function that specifies values or attributes rather than pulling them from the state variable is a risk of failure.  A string that contains the column headers, for example, is difficult to alter if the column titles  are changed by some other part of the program. The more dynamic (built as-needed from a data source that every function can access) the processes are, the less likely they are to suffer a conflict with how other parts of the machine are built.

There's more, but it's late again, and we're doing more with recursion tomorrow.

Monday, January 18, 2016

It's late and I'm exhausted but wow did I do some cool stuff today.  My best thing so far, I think, is this error correction module "entry_validation.py"

If it's imported to a python script, you can use validate('question', [list of correct answers], 'data type')
and validate returns an acceptable answer (courtesy of try, assert and while).  You can also test for simple entry types (int, str, float) and force the user to enter an acceptable type by leaving the [list] argument just an empty list.

I'm pretty sure this module can be improved (especially since 'data type' is not just a type, but one of a long list of flags I devised - they're written out in the comment at the top of the module).

But still, I'd seen, but not worked with "Try/except" or "assert" before today.

Also! My budget app now has error correction, entries can be edited, and files can be written and saved and re-opened with no loss of data (even the index/counter will be the same as before).

I'd still like to be able to open a file and append it to an existing inventory (although you can open a file, import it to the in-app dictionary with column titles becoming dictionary keys dynamically).

Also, being able to change the number of data fields in response to user input would be nice.

Also, error correction on the file open function will go in tomorrow.

But still, not too shabby since I only had a few hours to work independently today. (I'm doing some crude version control with file names.  Git tutorial soon!)

Update on the morning after: the error fixing code is probably needlessly complex.  Still a good learning experience.

Sunday, January 17, 2016

Days 7 & 8 - Rest, and challenge

Day 7, Saturday, was our day of rest.  I still worked on my columns for US News and Time for a bit of Saturday morning.  Saturday afternoon, though, was just rest and relaxation.

Day 8, Sunday, was a fiasco.  I was up early, made food for the week, did some laundry...and broke my little budge app. The rest of the day was spent fixing the budget app.  It's 7 pm and I've manage to restore the app to yesterday's functionality with a few marginal improvements.  On the bright side, I have a large, well-seasoned pot of beans and some clean laundry.

What did I learn today?  Don't push every element of a program to the limit (or beyond) of your capabilities.  When something breaks, you don't understand all the elements well enough to follow what's going on around the part that broke.

Also: learn version control so this doesn't happen again.

Update: 8:45 pm

I went for a short walk, came back and figured out some more useful elements.  One of my goals for this code school project is to demonstrate that I can still work through setbacks.  The hardest part, for me, is not taking failed attempt at coding as a judgement on my worth and skill.  I want to get to where I care deeply about making clean, functional, elegant code but I don't see every mistake as an indictment.  It's a hard process, and it's ok to make mistakes.  The key is process: be methodical, document, test, move on.  Also, version control.

Friday, January 15, 2016

An all-day project

I made this (link to python file on dropbox). It won't run in the trinket.io page, but you could look at the code if you were so inclined.  The (minimum) design specs are in the red text surrounded by ''' (i.e. the long comments at beginning and end)

"It" it is a basic budget app.  You interact with it via command line (as with everything else I've made in python so far).  It's only 217 lines, and half of those empty space, but it's some of the densest code I've written.  It's mostly an exercise in memory management using dictionaries and data i/o using csv files.

Features:

1. Asks user for item/cost/recurring and stores that info in hash, using a counter variable as the key.

2. Maintains a speed-lookup dictionary with name: key pairs (where name is the name of the item...important since some app functions require lookup by item name and this allows quick lookup of where an item is stored.

3. All functions (save for a few specialized uses) take a state variable as their only argument.  The state variable contains the dictionary of items in the budget, the counter variable for generating keys, the speed lookup dictionary, the file name that is the source of any data, or the destination of data to be written.

4.  Instead of a simple while loop that ends when the q(for quit) key is pressed, q calls a function that saves the current budget inventory in a "temp.csv" file and uses "raise SystemExit()" to terminate the program.  I remember losing an hour of work once when using a crappy old Pascal program to process data, and I didn't quit properly.

5. A dictionary for switching among functions based on user input.  The switch uses dict.get() so that I can handle edge cases with an "error" function that tells the user to re-enter their choice.

6. a file import function that opens a csv and imports it into the dictionary used in the script.  The script will parse the key values written in the source file, and set the state counter to the max key value among the imported data.  (The "add new item" function increments the counter before an item is actually added).

7.  Item delete, with the user being able to type in the item name.  Again, a get function provides some edge case handling.

Future:

1. a user input checking/cleaning module
2. differentiate between input/output files
3. dynamic column names/dictionary keys depending on user input and/or csv contents
4. delete column based on user input
5. forecasting expenses.

Not bad for one day's work at this stage.

Thursday, January 14, 2016

Day 5 - Learning clean code...and I make a thing unnecessarily recursive

Another moment of undiluted joy today: I built a recursive function, mostly from scratch.  That was one good lesson.  The other was ensuring that each function does one thing well...and generally one thing only.  That makes the function more portable, and makes code easier to understand and to troubleshoot.  

The project itself was a fairly simple exercise in opening and closing files and writing functions.  Given a file of 1000 lines, split it into two new files of 500 lines.  Doing so was pretty straightforward, and a little bit more work got it cleaned up (after a discussion of functional hygiene, so to speak).  I've had a tendency to treat functions like sub-scripts and just list a bunch of operations until a function "felt" unwieldy, then call in a new one to finish the job.  

I like this approach better.  I'm getting a better feel for how code works, and how the pieces fit together like legos.  You can build better stuff using legos, when you have lots of little pieces that each do one thing well.  Having large, unwieldy, highly-specialized pieces may let you build one thing well (like a space ship) but isn't very useful for building any of the other things you can imagine.

And yes, I went on to build a recursive version of the file-splitting program.  It will take a file of any size, and split it into files of a specified number of lines.  I know there's limitations to this approach (it's resource intensive, it's hard to read, it's slower than simpler versions that do the same thing...).  The point, though, is that I made a working recursive program, and I did it by following the arguments through the logical steps needed to make it work. I didn't give up when my script ran without errors, but terminated without producing the files I expected.  (That was an interesting new troubleshooting experience.)

So.  We're getting into recursive functions next week, formally speaking.  I'm relieved to know I can make one work.  I'm looking forward to learning the situations in which it's useful.

In other news, I woke up at 6 this morning with a great idea to make my "variable_catcher"aka "error_checker" function work better.  I had enough time to test my idea in the terminal, and it may work.  I didn't have time to play with it though.  Tomorrow is supposed to be review...so perhaps then.





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.

Tuesday, January 12, 2016

Day 3 - Getting looped

I got a 'coding buzz' today.  I'm not sure if that's even a thing, but I had a moment where a difficult challenge was falling into place, and I'd just run through a set of coding challenges in record time, and I really felt in a 'flow state' with coding.  It was joyous.  I've been terrified of making this change, and doubting whether I really belong, whether I'm good enough, whether I can "think like a coder".  Maybe I drank too deep of the elitist kool-aid on various forums wherein the cognoscenti opine on who is fit to be a coder, and who is merely a poser hacking at web frameworks.  One good day is certainly not enough to base a career on, but...it felt so good.

Today was all about loops and data structures.  As it turns out, this is a topic with which I'm pretty comfortable, and one which I've used a bit in project Euler and project Rosalind.  I got a little hung up on a set of nested dictionaries, and aggregating all the numbers hidden in values in keys on various levels.

Instead, I used my extra work time to build a small debugging tool that displays all the variables, their types, and their values at a give point in a script.  The idea came from a moment in lecture about following a variable through a script and keeping track of the type and value associated with a particular namespace by using a table:

a = 5
b = a
c = str(a)
name          type           value
a                 int              5
b                 int              5
c                 str               '5'

(yeah, it's a trivial example, but its 930 pm after a long day and still have some things to read for tomorrow).

To automate this process for more complex code, I wrote a series of functions that would collect the variables currently in use (using dir(), which supplies the names in use), remove the 'magic' variables since those clutter the table of variables declared by the user, and collect the type and value of said variables, and then display that all in a table as a print-out in the command line. (credit to Jonathan for introducing the table display and Jeremy for suggesting the dir() function as a means of collecting variable names).

The first version of this was assembled at the end of one of the coding challenges.  It was a mess, with global variables called in multiple places.  Plus, having this code at the end meant that any error that occurred higher in the script would would never be caught by my variable-catcher.

The next iteration cleaned up the global variables into functions...whereupon I discovered that dir() called within a function finds only the local variables.  Version 0.3 saw all the function definitions moved to the top of the script (so they would be available when called anywhere below).  The whole process was now called in a function 'print_table' that took dir() as it's only parameter.  That way, "print_table(dir())" could be inserted at an arbitrary point and dir() would harvest the names in the scope in which it was called.  The list generated could then be processed and displayed.

Version 0.4 saw the various function definitions moved to an independent file (error_checker.py on github).  Now, instead of having to copy my code into a problematic python script, you can simply copy the error_checker.py file into the same directory, and add "from error_checker import *" to your code.  Finally, just type "print_table(dir())" at the point where you wish to see the names in use and the table will be printed to the terminal.

Improvements I'd like to make: output to a csv file instead of terminal, dynamically catch the 'magic' variables that should be removed, and a few cleaner implementations of search functions.

So, hardly perfect, but I'm pretty happy with having gotten it to work so well, mostly on my own (beyond the dir() suggestion, and some suggestions for making the code cleaner and more compact), and entirely in the time after the main challenge work of the day was completed.

Monday, January 11, 2016

Day 2 - The Coding Begins

Today was a lot of orientation, a good chunk of lecture, and a review of the prework material: basic elements of python like data types, string functions, conditional statements, and so on.

It was all review since I've been working with these things for a while.  Regardless, there are always things to learn.

1. Push yourself

Meeting the minimum specs today would have been easy.  On one exercise, I finished early and helped a neighbor. Later, though, I made challenges for myself.  One exercise was to build a simple questionnaire to learn more about other students.  It was to run in the command line and ask 'yes' or 'no' questions.  I built it from the start to be case agnostic and to accept 'y' or 'yes' as equivalent answers (or 'n' or 'no').    The questionnaire also accepted short sentences for some of the questions and returned an answer based on wether user input contained a certain word or phrase.  One of the questions used a while loop with a counter.  An answer recognized as correct was registered, and the loop broken.  Otherwise, 3 wrong answers would break the while loop and move on.  For a half-hour project, it was ok.  (Although I went back later that night and cleaned it up a bit and fixed a weird bug in the while loop.)

The sample is here, with code and functional in-browser implementation courtesy of trinket.io. A useable version is embedded below:

(I'm writing all this down in part to remind myself, later, of how far I've come.  I know this stuff is trivial, but one of my projects while here to work on consistently pushing myself to do more and better than what's required.)

I learned, too, by comparing notes with my neighbor and seeing that she had made a list of questions that were accessed in order whereas I had simply created a script that was executed from top to bottom with a series of conditional statements.

2.  Keep going until it looks 'right'

Python, I hear, is notable for having many alternative ways of getting something accomplished.  Not all of them are equal in terms of speed, elegance, understandability, or "python-ness".  Learning when something 'looks right' is another long term goal.  There was a long series of tests of basic skills as part of the work.  One test (completed by setting a variable r = to some statement) was

# use the 'in' operator to see if 3 is in the array
a = [1,2,3,4]
assert r == True

My first answer was

if 3 in a:
    r = True

That works, and it's easy to understand, but it takes two lines. Defining r didn't sit right, either, since it seems that r should evaluate to True. My second effort:

r = 3 in a

which satisfies both the single line aesthetics and that the value of r is determined by evaluating an expression.

Another challenge asked

#get all the keys of hash a and set it to r

a = {'a':1,'b':2}
assert r == ['a','b']

My solution was

r = [x for x in a]

I've really struggled with this syntax in using an iterator to generate a list.  Trivial, again, but I pushed myself to do it the compact way.

Tomorrow, more things.  And now to sleep.

Sunday, January 10, 2016

First Day

The first day of code school is finally done.  Code-wise, there's not much to report since today was all logistics: getting to the site, getting settled, meeting people, etc.

It's interesting to see the mix of people here.  There's only 9 students (of whom I've met 7).  I won't go into specifics (Hi everybody!)...but it is interesting that so many of us have tried various other paths and been disappointed.  I'm not the only former adjunct professor here, for one.

That's the modern mode, right?  Endless self-reinvention.  I read blog posts by people with PhDs (in microbiology, like me!) who parlayed that into being CEO of a biotech company by age 45.  Or people like my friend from high school who got a CS degree and has steadily worked his way up the ladder to where he's recently joined a startup...and he did it never having left Seattle.  The promised land.

Regardless, I'm here, and I'm very, very ready to get started.