What's in a Software Dev degree anyway? Course 1 - Information Structures

This is a continuation of What's in a Software Dev degree anyway?. Again, expect examples with no math and no crappy names

Okay, I did it. First class of this degree is done. This post is just a cumulative of topics and concepts that were covered in my 1st course of my Software Dev degree.

As of now, I'd still consider myself self-taught. It's rough not knowing what you should learn next. I have a lot of gaps in my knowledge. That's why I decided to go to school. And also why I'm hoping sharing this will help someone else.

MET CS 521 O1 Information Structures with Python (2021 Fall 1)

Jump to:

Wait! I just wanna test myself on the exercises you had in class. Glad you asked, here's the repo: Exercises for first class

Input (Learning Objectives)

Week 1

  • Data Types
    • primitives vs collections
    • primitives: int bool float complex char
    • collections: list tuple set dictionary string
  • Namespaces
  • Input/Output
  • Variable Scopes (legb)
  • Importing modules
  • statements dog_age = 6 vs expressions dog_age + 1
    • statement returns nothing
    • expression returns something, also called a side effect
  • Functions that can be applied to different data types are polymorphic

Unrelated to the curriculum, I also learned:

  • the professor has a preference for explaining Python in relation to C++ instead of explaining in ways everyone can understand.
  • use RateMyProfessors.com to look up before registering for future courses. I was watching Netflix series “The Chair” and learned about this.

Week 2

  • Data Types
    • complex numbers
      • totally new to me. Guess they’re used in things like electromagnetics, chemistry, and economics.
  • fractions module is super neat
  • Hashing hash() for quick comparisons (still confused on this)
  • Mutability
  • Python Ranges
  • Copying Objects
    • shallow copy makes copy but points to other object
    • deepcopy() makes new object
  • == vs is
    • == checks values
    • is checks id to see if same exact object

Week 3

  • UTF - 8 numbering for alphanumeric characters
    • chr() and ord()
  • Strings
    • immutable, but there are work arounds
      • range(start, stop, step)
      • half-open range: does not include stop number
      • slicing [start:stop:jump]
      • string reversal string[-1]
      • out of bound slicing will not error, but give you whatever is in bounds
      • string formatting {:[alignment][width][decimal precision][type descriptor]}
  • Control Flow
    • if-elif-else
    • try - except
  • Iterations
    • while and for
  • Files
    • open,read, readlines, write, writelines
    • importance of close
  • Lists
    • list comprehensions
      • can have multiple conditions
      • works for mutable objects (lists & sets, not tuples & strings)
numbers = [13, 72, 11, 43, 66, 82]

# iterate to get even numbers
evens_from_nums = []
for num in numbers:
    if num % 2 == 0:
        evens_from_nums.append(num)

# list comprehension to get even numbers
# same as above, just shorthand
odds_from_nums_again = [num for num in numbers if num % 2 == 0]
  • list reversal with slicing or .reverse()
  • enumerate() for indexed collections
    • returns a list with an index number
  • sort() vs sorted()
    • sort() changes things in place
    • sorted() orders things and creates a new list

Week 4

  • Lists
    • See above, went over some list stuff in week 3
    • indexing a nested list list[1][2] would give index 1 of main list then index 2 of the nested list
    • sorting list of list sorts on the index [0] of nested lists
    • some methods that modify a list: append() pop() extend() insert() remove() sort() reverse()
    • reversing a list list[::-1] (gives no start or stop and a -1 step)
    • Exercise: check if words are anagrams
    • create a copy slice using [:] (shallow copy?)
    • when list appends itself as an element, infinite regress occurs
  • Tuples
    • single element tuple tuple = ("cat",) note the trailing comma, otherwise this would not be a tuple
    • can use the same set up for a list comprehension
    • immutable but can contain mutable objects
    • tuples use most of the same methods as lists, except the ones that would change a list (eg append())
  • Dictionaries
    • can use a similar set up for a list comprehension
    • keys are not arranged in a specific order, they are in an order to efficiently search
    • Exercise: count words or letters in a string
    • namespaces are implemented with dictionaries
    • items() all key-value pairs as a list of tuples
    • keys() all keys as a list of list
    • values() all values as a list of list
    • zip() 2 or more lists together. Tuples by default
    • can merge dicts with update() (note: for keys that already exist, values will be replaced)
  • Sets
    • mutable, not ordered, only unique values
    • subset small_set <= big_set vs superset big_set >= small_set
    • frozen sets are possible to make sets immutable
    • Methods
      • & or intersection() creates new set of all elements that are the same
      • | or union() creates new set of all elements of both lists
      • - or difference() creates new set of all elements in 1st set but not 2nd set
      • ^ or symmetric_difference() creates new set of all elements that are different
      • Link to Python Tutor with examples (with animals) of these set methods
    • split() returns a list
    • data type is the actual use of data structures, where data structures are more the theory or idea of
    • efficiency refers to time, space, and algorithm
    • Implementing other data structures with the types we have
    • stacks can be made with lists
    • Ternary if basically an if-else but jammed onto one line
true_thing if condition else false_thing  # ternary syntax
throw_ball() if dog_wants_play else pet_dog()  # ternary example

