1.使用 type 动态创建类(type 是一个类, 用来创建类对象的元类, 所以也可以继承)

type("Person", (), {"name": "John"})

2.元类

  Python 中类也是对象, 元类就是创建这些类对象的类, 可以理解为

MyClass = MetaClass()
MyObject = MyClass()

3.type实际上是一个元类, type就是Python在背后用来创建所有类的元类, 类似 str 是创建字符串对象的类, int 是创建整数的类, type 就是创建类的类

4.Python 中所有东西都是对象!

>>> 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'>

  那么对于任何一个 __class__ 的 __class__ 属性又是什么呢?

>>> a.__class__.__class__
<type 'type'>
>>> age.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>

  结论: 元类就是创建类这种对象的东西, type就是Python的内建元类(xx.__class__.__class__为 type )

5.__metaclass__ 属性

  可以在写一个类的时候为其添加 __metaclass__ 属性

class Foo(object):
__metaclass__ = something…
  pass

  如果你这么做了, Python就会用元类来创建类Foo, 小心点, 这里面有些技巧, 你首先写下class Foo(object), 但是类对象Foo还没有在内存中创建, Python会在类的定义中寻找__metaclass__属性, 如果找到 了, Python就会用它来创建类Foo, 如果没有找到, 就会用内建的type来创建这个类

6.深入理解下上一步中的 __metaclass__

class Foo(Bar):
pass

  Foo中有__metaclass__这个属性吗?如果是, Python会在内存中通过__metaclass__创建一个名字为Foo的类对象(我说的是类对象, 请紧跟我的思路), 如果Python没有找到__metaclass__, 它会继续在Bar(父类)中寻找__metaclass__ 属性, 并尝试做和前面同样的操作, 如果Python在任何父类中都找不到__metaclass__, 它就会在模块层次中去寻找 __metaclass__, 并尝试做同样的操作, 如果还是找不到__metaclass__, Python就会用内置的type来创建这个类对象

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

7.自定义元类

  条件:模块里所有的类的属性都应该是大写形式

  实现(__metaclass__实际上可以被任意调用, 它并不需要一定是一个正式的类):

# 元类会自动将你通常传给‘type’的参数作为自己的参数传入
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) # 通过'type'来做类对象的创建
return type(future_class_name, future_class_parents, uppercase_attr) __metaclass__ = upper_attr # 这会作用到这个模块中的所有类 class Foo(object):
# 我们也可以只在这里定义__metaclass__,这样就只会作用于这个类中
bar = 'bip' print hasattr(Foo, 'bar')
# 输出: False
print hasattr(Foo, 'BAR')
# 输出:True f = Foo()
print f.BAR
# 输出:'bip'

  用OOP实现:

# 请记住,'type'实际上是一个类,就像'str'和'int'一样
# 所以,你可以从type继承
class UpperAttrMetaClass(type):
# __new__ 是在__init__之前被调用的特殊方法
# __new__是用来创建对象并返回之的方法
# 而__init__只是用来将传入的参数初始化给对象
# 你很少用到__new__,除非你希望能够控制对象的创建
# 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
# 如果你希望的话,你也可以在__init__中做些事情
# 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
def __new__(upperattr_metaclass, 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)

8.为什么要使用元类?

  现在回到我们的大主题上来, 究竟是为什么你会去使用这样一种容易出错且晦涩的特性?好吧, 一般来说, 你根本就用不上它:

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

元类的主要用途是创建API, 一个典型的例子是Django ORM, 它允许你像这样定义:

class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()

但是如果你像这样做的话:

guy  = Person(name='bob', age='')
print guy.age

这并不会返回一个IntegerField对象, 而是会返回一个int, 甚至可以直接从数据库中取出数据, 这是有可能的, 因为 models.Model定义了__metaclass__, 并且使用了一些魔法能够将你刚刚定义的简单的Person类转变成对数据库的一个复杂hook, Django框架将这些看起来很复杂的东西通过暴露出一个简单的使用元类的API将其化简, 通过这个API重新创建代码, 在背后完成真正的工作

9.小结

  Python中的一切都是对象, 它们要么是类的实例, 要么是元类的实例, 除了type, type实际上是它自己的元类

摘抄自:http://python.jobbole.com/21351/

Python-深入理解元类(metaclass)的更多相关文章

  1. [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式

    使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...

  2. Python中的元类(metaclass)

    推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...

  3. 深刻理解Python中的元类metaclass(转)

    本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热 ...

  4. 深刻理解Python中的元类(metaclass)

    译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...

  5. [转] 深刻理解Python中的元类(metaclass)

    非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...

  6. 深刻理解Python中的元类(metaclass)【转】

    译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...

  7. 深刻理解Python中的元类(metaclass)以及元类实现单例模式

    在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...

  8. 深入理解Python中的元类(metaclass)

    原文 译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍 ...

  9. python——深刻理解Python中的元类(metaclass)

    译注:这是一篇在Stack overflow上 很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉 ...

  10. python中的元类metaclass

    本文是一个转载的,因为原文写的太好了,所以直接copy过来吧. 原文请看:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上 很热的帖子.提问 ...

随机推荐

  1. 【Kruskal】舒适的路线

    [codevs1001]舒适的路线 题目描述 Description Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光.Z小镇附近共有N(1<N≤500)个景点(编号为1,2,3,… ...

  2. BZOJ 1109 [POI2007]堆积木Klo(树状数组)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1109 [题目大意] Mary在她的生日礼物中有一些积木.那些积木都是相同大小的立方体. ...

  3. 【多重背包】CDOJ1691 这是一道比CCCC简单题经典的中档题

    #include<cstdio> #include<algorithm> using namespace std; int n,V,w[110],c[110],a[110],f ...

  4. 【DFS】POJ3009-Curling 2.0

    [题目大意] 给出一张地图,一旦往一个方向前进就必须一直向前,直到一下情况发生:(1)碰到了block,则停在block前,该block消失:(2)冲出了场地外:(3)到达了终点.改变方向十次以上或者 ...

  5. 泛型类Bag

    课堂练习--泛型类Bag 要求: 0.代码运行在命令行中,路径要体现学号信息,IDEA中,伪代码要体现个人学号信息 1.参见Bag的UML图,用Java继承BagInterface实现泛型类Bag,并 ...

  6. 求n以内的质数的数量

  7. 倒置数组 Exercise07_12

    import java.util.Scanner; /** * @author 冰樱梦 * 时间:2018年下半年 * 题目:倒置数组 * */ public class Exercise07_12 ...

  8. django框架下celery+rabbitmq+flower完成异步任务

    [转载请注明出处:] http://www.cnblogs.com/yukityan/p/8035787.html 环境: ubuntu16.04 64位 安装: sudo apt-get insta ...

  9. [转] Log4j 配置 的webAppRootKey参数问题

    在tomcat下部署两个或多个项目时,web.xml文件中最好定义webAppRootKey参数,如果不定义,将会缺省为“webapp.root”,如下:<!-- 应用路径 --> < ...

  10. 网络数据包分析 网卡Offload

    http://blog.nsfocus.net/network-packets-analysis-nic-offload/     对于网络安全来说,网络传输数据包的捕获和分析是个基础工作,绿盟科技研 ...