zoukankan      html  css  js  c++  java
  • Python之元类

    类型对象负责创建对象实例,控制对象行为。那么类型对象又由谁来创建呢?

    元类(metaclass)——类型的类型

    New-Style Class的默认类型是type

    >>> class Data(object):
    ...     pass
    ... 
    >>> 
    >>> Data.__class__
    <type 'type'>
    >>> 
    >>> type.__class__
    <type 'type'>

    #最终的类型是type,包括type自己

    关键字class会被编译成元类创建类型对象指令

    >>> Data = type("Data",(object),{"x":1})
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: type() argument 2 must be tuple, not type
    >>> Data = type("Data",(object,),{"x":1})#class的实际行为
    >>> 
    >>> Data.x
    1
    >>> Data.__class__
    <type 'type'>
    >>> 
    >>> Data.__base__
    <type 'object'>
    class type(object)
     |  type(object) -> the object's type
     |  type(name, bases, dict) -> a new type

    正因为class和def一样是指令,可以在任何地方创建类型对象。

    >>> def test():
    ...     class Data(object):pass
    ...     return Data
    ... 
    >>> 
    >>> Data = test()
    >>> 
    >>> Data.__name__
    'Data'
    >>> 
    >>> type(Data)
    <type 'type'>
    >>> 
    >>> Data()
    <__main__.Data object at 0x7f822e1d2490>

    元类、类型以及实例的创建顺序:

    class = metaclass(....) #元类创建类型
    instance = class(...)   #类型创建实例
    
    instance.__class__ is class #实例的类型
    class.__class__ is metaclass #类型的类型

    __metaclass__

    除了使用默认元类type以外,还可以用__metaclass__属性指定自定义元类,以便对类型对象创建过程进行干预。

    #!/usr/bin/env python26
    #-*- coding:utf-8 -*-
    
    class InjectMeta(type):
            def __new__(cls,name,bases,attrs):
                    t = type.__new__(cls,name,bases,attrs)
    
                    def print_id(self):print hex(id(self))
    
                    t.print_id = print_id #为类型对象添加实例方法
                    t.s = "Hello,world!" #添加静态字段
    
                    return t
    
    class Data(object):
            __metaclass__ = InjectMeta #显示指定元类
    
    print Data.__metaclass__
    print Data.__class__
    print Data.s
    
    print dir(Data)
    
    Data().print_id()

    输出:

    <class '__main__.InjectMeta'>
    <class '__main__.InjectMeta'>
    Hello,world!
    ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__metaclass__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'print_id', 's']
    0x7f3687df7250

    自定义元类通常都从type继承,习惯以Meta结尾。和继承有点类似。

    只需注意__new和__init__方法参数的区别:

    http://www.cnblogs.com/gsblog/p/3368304.html

    当解释器创建类型对象时,会按以下顺序查找__metaclass__属性:

    class.__metaclass__->bases.__metaclass__->module.__metaclass__->type

     magic

    对象行为由类型决定。实例不过存储状态数据。控制类型对象的创建,也就意味着可以让对象的实际行为和代码存在极大的差异。这是魔法的力量。

    静态类(static class):不允许创建实例。通常作为工具类(Utility)存在

    [root@typhoeus79 20131014]# more static_class.py
    #!/usr/bin/env python26
    #-*- coding:utf-8 -*-
    
    class StaticClassMeta(type):
            def __new__(cls,name,bases,attr):
                    t = type.__new__(cls,name,bases,attr)
    
                    def ctor(cls,*args,**kwargs):
                            raise RuntimeError("Cannot be created a instance of the static class!")
                    t.__new__ = staticmethod(ctor)
    
                    return t
    class Data(object):
            __metaclass__ = StaticClassMeta
    
    Data()
    [root@typhoeus79 20131014]# ./static_class.py   
    Traceback (most recent call last):
      File "./static_class.py", line 16, in <module>
        Data()
      File "./static_class.py", line 9, in ctor
        raise RuntimeError("Cannot be created a instance of the static class!")
    RuntimeError: Cannot be created a instance of the static class!

    密封类(sealed class):禁止被继承

    >>> class SealedClassMeta(type):
    ...     _types = set()
    ...     def __init__(cls,name,bases,attrs):
    ...             if cls._types & set(bases):
    ...                     raise SyntaxError("Cannot inherit from a sealed class!")
    ...             cls._types.add(cls)
    ... 
    >>> 
    >>> class A(object):                    
    ...     __metaclass__ = SealedClassMeta
    ... 
    >>> class B(A):pass
    ... 
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 5, in __init__
    SyntaxError: Cannot inherit from a sealed class!
  • 相关阅读:
    页面后退的总结
    Flash Builder4.6 无法启动,并且报 Failed to create the Java Virtual Machine(1不行的话可以参考下2)
    单独的js代码文件被JSP文件调用,中文乱码问题
    Flash Builder4.6 破解方法的实践
    sql文学习.....关于条件判断的查询....casewhenthen
    解决flash builder 4.6安装过程中安装程序遇到错误(1)
    flex builder 4 控制台不能输出trace()的解决方法
    jstl遍历map,foreach
    jar包直接拷贝到WEBINF/lib下和以userLibrary形式引入的区别?/jar包放置在WEBINF/lib下和通过build path导入的区别是什么?
    flash build 4.6 不能debug 报错 C:\WINDOWS\system32\Macromed\Flash\NPSWF32.dll
  • 原文地址:https://www.cnblogs.com/gsblog/p/3368335.html
Copyright © 2011-2022 走看看