At the core of any programming language is the notion of functions, but we tend to take them for granted. Sure, there’s the obvious fact that functions allow code to be encapsulated into individual units, which can be reused rather than being duplicated all over the place. But Python takes this beyond just the notion of what some languages allow, with functions being full-fledged objects that can be passed around in data structures, wrapped in other functions, or replaced entirely by new implementations.
In fact, Python ...