In Python, built-in types such as dictionaries are different from classes that you or I put together. Before Python 2.2, the differences were not incredibly overt, but they served as an annoyance. The biggest difference was that you could not subclass built-in types in your own classes. While differences still exist, these differences are now fewer in number and less severe since the introduction of some new features in Python 2.2. Now, you are free to subclass built-in types, and many other things have been introduced as well that we will discuss. Classes that utilize these new features are called “new-style” classes.
Let's build one of these new-style classes by subclassing the int type. Currently, if you create an int object and assign a decimal value, everything past the decimal point will be cut off:
>>> x = int ( 5.2 )
Let's say we wanted to subclass int and change this behavior, rounding the number to the closing integer. What was once impossible in Python is now easily done. We simply set int as the base class for our new class, and we do our magic in the __new__ method:
>>> class RoundInt ( int ):
Now, you may be wondering why we use __new__ rather than __init__. The answer is very simple: __new__ is responsible for returning an instance of the class. We have to round the given number before the number is returned, or it will be too late. You may also be wondering why we use the variable cls rather than self. This can be explained by this bit of code:
>>> class TestInt ( int ):
Of course, nothing is stopping you from using self rather than cls, just as nothing is stopping you from using this as opposed to self.
Instead of referencing int when we access its __new__ method, there is an alternative way to write our RoundInt class. We'll rewrite our class to use super:
>>> class RoundInt ( int ):
Here's the result of our class:
>>> y = RoundInt ( 5.2 )
We could also create a class based off int that accepts a sequences of numbers, adding them all together to get its value:
>>> class ListInt ( int ):
Here is our new class in action:
>>> x = ListInt ( [ 1, 1 ] )
It's easy to see that this allows for some pretty unique and interesting things to be done with Python. Let's say that we want to subclass dict to take two arguments: a list of keys and a list of values. In __init__, these lists will be put together: one key to the one respective value. If none of these arguments are passed, then this special process is ignored. We use __init__ rather than __new__ because we want to work with the already initialized dictionary. Here's how it's done:
>>> class ListDict ( dict ):
Here's how our new class works:
>>> x = ListDict ( [ 'one', 'two', 'three' ], [ 'eins', 'zwei', 'drei' ] )
Obviously, this new ability is a pretty big change to Python. The products of it can be quite interesting, as our two examples have shown. This change to the language allows you to create hybrids of built-in code and user-written code which better suit your application.
blog comments powered by Disqus