2013年10月23日星期三

Python的反射和自省

[转自网络]
本文主要介绍python中的反射和自省,以及该机制的简单应用
熟悉JAVA的程序员,一定经常和Class.forName打交道。即使不是经常亲自调用这个方法,但是在很多框架中(Springeclipse plugin机制)都依赖于JAVA的发射和自省能力。而在python中,也同样有着强大的反射和自省能力,本文将做简单的介绍。

首先看一下自省,介绍一下几个重要的函数:
dir函数,传入的参数是对象,返回该对象的所有属性和函数列表:
如:



可以看到,string对象的所有函数,属性都列举出来了。

getattr方法,传入参数是对象和该对象的函数或者属性的名字,返回对象的函数或者属性实例,如下:

 

callable方法,如果传入的参数是可以调用的函数,则返回true,否则返回false



下面这段代码列出对象所有函数:
methodList = [method for method in dir(object) if callable(getattr(object,method))]
比如查看string的所有函数:



接下来,看看python的是如何体现反射的。
globals()
这个函数返回一个map,这个mapkey是全局范围内对象的名字,value是该对象的实例。
在不导入任何module下,执行globals()的结果如下:


在导入sys后,可以发现,globals()返回的map中,多了sys module
 

在导入sgmllib,如下:


如果导入类后,在map中,可以找到类。
 

所以,只要将class的名字最为key,即可得到class。如下:

 
而如果要实例化一个对象,可以如下:


这样,实现了类似java中,Class.forName().newInstance()的功能。但是,在使用globals函数之前,还需要导入相应的类,如果不导入,而直接使用globals[‘...’]查找这个类,则会抛出异常。
所以,我在介绍一种可以动态导入的方法。
首先,介绍一个函数 __import__, 这个函数传入的参数是module的名字,返回这个module,然后,在结合之前介绍过的getattr,于是,我们可以写出下面两句代码,实现对象的自省。



