元类

什么是元类

元类就是用类创建类的东西,元类是类的类。type就是python在背后用来创建所有类的元类。

  • __metaclass__属性
    python会在内存中通过__metaclass__创建一个名字为XXX的类对象。如果Python没找到__metaclass__,它会继续在父类中寻找__metaclass__属性,并尝试做和前面同样的操作。如果python在任何父类中都找不到__metaclass__,它就会在模块层中找__metaclass__,并尝试做同样的操作。如果还是找不到__metaclass__,python就会用内建的type来创建这个类对象。

    现在的问题是,你可以在__metaclass__中放置什么代码呢?
    答案:可以创建一个类的东西。那么什么可以用来创建一个类呢?type, 或者是任何使用到type或者子类化type的东旭都可以。

type动态的创建类

  • 语法:
    type(类名, 父类元组(针对继承的情况,可以为空), 包含属性的字典(名称和值))
  • 例如:
    • 无参数
    >>> class MyShinyClass(object):
            pass
    
    上面这段代码可以改写为:
    >>> MyShinyClass = type('MyShinyClass', (), {})
    >>> print MyShinyClass
    <class '__main__.MyShinyClass'>
    >>> print MyShinyClass()
    <__main__.MyShinyClass object at 0x878688>
    
    • 带参数
      type 接受一个字典来为类定义属性,因此
    >>> class Foo(object):
            bar =  True
    
    上面这段代码可以改写为:
    >>> Foo = type('Foo', (), {"bar": True})
    
    • 继承
    >>> class FooChild(Foo):
            pass
    
    上面这段代码可以改写为:
    >>> FooChild = type('FooChild', (Foo, ), {})
    
    • 类增加方法
    >>> def echo_bar(self):
            print self.bar
    >>> FooChild = type("FooChild", (Foo, ), {'echo_bar': echo_bar})
    

自定义元类

元类的主要目的就是为了当创建类时能够自动地改变类。通常,你会为API做这样的事情,你希望可以创建符合当前上下文的类。

  • 示例
    • 函数创建类
        def upper_attr(future_class_name,future_class_parents,future_class_attr):
            attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
            uppercase_attr = dict((name.upper(), value) for name, value in attrs)
            return type(future_class_name, future_class_parents, uppercase_attr)
    
        class Foo(object):
            __metaclass__ = upper_attr
            bar = 'bip'
    
    • 类创建类
        class UpperAttrMetaClass(type):
            def __new__(cls, future_class_name, future_class_parents, future_class_attr):
                attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
                uppercase_attr = dict((name.upper(), value) for name, value in attrs)
                return type(future_class_name, future_class_parents, uppercase_attr)
    
        class UpperAttrMetaclass(type):
            def __new__(cls, future_class_name, future_class_parents, future_class_attr):
                attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
                uppercase_attr = dict((name.upper(), value) for name, value in attrs)
                return type.__new__(cls, future_class_name, future_class_parents, uppercase_attr)
    
        class Foo(object):
            __metaclass__ = UpperAttrMetaClass  
            bar = 'bip'
    
        print hasattr(Foo, 'bar')
    
        print hasattr(Foo, 'BAR')
    
        f = Foo()
        print f.BAR
    

为什么要用metaclass类而不是函数?

由于metaclass可以接受任何可调用的对象,那为何还要使用类呢,因为很显然使用类会更加复杂,原因:

  • 意图更加清晰
  • 你可以使用oop编程,元类可以从元类中继承而来,改写父类的方法。元类甚至可以使用元类。
  • 可以把代码组织的更好。将多个方法归总到一个类中会很有帮助,会使你的代码更容易阅读。
  • 可以使用__new__, __init__以及__call__这样的特殊方法。它们能帮你处理不同的任务。

究竟为什么要使用元类

元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清除究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清除地知道他们需要什么,而且根本不需要解释为什么要用元类。 ------Python界的领袖 Tim Peters

  • 元类的主要用途是创建API。一个典型的例子是Django ORM。它允许你像这样定义:
    class Person(models.Model):
        name = models.CharField(max_length=30)
        age = models.IntegerField()
    
posted @ 2017-05-04 17:42  zane_zong  阅读(99)  评论(0编辑  收藏  举报