The first book I read on management was Peopleware. Its premise was simple: managers should guide and enable their employees, who will do wonderful job just by virtue of being smart, wonderful people in an autonomous, wonderful environment. It was a horrible failure; more due to me and to the team being young and inexperienced than to Peopleware being wrong, but still—it made me naturally gravitate towards the opposite school of thought, where I discovered the Mythical Man-Month.
“Whereas Peopleware says managers should be like kindergarten teachers,” I would passionately explain, indulging myself with a dash of demagogy, “The Mythical…
Finally, we’ve arrived at modules and packages: the last digivolve of Python. At first, it might surprise you to hear there’s a lot to say about them: after all, in C++,
#include is just a preprocessor directive that literally copies over the header, and in Java,
import is just a hint on how to link the bytecode. But in Python, like always, a module is an object—and as always, it opens up a new horizon of possibilities.
Let’s start with the basics:
import. Already, there are quite a few different objects it returns:
>>> import sys
We’re nearing the end of our journey: from stuff as basic as scopes, conditions and loops, through objects, classes and metaclasses — we’re ready to talk about our final topic: modules and packages. Before we do, I’d like to take a moment to address all the object-oriented stuff that I skipped, whether because it didn’t fit the narrative, or I just didn’t want to get bogged down by (even more) details.
There’s a very important special method I skipped:
__hash__. It’s pretty basic on one hand, and a bit complicated on the other, so it didn’t fit in any of…
So far, we’ve been talking about objects: what they are, how they behave, methods and attributes, descriptors, context management and creation. All objects are defined in classes, so we’ve been actually talking about them, too, all along—but classes are interesting in and of themselves; and, at least in my experience, vastly misunderstood.
Other languages, like C++, don’t actually have a notion of a “class” in their code—it’s mainly directives for the compiler as to how it should lay out and wire objects of this type. This way, all the attributes and methods are linked to the same values and code…
Last time, we talked about the awesome power of descriptors; now, getting back to objects, we still have a few behaviors to cover: namely, context management and creation. After that, I’ll add another article for the ones that got away—but in the meantime:
Let’s start with a background story for motivation, again. You probably did this in the past:
>>> fp = open(path)
>>> data = fp.read()
And that’s OK; the question is, whether you did it like so:
>>> fp = open(path)
... data = fp.read()
The reason being,
Last time, we saw how to use descriptors to implement basic Python functionality—namely, methods. This time, we’ll expand our scope to implement more advanced features like properties, class methods, and some cool tricks that aren’t available by default.
Let’s start with properties; but first, let’s come up with a background story for motivation. Say we’re developing a class that encapsulates a 2-dimensional point, and we start with an implementation that uses cartesian coordinates:
def __init__(self, x, y):
self.x = x
self.y = y
Anyone who’s ever programmed C++ or Java would tell you this is a bad idea—you’re…
Last time, we said that everything in Python is an object—integers, strings, functions, instances, and even classes. We said each object has three defining properties: a unique identifier, a type, and a value. The type is the important part: it defines that object’s structure and behavior under different circumstances—whether it’s testing for equality, doing arithmetics, or iterating over it. The value is just the object’s state, which parametrizes this behavior.
Curiously, the most sophisticated behavior is also the most underrated one: attribute access. It looks deceivingly simple, and all objects have it—but in fact, there’s a lot to be said…
Last time, we saw that objects comprise of an ID, a type and a value—and that the type is by far the most interesting. We’ve covered display, equality and comparison, so it’s time for some more exciting tricks.
Any object can have a boolean value—its state being either “on” or “off”. To make this value easily accessible—for example, to use the object as-is in an
if statement—you’d have to implement the
__bool__ method (unfortunately named
__nonzero__ in Python 2):
>>> class A:
... def __init__(self, x):
... self.x = x
In Python, everything is an object. Well, almost everything—keywords like
if are not; but everything else is: numbers, strings, functions, instances—even classes! Each object has a unique ID, a type that defines its behavior, and a value that parametrizes it—but contrary to popular belief, the most important (and interesting) part of this trinity is the type. In this article, we’ll understand why, and see some of the fascinating behaviors we can imprint unto custom objects.
But first thing first: let’s talk about object-oriented programming, or OOP. So far, we’ve dealt with procedural programming: in this paradigm, abstractions are encapsulated as…
The next stop after functions (and beyond, and internals 1 and 2) is generators: functions with a state. The premise is very simple—you write a regular function with
yield statements instead of
return statements, and when you run the function—even as it’s yielded a value, you can resume it from there on, harvesting the fruit of its gradual execution. The use-cases, however, are many—and fascinating, so let’s get to it.
Generators are often presented as a sophisticated way to encapsulate an iteration, even though they’re much more than that. Even so, let’s start with that:
>>> def gen():