由此可见,python提供的反射和自省机制是十分便捷的。这也方便了很多操作。比如,如下这段代码,将导入脚本文件所在文件夹下的所有测试文件(以test结尾的脚本文件0,并进行测试。



代码出自dive in python(这本书写的很好),比较容易理解,不做详细介绍了。主要是先获得目录,然后过滤出符合条件的脚本文件,去掉后缀名,作为模块加载。

2013年10月14日星期一

Thread in Python 学习笔记

    这段时间做IO的testing,发现如果我主进程P1里启动一个线程T1,T1里popen一个dd的命令,然后P1又继续popen一个sg_reset的命令,有小概率可能P1执行完popen之后会卡住不再继续。kernel的同事说kernel显示都schedule了,那问题可能就出在管道上,log显示的是wait for read。查看了代码说如果popen参数设置了subprocess.PIPE,如果输出太多可能导致卡住。可是我的dd命令是不会有输出的似乎,所以不太像这个原因。试过好种办法,效果都不太好,于是换了multiprocessing来跑dd。虽然效率差了,但是能保证UT的稳定性,也就作罢。现在有时间,研究一下python的thread。

首先把相关的module都列出来:
threading
multiprocessing
subprocess

multiprocessing-with-python-presentation是一个很好的slides对比。

看到了很多例子,由于GIL (global interpreter lock),python thread里是可以用popen的,内核同事说C thread用popen是不对的:threads and fork-think twice before using them


2.5 引入了with statement
pep-343阐述了大概原理。大意是 __enter__, __exit__完成了with的工作
  • The expression is evaluated and should result in an object called a ``context manager''. The context manager must have __enter__() and __exit__() methods.
  • The context manager's __enter__() method is called. The value returned is assigned to VAR. If no 'as VAR' clause is present, the value is simply discarded.
  • The code in BLOCK is executed.
  • If BLOCK raises an exception, the __exit__(typevaluetraceback) is called with the exception details, the same values returned by sys.exc_info(). The method's return value controls whether the exception is re-raised: any false value re-raises the exception, and True will result in suppressing it. You'll only rarely want to suppress the exception, because if you do the author of the code containing the 'with' statement will never realize anything went wrong.
  • If BLOCK didn't raise an exception, the __exit__() method is still called, but typevalue, and traceback are all None.
这里可以看到,不管有没有异常,__exit__会帮们处理好,所以
lock = Threading.Lock()
with lock:
    statements
这样的片段是exception安全的,不会因为异常而没有release锁。

Pool:

Pool是一个进程池,可以指定若干个 worker进程来做事情,也分为sync和async的版本,同时可以获得返回值来做一些同步。需要注意的是,在调用pool.close()之后,pool就结束了,如果不小心把pool.close()放在了一个for循环里,或者在apply()之前调用了,比如
def func(msg):
    for i in xrange(3):
        print "func:"+msg
        time.sleep(1)
    return "hello func %s" % msg

if __name__ == "__main__":
    pool = multiprocessing.Pool(processes=2)
    result = []
    for i in xrange(3):
        msg = "hello %d" %(i)
        result.append(pool.apply_async(func, [msg]))
        pool.close()   <--- done.="" es="" for="" in="" obj.get="" obj="" pool.join="" pre="" print="" result:="" tab="" timeout="1)" ub-process="">
会得到一个断言异常:AssertionError: assert self._state == RUN


正确写法是:
def func(msg):
    for i in xrange(3):
        print "func:"+msg
        time.sleep(1)
    return "hello func %s" % msg

if __name__ == "__main__":
    pool = multiprocessing.Pool(processes=2)
    result = []
    for i in xrange(3):
        msg = "hello %d" %(i)
        result.append(pool.apply_async(func, [msg]))
    pool.close()
    pool.join()
    print "Sub-process(es) done."
    for obj in result:
        print obj.get(timeout=1)

数据访问和共享

Fusion drive + bootmap解决win7安装分区配置

转自网络

自从一个月前在官网订 Mac Mini 时头脑发热选配了 1T Fusion Drive 后, 就一个劲儿的后悔。 Fusion Drive 相当好用,从按下电源键到进入桌面只需要 8 9 秒,开启常用的程序也可以 说是秒开,日常使用几乎听不到 HDD 启动的声音 ……
可惜这么多优点只能在 os X 下实现,用 Boot Camp 助理装 Win7 时就能发现,分区只能放 在 HDD 那部分。也就是说哪怕 os X 只占用了不到 20G 空间,也只能将最多 1T 空间分给 Boot Camp ,最前面的 128G 空间(也就是 SSD 容量)只能是 os X 的。硬着头皮在 HDD 下分区装了 Win7 ,发现使用感觉和 os X 差距过大,干什么都无比缓慢。

于是果断搜帖子,发现了拆分 Fusion Drive 为两块独立硬盘的各种方法,包括官网上的教 程。 可一个一个依次实施后,  发现没一个能真正剥离原配 Fusion Drive 的, 只要安装 os X , 还是自动把两块硬盘合二为一。
折腾了快一个月后, 终于得到高人 Kfram 点拨, 学会了真正拆分原配 Fusion Drive 的方法。 赶紧把整个过程写下来, 一是防着自己以后忘掉, 二是万一有人需要可以参考; 我知道这个 教程含金量极低,希望老鸟勿喷,谢谢。

第一步,在原配 os X 中接入移动硬盘运行 Time Machine 备份一次系统。注意不要把数据 量大的图片、  音乐什么的都备份进去, 只备份基本系统就行了, 占地方的个人数据可以直接 拖进移动硬盘保存的;保证 Time Machine 一次备份的占用空间不超过 20G 就可以了。

第二步,重新开机,在 “ 咣 ” 声后按 option 键,屏幕有反应后选择从移动硬盘(也就是彩色的 那个)启动,随后会进入恢复模式界面。

第三步,在恢复模式主界面中顶栏右起第二个下来菜单中选择启动终端。

第四步,在弹出的终端窗口内直接输入: diskutil cs list ,然后回车;出现一屏内部存储器信 息 。 在 第 三 行 能 看 到 : +--Logical Volume Group XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX X 都是 16 进制字符,统统复制下来 备用。

第 五 步 , 再 次 在 终 端 窗 口 中 输 入 : diskutil cs delete XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX ,这么多个 X 当然就是刚才复制的了, 直接粘贴了事;回车后耐心等待半分钟,原配的 Fusion Drive 就被拆开了。
第六步,最后在终端窗口中输入: exit ,然后回车。终端界面会出现  logout Process completed ] ;完事大吉,关闭终端,回到恢复模式界面。

