Meta classes in Python
Posted On January 7, 2008 by Sneha Latha filed under
Class method, and Static method in Python are considerably different from that in Java, and C++. Python, also, has an interesting concept called Meta class.
The classic and elegant programming language, Python has many rich, interesting, and often, intriguing features that very few programmers have explored. These include the class methods, static methods, Meta Classes, and Decorators.
In this article, we take a quick look at each of these ideas, and will try figuring out how you can improve your existing code using these methods.
Before that let us remember some basics.
Python is a dynamically typed language, and also, is object oriented. Hence every variable in Python is an object, and it has a type. You can figure out the type of an object using the type() function.
Python has modular approach much like Java, and C#. Except for a few critical utilities, most of the library functions are stored in modules, which need to be imported.
Python is indented, and forces you to indent code, to separate blocks of logic.
Many developers exploring Python from languages, such as Java, or C++ often stumble upon some of the advanced features in Python. One of them is the static, and another one is the class methods in Python.
Static Methods and Class Methods
Static Methods in Java, are some of the simplest ideas you can think off. You have a class with some methods inside it, if you can call the methods from that class without explicitly creating an instance of the class, then, that method can be classified as static method. In Java, you create a static method by explicitly mentioning the keyword static to decorate the method.
I am not discussing the Java code, but this ought to be elementary for the readers.
In Python, static method is somewhat different. I will try illustrating the same with some simple examples.
Let us first write a simple program, which consists of a class, a method, and a parameter for the method.
>>> class C:
def foo(self, name):
self.name = name
print name
>>> a= C() # instantiates the class
>>> a.foo('Ramdas') # Calls method 'foo' on instance 'a'
>>> Ramdas
This is, indeed, very simple for a Python coder. But for a programmer from the Java, and C++ stables, we need to stress that Python explicitly expects you to declare the instance of the class, as the first parameter of any method called by the instance. This is the reason that you have 'self' in the method foo.
At the same time, if you attempt to call the method from the class itself, you will get an error.
>>> C.foo('Ramdas')
Traceback (most recent call last):
File "<pyshell#67>", line 1, in ?
C.foo('Ramdas')
TypeError: unbound method foo() must be called with C instance as first argument (got str instance instead)
You can work around, and still, call the method from the class with a small tweak.
>>> C.foo(C(), 'Ramdas')
Ramdas
All you did was to follow the error in the previous attempt to call a method, and created an instance of the class as the first parameter.
If you attempt to ignore the ‘self’ clause, you, indeed, get an error.
>>> class B:
def foo(name):
print name
>>> B.foo()
Traceback (most recent call last):
File "<pyshell#65>", line 1, in ?
B.foo()
TypeError: unbound method foo() must be called with B instance as first argument (got nothing instead)
Now, this all is clear. But, with a bit of magic, you can get a static method to work. This is achieved by the decorator, called staticmethod.
>>> class A:
@staticmethod
def foo(name):
print name
>>> A.foo('Ramdas')
Ramdas
The class A is essentially a minor modification of class B, all you did was you added the decorator-- @staticmethod. You can now call a method from the class without instantiating the class.
The decorator is a fairly new phenomenon, and may not work in pre-Python 2.3 series.
Class Methods in Python, is more complex than static methods. In a Python classmethod, the class object that the method is invoked upon is passed as the first parameter to the method. From a 30,000 feet view, classmethods in Python are similar to static methods in Java, but functionally, they can be very different.
Let us take a 30,000 feet view of a classmethod in Python.
Creating a class D, which is inspired from the class A, which we had created earlier.
class D:
@classmethod
def foo(cls,name):
print name
You will note that class D essentially is same as A except for the change in the decorator, and the fact that the class takes the cls as the first argument in the method foo.
Now, we write another example. We create two classes X, and Y with a variable declared inside the class outside methods called _name, whose initial value is 'James'. Class X has a classmethod called foo, class Y has a normal method called foo. The goal of foo is to alter the value of _name with the parameter, which is passed.
class X:
_name = 'James'
@classmethod
def foo(cls, name):
cls._name = name
>>> class Y:
_name ='James'
def foo(self, name):
self._name = name
Now, we will instantiate both classes, and call foo on both, with the parameter 'Bond'.
>>> x=X()
>>> x.foo('Bond')
>>> X._name
'Bond'
>>> y=Y()
>>> y.foo('Bond')
>>> Y._name
'James'
Notice the snippet above, the instance x on the class X has changed the value of the variable _name of class X. However, the variable _name has its value unchanged in case of class Y. This is because, foo was a class method inside class X, and an ordinary instance method in Y.
Now, let us create another class titled Z, where we are calling a staticmethod 'foo', which is similar to that in class X, and Y.
class Z:
_name = 'James'
@staticmethod
def foo(name):
_name = name
>>> z= Z()
>>> z.foo('Bond')
>>> Z._name
'James'
The staticmethod also was unable to change the integrity of the class Z.
I hope the above examples, which are the simplest I could think off, illustrate the power of classmethods in Python. You can use classmethods to change the constructor of a class on the fly.
Meta Classes
The simplest definition of a Meta Class that it is a Super class, whose instances are classes. I have done a lot of Python programming without ever writing, or using a Meta Class. In fact, I know a number of hard core Python programmers, who never had to use a Meta Class programming. But yet, it is an important subject for us to delve into.
>>> def func1 (self,x):
self.x = x
print x
>>> def func2 (self, y):
self.y = y
print y
These are two simple functions, with the argument 'self' as the first paramter. You can use the type function in Python, and create a Metaclass very easily as given below:
>>> E = type('Class',
(object,),
{'f1':func1, 'f2':func2})
>>> e= E()
>>> e.f1(4)
4
>>> e.f2('camel')
camel
>>> type(E)
<type 'type'>
>>> type(e)
<class '__main__.Class'>
Now, what did we do?
We created an object of the type 'type' called E. The built-in 'type' is the most common Meta class; it is the Meta class of all built-in types. Classic classes use a different metaclass: the type known as types. ClassType. So, by passing the methods as a dictionary values, to the class factory function type, we managed to create a Metaclass.
The topic gets even more interesting, as we go even deeper. But that discussion we will have it on another article.