Week 5

  • Error Handling
    • interupts vs Exceptions
    • Allows us to watch code for errors
      • useful for things like user inputs ("All user input is evil")
    • Try - Except
      • can handle multiple exceptions
    • can do except IndexError as e to later use e (the error)
    • If you use finally it runs every time, not required though
  • Functions
    • functions are objects and have their own namespace (reminder: everything is an object)
    • function docstring can include inputs, outputs, what the function does
    • Parameters != arguments
      • parameters are in the function definition def feed_dog(dog_weight):
      • arguments are in the function call/invocation feed_dog(25.5)
    • functions return None if there is no return statement
    • can pass functions as arguments
    • possible to have different function "signatures". same name === same function
    • default parameters def pet_cat(time="now"): if you don't give a different time, cat will be pet now
    • variable positional args def func(*args): this requires a tuple as input
    • Mutable parameters as args/params, avoid if possible. Can cause issues
    • parameter names as keywords feed_dog(dog_age=5, dog_weight = 25.5)
    • annotation of params to document/suggest what type the param should be def feed_dog(dog_weight: float, dog_age: int):
#syntax
 def function_name(param1, param2):
     '''what it does, inputs, and outputs'''
     # code for your function to do
 function_name(arg1, arg2) 

 # example
 def feed_dog(dog_weight: float, dog_age: int):
     '''calculate/output how much to feed dog with given dog weight arg'''
     pass
 feed_dog(25.5, 5)

 # -----other ways to call/invoke-----
 # how to invoke with out of order args
 feed_dog(dog_age=5, dog_weight = 25.5)  # also useful when there are a lot of params
 # use a dictionary for function args
 dog_dict = {"dog_weight":25.5, "dog_age":5} # same names as params
 feed_dog(**dog_dict)  # using ** to pass a dict
  • generators functions
    • use yield instead of return
    • allows you to start where you pick up as opposed to the beginning like a return
    • yield give results and wait until next time function is called
    • __iter__() __next__()
  • Lambda Function

    • lambda args: expression
  • map() filter() reduce()

  • Recursion

    • must have a base case and the base case must be first in the function
    • can be slower than a non-recursive function
    • Advantage: less code, may be easier for some problems
    • Disadvantage: inefficient on memory and processing time, harder to read and follow
      • Calls by...
      • if you pass a mutable param -> call by reference
      • create a new object -> call by values
      • if you pass a immutable param -> call by value ### Week 6
  • Classes

    • can be used to make new data structures. (Classes were used to build dict(), set(), list() etc)
    • defining a class:
    • self allows an object to keep it's own data (like this in js/c++/java)
import copy
class Dog():
    __stomach = 1  # a static variable w/ name mangling
    # define a constructor
    def __init__(self, name):
        self.__name = name  # w/ name mangling

    def __copy__(self):  # shallow copy 
        return Dog(self.__name)  # w/ name mangling

    def __str__(self):
        '''give a string when you print(instance_variable)'''
        return 'dog with name: ' + str(self.__name)  # w/ name mangling
    def add(a,b):  #
        return Dog(a.__name + b.__name)
    def get_stomachs(self):  # getter/accessor
        return self.__stomach

    def eat_dinner(self):  # self is like `this` in js/c++/java
        '''a class method for the dog to eat dinner'''
        # use Class_Name.variable to get the static variable
        print(f"{name} reports for dinner with their {Dog.stomach} stomach")

dog_one = Dog("wiley")  # makes a Dog just like list() makes a list
dog_one_come = dog_one.eat_dinner()
dog_copy = copy.copy(dog_one)
print(dog_one)  # prints return of __str__
  • Static vs. Instance Variables
    • better to have static variables vs instance variables
    • better to have 1 copy of a variable as opposed to 1 copy per instance
    • static vars are before the methods defined in a class
    • instance var or non-static would have the var in a method and each instance would have it's own copy of the var making it not so efficient
    • __repr__() "official" object description (example: <__main__.Dog object at 0x7f545b6db8d0>)
  • Data Encapsulation
    • no private like java
    • all methods and variables are public
    • name mangling provides minimum protection
      • give __ before name like __stomach to prevent accidental changing.
      • Though you could still change Dog._Dog__stomach = 4 it would just be less of a chance to do it by accident
  • Overloading
    • Could write a method to use +,-,<,>,==,!=,&,! in a way they weren't already built to do by using "magic methods"
    • magic methods are just overwritten methods that overload operators?
def add(self, other):  # 
        return Dog(self.__name + other.__name)
  • Inheritance and Polymorphism
    • can derive classes from new classes.
    • In real life, mammals could be a parent class and cats could be a child class. Cat has some similarities, but some stuff is different
    • if child class doesn't have a str() defined, python will look in the parent class
    • functions like print() and len() can be used across different classes and functions
    • if inheriting a parent class, include in the constructor/__init__
  • Multiple Inheritance
    • python allows classes to have multiple parent classes. not all languages allow this (like Java and C)
    • one problem
  • Abstract Classes

  • Unit Tests

    • run your function and use assert statements to test the expected output

Output (Projects and Work)

Week 1

assignment

quiz

The quiz had some ridiculous questions on it. Oh well.

Week 2 (data types, casting, mutability)

assignment

Week 3 (strings, control flow, loops, files)

assignment

Week 4 (lists, tuples, dictionaries, sets)

assignment

Week 5 (error handling, functions, recursion, generators)

assignment

Week 6 (classes, overloading, ecapsulation)

assignment

Week 7

Final Project

Final Exam

15 questions and 30 minutes later.
Covered:

  • generators
  • nested list/tuple indexing
  • function syntax
  • slicing
  • hashable and immutable data types
  • break and continue
  • classes and inheritance

Documentation (References)

19