Back at it after a short personal break. Lots of stuff to catch up on!

MITx, 6.00.1x, Introduction to Computer Science and Programming Using Python

Learning about lists.

  • They are

    • iterable, i can run through its elements one by one and do stuff
    • mutable, i can change things inside them
    • append, will append stuff to the end
    • extend, will take another iterable (another list, for example) and then take those elements one by one, and tack them on the the end of this one
  • i can go back and forth, between lists and strings, converting one to the other and vice versa

  • i can sort and reverse sort the items in them.

    • sorted will return a new list
    • .sort will mutate and sort the list itself as will .reverse.
  • since i can change them at will, i need to be careful about things that might break.

    • 10 names pointing to the same list. changing something in one, changes them all.
    • consider cloning a list and making seperate copies. (this is how’d i’d naturally do it. but is it expensive with resource usage?)
    • one example is iterating over lists
      • if you modify them as you run over them, it can lead to all sorts of trouble and confusion, if items get added, removed or changed
        • best to clone the list, iterate over the clone and modify your original
  • i can nest lists. have lists of lists!

  • you’ll get confused and make mistakes. it’s ok.

Learnt about Functions as objects

do i still remember functions?

  • pieces of code (functionality, my customised shit) that i write that i can call from elsewhere.
  • first class objects in python
  • can be elements of data structures (i can have a function in a list)
  • can appear in expressions
    • i can assign a function to something (a variable for example)
    • can use it as an argument to another function.
      • (i have a function that does things to lists. this function could call a function that sorts and sanitises the list, first)
  • basically, i can use them the same way i’d use numbers, or strings or lists

this inceptive programming, using function as arguments to others and combining them with other elements like lists (or inside lists to do shady shit on other lists)? it’s fancily called higher order programming.

  • i could apply a series of functions to a list
  • i could apply a series of lists to a function

