More Special Methods
In the previous lesson, I showed you even more about descriptors than was covered in part one of the course and gave you an overview of
.__slots__. In this lesson, I’ll continue down the dunder rabbit hole, and if you’re lucky, you’ll see a smiling cat. Is an Alice in Wonderland reference too obscure?
Continuing on our journey to dunder all the things, let me remind you that everything in Python is an object. So when you go to do key things like operations, they are actually implemented with methods. They’d have to be ‘cause, well, they’re objects. And using dunder methods, you can perform operations like adding, subtracting, in fact all the math things, as well as bitwise operations, convert things … You’ve seen
.__repr__() in previous parts of this course, and this goes for all conversion.
float() invokes a corresponding dunder method. That also goes for comparison. All the things you might do in an
if statement, like comparing for equals, are done with dunder underneath.
01:14 Let’s go visit the Great Down Dunder. No? Enter the Dunder Dome. Dunder the Boardwalk? Okay, I’ll stop now. Nah, one more. Dunderworld, a movie about tight pants and object methods. Entertain me.
01:33 A common reason to override operations is to implement classes where those operations are natural. If you want to build math concepts like matrices or vectors, there’s no reason why you shouldn’t be able to take advantage of the math operators, adding two of them together, for example. Of course, most of this is already in the standard library or third-party libraries like NumPy, so don’t write it yourself, but if you wanted to, this is what it’d look like.
The signature takes on one other object, the thing being added to this instance. The result of
.__add__() should be a new vector with its attributes being the addition of this vector and the one passed in. To make this visible in the REPL, I’ve also implemented
There are a ton of these dunders in the base object, which you can override. Using dunder methods, you can create context managers, muck around with dynamic class creation and instantiation control, check whether something is inside something else, is an instance of something else, or how long it is, control what happens when the
format() function is called.
03:27 In a previous lesson, you saw how to control some of those attribute management things, but it goes much further. There are multiple mechanisms for getting, setting, adding, and removing attributes, and that’s not it.
03:40 There are over 125 dunder methods and attributes on the base class, which you automatically inherit just by writing a class definition. There are so many that if you laid them end to end, you could use a submarine to travel 20,000 leagues—say it with me—dunder the sea. Before moving on to the next lesson, a quick little tangent about things that can go wrong.
Depending on what you’re doing with a class, you can see different kinds of errors. An
AttributeError is raised if you attempt to access an attribute that’s not on the object or class. A
TypeError is raised if you’re trying to do an operation on the object that isn’t implemented. For example, calling
len(), which invokes
.__len__() on an integer. And some classes that expect to be extended will define a method and have it raise a
04:30 That way, if the extender didn’t override it, you’d get this exception. There’s another way of accomplishing this, though, called an abstract base class, which I’ll cover in a later lesson. If you’re writing classes, there are a few common mistakes to look out for.
Forgetting to include the
self argument in a method will cause either an exception if you had no arguments at all, or having a reference to the object stuffed in whatever you wrote as the first argument.
05:06 Another case is confusing when you are supposed to be using the class itself vs an instance. This isn’t as common as the previous error, but can happen when you’re supposed to be passing around a class reference rather than instance reference to, say, a utility method or function.
05:29 I covered a tricky version of this bug in part one of the course, where I showed the accidental creation of an instance attribute instead of modifying an existing class attribute. Not quite mistakes, but some things that can lead to problematic code are using non-public members outside a class.
05:48 Things with leading underscores are a sign by the coder that they might change or have side effects that you’re unaware of. Generally, if you aren’t inside the class, you shouldn’t be using non-public members.
06:01 The entire third part of this course could be summed up in don’t misuse object-oriented relationships. Coders new to OO or coming from object-oriented heavy languages will tend to create oodles of objects.
06:13 This is often overkill in Python, and likewise, you can always tell a programmer who’s recently discovered the beauty of operator overloading when they tend to overload the operators to save typing.
Become a Member to join the conversation.