What I learned from Python Koans
Or: A Programmers’ Guide To Thinking In Python§
I’ve been dabbling with Python on and off since the 2.x era, when I just thought of it as a curiosity with syntactic whitespace. But I’ve never really set myself to learning it thoroughly. Now it’s become one of the most popular languages in use, especially for data analysis, so I started working with Python Koans to get myself familiar with the language. I’ve found while learning that there are a lot of guides that assume you’ve never written code before, but relatively few that address Python to an audience of existing programmers learning a second (or third, or tenth) language.
This information may feel very obvious to people who’ve used Python a long time, but writing about new things helps me retain and contextualize what I’ve learned.
The Kinds of Collections§
Lists§
Lists are basically arrays, as you think of them in most C-like languages.
Tuples§
On the surface, they’re just lists but immutable. A lot of languages don’t actually have this data type so using it doesn’t come naturally to mind if you’re coming from, say, Javascript. The concept exists in computer science, though. Relational database rows are a kind of tuple. They’re the right construct for representing a column-based record (SQL query results, CSV data, spreadsheet input, etc.), since the column order matters and it shouldn’t be messed with.
Set§
A set is a unique collection of values. Useful when you need to ensure you’re getting a unique subset.
// In other languages you have to work around the lack of sets like:$distincts = [];foreach ($record as $r) { $distincts[$r] = 1;}
// or$distincts = [];foreach ($record as $r) { if (!in_array($distincts, $r)) { $distincts[] = $r; }}In python you can just do this:
distincts = set()for r in records: distincts.add(r)
# or even better!distincts = set(r for r in records)
# or even EVEN better!!distincts = set(records)Overview§
| Collection Type | Ordered | Keyed | Unique | Iterable | Mutable | Adding |
|---|---|---|---|---|---|---|
| List [1,2,3,3] | ✅ | ❌ | ❌ | ✅ | ✅ | .append() |
| Tuple (1,2,3,3) | ✅ | ❌ | ❌ | ✅ | ❌ | N/A |
| Set {1,2,3} | ❌ | ❌ | ✅ | ✅ | ✅ | .add() |
| Dictionary {“a”: 1, “b”: 2} | ❌ | ✅ | ✅ (by key) | ❌ (use .items()) | ✅ | my_dict["key"] = value |
There Are a Lot of Ways to Iterate§
Regular Old Loops§
I think of these as “regular” loops because they’re the kind you find in any C-like language:
for item in iterable_collection: doStuff()
for i in range(x,y): doStuff()
for k, v in this_dictionary.items(): doStuff()
i = 0while i < 5: doStuff() i+=1
# While loops have an else though! It executes any time you don't breaki = 0while i < 5: print(1) i += 1else: print("All done") # This always prints _unless you break_!List Comprehensions§
List comprehensions are almost inside-out loops: you define what needs to be done, then over what iterable to do it. They apparently don’t have to be a single line, but it seems to me readability would suffer if they started to get a lot longer. Probably better to define a function and use the function in the “do” portion of the syntax.
# Return a list from a collectionresult1 = [item * 2 for item in iterable_collection]
# Return a list by executing N timesrestult2 = [doStuff() for _ in range(0,n)]
# Return a list over a collection conditionallyresult3 = [doStuff() for k,v in {"a": 1, "b": 2, "c": 3, "d": 4}.items() if v % 2 == 0]Modules§
A folder that contains an __init__.py file can be treated like a module. The __init__.py
file defines what gets exported from that module.