第七步,最关键的一部,我栽在这里至少 10 天。千万不要进入磁盘工具查看硬盘拆分的如 何,一进去就会被迫按原厂方式修复成一块 Fusion Drive 了。要坚信自己已经拆开了两块 硬盘,直接进入 “ 使用 Time Machine 恢复系统 ” 界面,按步骤一步一步恢复即可,一定要按 容量选好恢复到哪个硬盘哦,小的那个才是 SSD

第八步, Time Machine 恢复完后自动进入 os X 桌面, 进入 Boot Camp 助理, 准备好  Win7 安装镜像文件、 4G 以上的 U 盘,按步骤一步步往下走就 ok 了。关于 Boot Camp 分区,我 是把 SSD 对等分成了两个,一边 60G

第九步, 如果内存很大的话, 记得装好 Win7 后删除休眠文件和页面文件,  本来就只有 60G 的空间,这俩完全没用的文件就占了 32G 怎么行啊。

行了,完美的双系统终于在 Fusion Drive 上实现了。还剩下 1T HDD ,我格成了 HFS 系 统, 因为主力还是要用 os X 嘛, 个人数据都放在 HDD  上; 个别应用需要在 Win7 下完成的, 切换启动只需半分钟不到,就能进入 Win7 桌面了。拜 Boot Camp 支撑包所赐, Win7 下也 可以读取 HDD 中的信息,不过也只能读了。如果 os X Windows 都要经常使用的话,可 以考虑把 HDD 分成两个区, HFS NTFS 各整一个。

我现在的存储架构是:所有的文件都放进一个 USB3.0 外置的 Raid10 里, 4 2T 西数绿 盘组成了 4T 容量,安全又高速。近期常用的文件复制进 Mac Mini 内置的 HDD 中,方便随 时调用。 ( 其实调用 Raid10 中的文件比调用内置 HDD 快了一倍不止, 可惜 Raid10 有点吵, 大半夜开久了听着有些头疼。 )另外还有一块西数 2.5 寸的 2T 移动硬盘,好处是不需要电 源线,一根 USB3.0 就够了;分了 HFS NTFS 两个区,分别做为两个系统的备份盘。
之前一直特别后悔选了 Fusion Drive 没选 256SSD ,现在感觉好多了,至少拆完后两个系 统都是飞速,还多了一个内置的存贮盘,偶尔拿着饭盒出门还是要比只内置 SSD 的方便一 点。

还有, 如果有一天, 彻底投入了 os X 的怀抱, 再也不打算用 Windows 了, 如何恢复 Fusion Drive 呢。非常简单,还是进入恢复模式界面,进入磁盘工具,一切就自动整合了,然后再 用 Time Machine 恢复一下系统,完全搞定。

Python *args and **kargs

关于*args和**kargs的区别和用法,这段代码足够解释一切了。*args是单个不定参数,**kargs是k-v的不定参数
def any_function(required_arg, *args, **kwargs):
    print required_arg
 
    # args will be a list of positional arguments
    # because it has * before it
    if args: # If there is anything in args
        print args
 
    # kwargs will be a dictionary of keyword arguments,
    # because it has ** before it
    if kwargs: # If there is anything in kwargs
        print kwargs
 
any_function("Required Argument.")
any_function("Required Argument", 1, 2, "pos3")
any_function("Required Argument", (1, 2), "pos3", keyword1=5, keyword2="spam")
输出:
Required Argument.
Required Argument
(1, 2, 'pos3')
Required Argument
((1, 2), 'pos3')
{'keyword2': 'spam', 'keyword1': 5}

Abstract Class

Classes as objects

Before understanding metaclasses, you need to master classes in Python. And Python has a very peculiar idea of what classes are, borrowed from the Smalltalk language.
In most languages, classes are just pieces of code that describe how to produce an object. That's kinda true in Python too:
  >>> class ObjectCreator(object):
  ...       pass
  ... 

  >>> my_object = ObjectCreator()
  >>> print(my_object)
  <__main__.ObjectCreator object at 0x8974f2c>
But classes are more than that in Python. Classes are objects too.
Yes, objects.
As soon as you use the keyword class, Python executes it and creates an OBJECT. The instruction
  >>> class ObjectCreator(object):
  ...       pass
  ... 
