Quantcast
Channel: CodeSection,代码区,Python开发技术文章_教程 - CodeSec
Viewing all articles
Browse latest Browse all 9596

Lintel Technologies: Python metaclasses explained

$
0
0

python is having obscure wonderfulmechanism of classes and it’s implementation. In python every thing is an object. If you define a class, that class it self is an object in memory and it is an instance of other class . You may call it as a class object. If you instantiate it you will get brand new object called instance( instance of class).

Probably, meta classes are sort of confusing concept. Many people are afraid of this concept, but believe me it is very nice and simple if you understand it.

In simple words, meta classes are classes which are responsible to create a class object( in memory) .

As mentioned above, when you define a class. A class object will be created in memory but behind the senses it is an instance of other class by default type. So, classes are created by meta classes. You can specify your custom meta class which is responsible to create a class.

Mostly, meta classes are used when you write APIs or frameworks. Like django uses metaclasses in models.


Lintel Technologies: Python metaclasses explained
Meta Classes

I would like to explain this concept by taking real world example, to get you good understanding. Let’s take a look at following picture.


Lintel Technologies: Python metaclasses explained
Python MetaClasses Illustrated

As show in picture, A factory can be treated a metaclass. Where, it producesvending machine, can be considered as a class. Where, the class (vending machine) produces instances, which are cans, bottles etc.

An example representing normal class definition and instance creation

>>> class Foo(object): ...a = 3 ... >>> >>> Foo <class '__main__.Foo'> >>> >>> i = Foo() >>> i <__main__.Fooobject at 0x110126910> >>> >>> isinstance(i, Foo) True >>> isinstance(Foo, type) True

Python is having builtin function called isinstance. Using this function we can determine if any object is an instance of specified object.

In the aboveexamplewe haven’t specifiedthe metaclass. So, python would use default one. i.e type.

In python 2, we specify metaclass using magic method __metaclass__.

__metaclass__ can be specified either as a class attribute or global variable. When you specify it globally in module level, all classes will become instances of this metaclass. If you specify this as a class attribute, only that class will become instance of specified metaclass. In python3 this__meatclass__ attribute is removed in favour of using metaclass argument that you have to specify in class definition.

Implementation of simpleclass with metaclass in place

>>> class MetaClass(type): ...pass ... >>> >>> class Foo(object): ...__metaclass__ = MetaClass ...pass ... >>> >>> i = Foo() >>> >>> isinstance(i, Foo) True >>> isinstance(Foo, MetaClass) True >>> isinstance(MetaClass, type) True >>>

Here in this example, you can see class Foo is the instance of metaclass MetaClass . Thus, Foo gets created as an instance of MetaClass. And, i is an instance of class Foo. As you can see, we confirmed this relation using isinstance function.


Lintel Technologies: Python metaclasses explained
Python metaclasses instance, class and metaclass

There is no restriction over how many times one class can be used as a metaclass for other classes.

>>> class MetaClass(type): ...pass ... >>> >>> class Foo(object): ...__metaclass__ = MetaClass ... >>> >>> class Bar(object): ...__metaclass__ = MetaClass ... >>> >>> >>> i = Foo() >>> j = Bar() >>> >>> isinstance(i, Foo) True >>> isinstance(j, Bar) True >>> isinstance(Foo, MetaClass) True >>> isinstance(Bar, MetaClass) True >>>

In the above example, the meta class MetaCalss is used in both Foo and Bar classes. Like wise you can use it in as many classes you want. If you want to apply it for all module level classes. You better use global __metaclass__ attribute. As you can see in the following example

""" This is a simple module to demostrate global __metaclass__ attribute """ class MetaClass(type): pass __metaclass__ = MetaClass# This will affect all class in module class Foo(): pass class Bar(): pass class NewStyleClass(object): pass print "is instance of Foo: MetaClass:: %s" % isinstance(Foo, MetaClass) print "is instance of Bar: MetaClass:: %s" % isinstance(Bar, MetaClass) print print "is instance of NewStyleClass: MetaClass:: %s" % isinstance(NewStyleClass, MetaClass) OutPut: pythonglobal_metaclass.py is instanceofFoo: MetaClass:: True is instanceofBar: MetaClass:: True is instanceofNewStyleClass: MetaClass:: False

This module level __metaclass__ magic variable doesn’t work on new style classes as show in above code.

Python Metaclasses Key Notes Metaclasses are callables Subclasses inherit the metaclass Restriction over multiple metaclasses inmultiple inheritance MetaClasses are callable

The MetaClass always need not be a class. You can use any callable as a metaclass. A Simple example demonstrates using callable (function) as a metaclass

>>> def metaClass(name, bases, d): ...print "CreatingClass %s" % name ...c = type(name, bases, d) ...return c ... >>> >>> >>> class Foo(object): ...pass ... >>> >>> class Foo(object): ...__metaclass__ = metaClass ... CreatingClass Foo >>> >>> class Bar(object): ...__metaclass__ = metaClass ... CreatingClass Bar >>> >>> Foo <class '__main__.Foo'> >>> Bar <class '__main__.Bar'> >>>

If you are using callable as ametaclass class. It should have same signature(arguments) as type. That is,

type(nameoftheclass, tupleoftheparent class (for inheritance, canbeempty), dictionarycontainingattributesnamesand values)

Following example is useless but explanatory. You can hack the class creation using metaclass. You can see below example, Foo became 3 instead of class object as we did return 3 from metaclass.

>>> def makeClass(name, bases, d): ...print name, bases, d ...return 3 ... >>> >>> class Foo(object): ...__metaclass__ = makeClass ... ... >>> >>> Foo 3 Subclasses inherit the metaclass

Like all other attributes and methods subclasses inherit metaclass.

class M1(type): def __new__(meta, name, bases, atts): print "Meta Class M1 called for class " + name return super(M1, meta).__new__(meta, name, bases, atts) class Base(object): __metaclass__ = M1 class Sub(Base): pass OutPut: pythonmetaclass_inheritance.py MetaClass M1calledfor class Base MetaClass M1calledfor class Sub #TODO Restriction over multiple metaclasses in inheritance Classes can have multiple base classes. Those maetaclasses may have different metaclass. If s

Viewing all articles
Browse latest Browse all 9596

Trending Articles