Started with a new Reuven Lerner Course, on Advanced Data Structures..
Aiming to comfortably finish this in a week.
Notes and experiences, follow.
The course is three parts.

  • Part 1 - Deep dive into the common data structures
  • Part 2 - Combining Data Structures. Lists of lists, Dicts of lists, Tuples of Lists and so forth. How far can I go without classes? Or how can I enhance my classes with this approach?
  • Part 3 - Complex data structures, that come with the Python Standard Library. The Collections module, Weak references etc.

Notes

Part 1

  • The id of a variable shows me where the object in refers to, is located in memory.
    If x=5 then the id(x) will point to where it’s object, here the number 5, is located in memory.
  • When I assign a variable to another, what I actually do is assign the new variable to the same objects address. That is all. When I do x = y, then y will point to 5 too, independent of x. If I set x to something else later, y is not going to follow x. Instead it steadfastly points to 5.
  • A simple way to say this is x is y, where I am not checking for equality, but rather testing the fact, that both of them point to the same location in memory, or not.
  • I can use sys.getsizeof() to find the size of an object in memory. (how much memory it uses), but it’s a tricky beast. For e.g. when it shows me the size of a list, it shows me the size of the list object. Not the size of the elements it contains. To get that, I need to go check the size of its elements one by one.
  • A singleton object (not many in Python) is an object that every time you create a new instance of, from the parent class, it always points back to the same instance. None is an example in Python.
  • Better to create a list using square brackets, rather than assigning them via a string. x = ['a','b','c','d'] works better than going x = list('abcd'). This obviously matters upon what you are doing and if that is possible to do or not.
  • I can tuple-unpack-split a string in various ways. If I go, a, b, *c = s.split[] it will get the first split item in a, the next one in b, and the rest will be a list in c. But if I want the first and last elements for example and don’t care about the stuff in the middle, I can also go, a, *b, c = s.split(). I need to play with this. Just realised I could’ve solved a lot of exercises I did in the past, more elegantly if I knew this then.
  • If I access an element in a sequence via its index, I will get the element back along with the elements type, but if I slice a sequence to get just one element back, I get a single element of the sequence’s type. Very nifty!
    • For example if I access s[0] in the list ['jason', 'braganza'], then I will get a string jason back.
    • But if I slice and get just the first element with a s[:1] (get upto, but not including 1), I get a single element list, ['jason'] back.
  • If I look up a key z in a dictionary d with a d[z] and it does not exist, then I get a KeyError. If I want to check keys without noise, I use the get method on a dictionary. If the key exists, the value is returned. If not None comes back.
    • I can set keys similarly with the setdefault key if I want to set keys safely. If I just do d[z] = 100 and z already existed, its value would have gotten trampled and set to 1000. But if I do the samething with a d.setdefault(z, 100) then it sets it to 100 only if the key does not exist. If it does, it just returns the old existing value. No harm, no foul.
  • If I have two dictionaries and I want the contents of one in the other, then I use the update method. For e.g., I have dictionary a and dictionary b, so I do a.update(b) and everything from b flows into a.
    • If there is overlap in the keys, then the values get trampled and overwritten.
  • I normally cannot add dictionaries, lists, or other sets to my sets (no unhashable types allowed), I can freeze a set with frozenset, which makes it hashable and then add it to my set.

Learning / Feedback/ Experiences from doing exercises

  • Reuven makes Python sound like a cute animated bear. ‘Python notices and says “Oh, you’re using 256. I’ve aleady got that. Don’t create a new object for that!”’ I wish my interpreter was as helpful 😂
  • This course is a lot less structured than the basic courses. It approaches you from the point of view, that you know stuff, you can read and write Python, you have a modicum of intelligence, so here’s a really juicy grab bag of interesting stuff about all the basics you learnt earlier.
    • It’s best to always use f-strings, but if you need to eke performance, can you figure out, what kind of strings are the best? (spoiler, benchmark it)
    • While Python lists are expandable, the C structures underyling it are fixed. How does Python let you have flexible, expandable lists then?
  • And so on and so forth. So far, this has been fascinating.

Read all about my Python advanced data structures journey here