creates in memory an object with the name ObjectCreator.
This object (the class) is itself capable of creating objects (the instances), and this is why it's a class.
But still, it's an object, and therefore:
  • you can assign it to a variable
  • you can copy it
  • you can add attributes to it
  • you can pass it as a function parameter
e.g.:
  >>> print(ObjectCreator) # you can print a class because it's an object
  <class '__main__.ObjectCreator'>
  >>> def echo(o):
  ...       print(o)
  ... 
  >>> echo(ObjectCreator) # you can pass a class as a parameter
  <class '__main__.ObjectCreator'>
  >>> print(hasattr(ObjectCreator, 'new_attribute'))
  False
  >>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class
  >>> print(hasattr(ObjectCreator, 'new_attribute'))
  True
  >>> print(ObjectCreator.new_attribute)
  foo
  >>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable
  >>> print(ObjectCreatorMirror.new_attribute)
  foo
  >>> print(ObjectCreatorMirror())
  <__main__.ObjectCreator object at 0x8997b4c>

Creating classes dynamically

Since classes are objects, you can create them on the fly, like any object.
First, you can create a class in a function using class:
  >>> def choose_class(name):
  ...     if name == 'foo':
  ...         class Foo(object):
  ...             pass
  ...         return Foo # return the class, not an instance
  ...     else:
  ...         class Bar(object):
  ...             pass
  ...         return Bar
  ...     
  >>> MyClass = choose_class('foo') 
  >>> print(MyClass) # the function returns a class, not an instance
  <class '__main__.Foo'>
  >>> print(MyClass()) # you can create an object from this class
  <__main__.Foo object at 0x89c6d4c>
But it's not so dynamic, since you still have to write the whole class yourself.
Since classes are objects, they must be generated by something.
When you use the class keyword, Python creates this object automatically. But as with most things in Python, it gives you a way to do it manually.
Remember the function type? The good old function that lets you know what type an object is:
>>> print(type(1))
<type 'int'>
>>> print(type("1"))
<type 'str'>
>>> print(type(ObjectCreator))
<type 'type'>
>>> print(type(ObjectCreator()))
<class '__main__.ObjectCreator'>
Well, type has a completely different ability, it can also create classes on the fly. typecan take the description of a class as parameters, and return a class.
(I know, it's silly that the same function can have two completely different uses according to the parameters you pass to it. It's an issue due to backwards compatibility in Python)
type works this way:
  type(name of the class, 
       tuple of the parent class (for inheritance, can be empty), 
       dictionary containing attributes names and values)
e.g.:
>>> class MyShinyClass(object):
...       pass
can be created manually this way:
  >>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
  >>> print(MyShinyClass)
  <class '__main__.MyShinyClass'>
  >>> print(MyShinyClass()) # create an instance with the class
  <__main__.MyShinyClass object at 0x8997cec>
You'll notice that we use "MyShinyClass" as the name of the class and as the variable to hold the class reference. They can be different, but there is no reason to complicate things.
type accepts a dictionary to define the attributes of the class. So:
>>> class Foo(object):
...       bar = True
Can be translated to:
  >>> Foo = type('Foo', (), {'bar':True})
And used as a normal class:
  >>> print(Foo)
  <class '__main__.Foo'>
  >>> print(Foo.bar)
  True
  >>> f = Foo()
  >>> print(f)
  <__main__.Foo object at 0x8a9b84c>
  >>> print(f.bar)
  True
And of course, you can inherit from it, so:
  >>>   class FooChild(Foo):
  ...         pass
would be:
  >>> FooChild = type('FooChild', (Foo,), {})
  >>> print(FooChild)
  <class '__main__.FooChild'>
  >>> print(FooChild.bar) # bar is inherited from Foo
  True
Eventually you'll want to add methods to your class. Just define a function with the proper signature and assign it as an attribute.
>>> def echo_bar(self):
...       print(self.bar)
... 
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True
You see where we are going: in Python, classes are objects, and you can create a class on the fly, dynamically.
This is what Python does when you use the keyword class, and it does so by using a metaclass.

What are metaclasses (finally)

Metaclasses are the 'stuff' that creates classes.
You define classes in order to create objects, right?
But we learned that Python classes are objects.
Well, metaclasses are what create these objects. They are the classes' classes, you can picture them this way:
  MyClass = MetaClass()
  MyObject = MyClass()
You've seen that type lets you do something like this:
  MyClass = type('MyClass', (), {})
