By the end of this chapter, you should be able to:
When we discuss special (also called "magic") methods, we are commonly referring to methods that contain a "dunder" (double underscore) like
__init__. You have actually used quite a few of these under the hood, but you can implement your own for classes you create. Let's see a couple:
__str__ - what is evaluated when
__len__ - what is evaluated when
len is called
__del__ - what is evaluated when
del is called
__doc__ - see the docstring for a value
__class__ - see what class created this object
There also exists another method called
__repr__ which is similar to
__str__; you can read about the differences here
You can read more about these here. Pay close attention to the differences between
One of the key principles in Object Oriented Programming is polymorphism. This is the idea that an object can take on many (poly) forms (morph).
A very common example you will see of Polymorphism is the
+ operator. If we do
5 + 3 in Python our result will be 8 as the operator knows to add the two numbers. But if we do
"8" + "3" Python knows to concatenate the values since they are strings. This single operator can take on many different forms, depending on the types it is working with!
You can see polymorphism applied when there is the same operation used for objects in different classes. Let's see another example!
sample_list = [1,2,3] sample_tuple = (1,2,3) sample_string = "awesome" len(sample_list) len(sample_tuple) len(sample_string)
These are three different classes that have the same operation applied to them!
A common implementation of this is to have a method in a base (or parent) class that is overriden by a subclass. Each subclass will have a different implementation of the method. When the superclass/parent class method is called, it chooses which method to run depending on the subclass/child class. Let's look at a common example:
class Pet(): def talk: raise NotImplementedError("Subclass needs to implement this method") class Dog(Pet): def talk(self): return "WOOF!" class Cat(Pet): def talk(self): return "MEOW!"
To implement polymorphism you do not need a superclass / parent class. It is only when you are using inheritance and polymorphism together that it is useful to ensure that the subclass implements its own version of the method.
For more on polymorphism, check out these articles:
In Python, you can't manipulate base classes for native data types in the same way. However, you can create a new class which extends the built in class, and add methods to the class you've created. To do this, you'll need to import the
builtins module and manipulate the class you're interested in.
import builtins # Extended subclass class extend_str(str): def first_last_character(self): return self + self[-1] # Overwrite the str class on builtins with the custom class defined above builtins.str = extend_str str(0123).first_last_character() # '03' str("awesome").first_last_character() # 'ae' "awesome".first_last_character() # 'str' object has no attribute 'first_last_character'
Note that in the example above, you can't use your custom method on strings unless they're explicitly created by being passed into the
str class. In short, this approach is cumbersome and not foolproof. But that's probably by design: you shouldn't be trying to modify these classes in the first place!
When you're ready, move on to Object Oriented Programming in Python Exercises