and all this stuff generalised and abstracted are called higher order procedures
python provides something like this, called map
very simply put, map

  • takes a function that expects a single argument. (len for example or abs)
  • and then runs them on a list (or it creates a list where it applies that function to each element in it.
  • what it returns is an iterable (think of it as the elements of the list, coming out one by one, but you get your grubby paws on them, before they go into some defined data structure like a list.)
  • you can then do what you want with those hot cross buns, er, elements. print them. put them in a list. whatever. it’s all good.
  • i can now amp this up to a 11. map can
    • take n functions and run them on n collections of arguments.
    • simple example, run through the elements of two lists, compare them, and pop out the lower number for each element. print or save or whatever.
    • mind fucking blown. insert Keanu going, ’I know Kung Fu!’

Common operations across strings, tuples, ranges and lists

if i assume seq is any of these data structures, i can,

  • seq[i] - get the ith element in that list or string or range or tuple
  • len(seq) - get its length
  • seq1 + seq2 - concatenate two of them (not range)
  • n*seq - repeat them (not range)
  • seq[start:end] - slice and dice them
  • e in seq - will return true if e exists in the sequence
  • e not in seq - will return true if it’s not
  • for e in seq - will iterate over each element in that sequence

Dictionaries

Why? They save me time!
Instead of indexing on numbers, like I do with the 1st element or the 0th element of a list, i can just index on things, I define myself

  • Like there’s a list of names and I can then attach attributes to them. relationships, address, phone number, whatever.
  • works just like a real dictionary. i can look up a word and then see all the information related to that word.

In python you create dictionaries using braces. and store data using key value pairs. here’s a few

  • dictionary_of_names = {} creates an empty dictionary.

  • dictionary_of_ages = {'Jason':40, 'Tess':48; 'Leo':76} creates a dictionary of names (keys) with their related ages (values)

  • and now I can just ask for Tess’s age with a dictionary_of_ages['Tess'] without having to lookup where and at what location Tess is in the dictionary

  • dictionaries are mutable

    • I can add entries (dictionary_of_ages['Puppy'] = 4 will add the age of my stray doggo to the dictionary)
    • I can test for existence of entries ('Leo' in dictionary_of_ages)
    • I can delete entries with a del
    • i can list my keys by calling the dictionary like a function using the keys method like so (dictionary_of_ages.keys()) and similarly I can get at the values with a dictionary_name.values()
  • unlike a proper dictionary though, there is no order to the way things are stored in a software dictionary. mostly its the order you shoved stuff in; and that can change.

  • on keys and values

    • values
      • can be any type
      • can be duplicated (different people having the same age)
      • can actually be any data structure (lists, numbers, strings, other dictionaries)
    • keys, on the other hand
      • have to be unique (can’t have two folks with the same name. if they do, then probably time to think of indexing on something else?)
      • need to be immutable (which restricts me to ints, floats, strings, tuples or booleans. can’t have strings in there)
        • actually according to Prof Grimson they need to be hashables, but I’ll cross that bridge when I come to it.
      • careful using floats as keys, because of accuracy issues.

So because of their flexibility on what they can store and index on, dictionaries are much more capable than other data types

Testing & Debugging

It’s like soup!
You’re making soup and there are bugs falling in, from the ceiling.
So how do you get good soup?
You could,

  • Check the soup and remove the crawlies if any. (that is testing your code)
  • Keep the soup pot covered. (defensive programming)
  • Clean the kitchen, so there are no bugs (eliminate the source of bugs. debug it. kill it.)

Defensive programming is,

  • how do you structure your code?
  • how do you write code that plans ahead?
  • it has three parts
    1. write specifications for the functions you write
      • use docstrings
      • mention what you expect as input and what you will provide in return
    2. Write modular programs
      • break up your program into obvious pieces.
        • something that collects data for e.g., and something else that works on it (could be one, or more pieces) and something elser that delivers it out.
        • help you while testing, because you can test each little piece seperately
    3. Check conditions on inputs and outputs.
      • i don’t know what this entails, will update this later

Testing code, basically boils down to checking inputs and outputs.

  • What did i expect to come in? What is my expected result?
  • If stuff’s not working, what do I do to debug it?
  • What can I do to stress test and break my program?

Debugging
Yikes! I have a bug!
How do I kill it? What do I want to do to fix this?

  • Look at the events that led to the error
  • Ask yourself, “Why is it not working? What’s causing that?”
  • and then having found that, “How do I fix it, so all is right with the world again?”

Set yourself up, for easy testing and debugging

  • Design code so this part is easy!
  • Is your code modular?
  • Are docstrings in place? What are you expected inputs? Output?
  • Document your assumptions. Why did you write this piece of code the way you did?

When you test you can,

  1. Unit Test
    • validate each piece of your program
    • test each function seperately
  2. Regression Test
    • if you find bugs, test for them the next time around
    • catch reintroduced errors that were previously fixed
  3. Integration Test
    • Does the overall program work?
      It kind of feeds each other like a cycle, so don’t hesitate to go around and round the testing circle.

Testing Approaches

  • Intuition
    • what do you think you naturally need to test?
    • what makes sense?
    • just pick things at random
  • Black box testing
    • use you program like an appliance
    • it says it does this on the box. well does it do it? does it do it well?
  • Glass box testing
    • look at the code and then test each path in the code
    • can’t do this with every path properly sometimes
    • do the big branches

Bugs

  • Overt
    • the program crashes
    • your computer hangs
  • Covert
    • the answers might not be expected
    • they might look ok, but are actually wrong. (off by 1?)
  • Persistent
    • happens every time you run the program
  • Intermittent
    • happens only some times

  • Overt & Persistent

    • Easy to detect
    • use defensive programming to try to steer bugs to fall into this category
  • Overt & Intermittent

    • if you can find what’s causing it, yay!
  • Covert

    • Really dangerous. you might be relying on wrong results and data that you wrongly trust!
    • could be a really long time before you catch something like this
  • Be Patient. this will take time to get good at

  • Use print statements liberally

    • when?
      • enter function
      • parameters
      • function results
    • use the bisection method
      • divide and conquer!
      • print halfway and then decide which half to focus on
  • Be systematic. Use your little grey cells.

  • Figure out the common errors (type errors, value errors, syntax errors)

  • Logic errors, the program does not work as expected

    • think of programming as a novel you write
    • dream up the path
    • explain your code
    • walk around trying to create the model in your head
    • how did i reach this place? this bug?
    • try explaining it to some one (or your rubber ducky)
  • Use the scientific method.

    • look at what you have,
    • figure out what could be causing the error,
    • think about what could fix it,
    • and then try it.
    • is it fixed? no? go back and try again :)

Work with small things.
Work in increments.
Test and debug it.
Use backups.
Have versions.
Test and compare across versions.
Feel free to work up and down the version tree

Professor Grimson is awesome, and teaches me the way, I imagined some one teaching me CS basics. So many aha moments!