It's because the function type is in fact a metaclass. type is the metaclass Python uses to create all classes behind the scenes.
Now you wonder why the heck is it written in lowercase, and not Type?
Well, I guess it's a matter of consistency with str, the class that creates strings objects, and int the class that creates integer objects. type is just the class that creates class objects.
You see that by checking the __class__ attribute.
Everything, and I mean everything, is an object in Python. That includes ints, strings, functions and classes. All of them are objects. And all of them have been created from a class:
  >>> age = 35
  >>> age.__class__
  <type 'int'>
  >>> name = 'bob'
  >>> name.__class__
  <type 'str'>
  >>> def foo(): pass
  >>> foo.__class__
  <type 'function'>
  >>> class Bar(object): pass
  >>> b = Bar()
  >>> b.__class__
  <class '__main__.Bar'>
Now, what is the __class__ of any __class__ ?
  >>> age.__class__.__class__
  <type 'type'>
  >>> name.__class__.__class__
  <type 'type'>
  >>> foo.__class__.__class__
  <type 'type'>
  >>> b.__class__.__class__
  <type 'type'>
So, a metaclass is just the stuff that creates class objects.
You can call it a 'class factory' if you wish.
type is the built-in metaclass Python uses, but of course, you can create your own metaclass.

The __metaclass__ attribute

You can add a __metaclass__ attribute when you write a class:
class Foo(object):
  __metaclass__ = something...
  [...]
If you do so, Python will use the metaclass to create the class Foo.
Careful, it's tricky.
You write class Foo(object) first, but the class object Foo is not created in memory yet.
Python will look for __metaclass__ in the class definition. If it finds it, it will use it to create the object class Foo. If it doesn't, it will use type to create the class.
Read that several times.
When you do:
class Foo(Bar):
  pass
Python does the following:
Is there a __metaclass__ attribute in Foo?
If yes, create in memory a class object (I said a class object, stay with me here), with the name Foo by using what is in __metaclass__.
If Python can't find __metaclass__, it will look for a __metaclass__ in Bar (the parent class), and try to do the same.
If Python can't find __metaclass__ in any parent, it will look for a __metaclass__ at the MODULE level, and try to do the same.
Then if it can't find any __metaclass__ at all, it will use type to create the class object.
Now the big question is, what can you put in __metaclass__ ?
The answer is: something that can create a class.
And what can create a class? type, or anything that subclasses or uses it.

Custom metaclasses

The main purpose of a metaclass is to change the class automatically, when it's created.
You usually do this for APIs, where you want to create classes matching the current context.
Imagine a stupid example, where you decide that all classes in your module should have their attributes written in uppercase. There are several ways to do this, but one way is to set __metaclass__ at the module level.
This way, all classes of this module will be created using this metaclass, and we just have to tell the metaclass to turn all attributes to uppercase.
Luckily, __metaclass__ can actually be any callable, it doesn't need to be a formal class (I know, something with 'class' in its name doesn't need to be a class, go figure... but it's helpful).
So we will start with a simple example, by using a function.
# the metaclass will automatically get passed the same argument
# that you usually pass to `type`
def upper_attr(future_class_name, future_class_parents, future_class_attr):
  """
    Return a class object, with the list of its attribute turned 
    into uppercase.
  """

  # pick up any attribute that doesn't start with '__' and uppercase it
  uppercase_attr = {}
  for name, val in future_class_attr.items():
      if not name.startswith('__'):
          uppercase_attr[name.upper()] = val
      else:
          uppercase_attr[name] = val

  # let `type` do the class creation
  return type(future_class_name, future_class_parents, uppercase_attr)

__metaclass__ = upper_attr # this will affect all classes in the module

class Foo(): # global __metaclass__ won't work with "object" though
  # but we can define __metaclass__ here instead to affect only this class
  # and this will work with "object" children
  bar = 'bip'

print(hasattr(Foo, 'bar'))
# Out: False
print(hasattr(Foo, 'BAR'))
# Out: True

f = Foo()
print(f.BAR)
# Out: 'bip'
Now, let's do exactly the same, but using a real class for a metaclass:
# remember that `type` is actually a class like `str` and `int`
# so you can inherit from it
class UpperAttrMetaclass(type): 
    # __new__ is the method called before __init__
    # it's the method that creates the object and returns it
    # while __init__ just initializes the object passed as parameter
    # you rarely use __new__, except when you want to control how the object
    # is created.
    # here the created object is the class, and we want to customize it
    # so we override __new__
    # you can do some stuff in __init__ too if you wish
    # some advanced use involves overriding __call__ as well, but we won't
    # see this
    def __new__(upperattr_metaclass, future_class_name, 
                future_class_parents, future_class_attr):

        uppercase_attr = {}
        for name, val in future_class_attr.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return type(future_class_name, future_class_parents, uppercase_attr)
But this is not really OOP. We call type directly and we don't override call the parent__new__. Let's do it:
class UpperAttrMetaclass(type): 

    def __new__(upperattr_metaclass, future_class_name, 
                future_class_parents, future_class_attr):

        uppercase_attr = {}
        for name, val in future_class_attr.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        # reuse the type.__new__ method
        # this is basic OOP, nothing magic in there
        return type.__new__(upperattr_metaclass, future_class_name, 
                            future_class_parents, uppercase_attr)
You may have noticed the extra argument upperattr_metaclass. There is nothing special about it: a method always receives the current instance as first parameter. Just like you have self for ordinary methods.
Of course, the names I used here are long for the sake of clarity, but like for self, all the arguments have conventional names. So a real production metaclass would look like this:
class UpperAttrMetaclass(type): 

    def __new__(cls, clsname, bases, dct):

        uppercase_attr = {}
        for name, val in dct.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return type.__new__(cls, clsname, bases, uppercase_attr)
We can make it even cleaner by using super, which will ease inheritance (because yes, you can have metaclasses, inheriting from metaclasses, inheriting from type):
class UpperAttrMetaclass(type): 

    def __new__(cls, clsname, bases, dct):

        uppercase_attr = {}
        for name, val in dct.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr)
That's it. There is really nothing more about metaclasses.
The reason behind the complexity of the code using metaclasses is not because of metaclasses, it's because you usually use metaclasses to do twisted stuff relying on introspection, manipulating inheritance, vars such as __dict__, etc.
Indeed, metaclasses are especially useful to do black magic, and therefore complicated stuff. But by themselves, they are simple:
  • intercept a class creation
  • modify the class
  • return the modified class

Why would you use metaclasses classes instead of functions?

Since __metaclass__ can accept any callable, why would you use a class since it's obviously more complicated?
There are several reasons to do so:
  • The intention is clear. When you read UpperAttrMetaclass(type), you know what's going to follow
  • You can use OOP. Metaclass can inherit from metaclass, override parent methods. Metaclasses can even use metaclasses.
  • You can structure your code better. You never use metaclasses for something as trivial as the above example. It's usually for something complicated. Having the ability to make several methods and group them in one class is very useful to make the code easier to read.
  • You can hook on __new____init__ and __call__. Which will allow you to do different stuff. Even if usually you can do it all in __new__, some people are just more comfortable using __init__.
  • These are called metaclasses, damn it! It must mean something!

Why the hell would you use metaclasses?

Now the big question. Why would you use some obscure error prone feature?
Well, usually you don't:
Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why).
Python Guru Tim Peters
The main use case for a metaclass is creating an API. A typical example of this is the Django ORM.
It allows you to define something like this:
  class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()
But if you do this:
  guy = Person(name='bob', age='35')
  print(guy.age)
It won't return an IntegerField object. It will return an int, and can even take it directly from the database.
This is possible because models.Model defines __metaclass__ and it uses some magic that will turn the Person you just defined with simple statements into a complex hook to a database field.
Django makes something complex look simple by exposing a simple API and using metaclasses, recreating code from this API to do the real job behind the scenes.

The last word

First, you know that classes are objects that can create instances.
Well in fact, classes are themselves instances. Of metaclasses.
  >>> class Foo(object): pass
  >>> id(Foo)
  142630324
Everything is an object in Python, and they are all either instances of classes or instances of metaclasses.
Except for type.
type is actually its own metaclass. This is not something you could reproduce in pure Python, and is done by cheating a little bit at the implementation level.
Secondly, metaclasses are complicated. You may not want to use them for very simple class alterations. You can change classes by using two different techniques:
  • monkey patching
  • class decorators
99% of the time you need class alteration, you are better off using these.
But 99% of the time, you don't need class alteration at all :-)