Python-深入理解元类(metaclass)

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=‘35‘)
print guy.age

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

9.小结

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

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

时间: 2024-12-15 05:01:36

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

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

深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例模式的那一节有些疑惑.因此花了几天时间研究下元类这个概念.通过学习元类,我对python的面向对象有了更加深入的了解.这里将一篇写的非常好的文章基本照搬过来吧,这是一篇在Stack overflow上很热的帖子,我看http://blog.jobbole.com/21351/这篇博客对其进行了翻译. 一.理解

Python中的元类(metaclass)

推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有创建对象(类实例)的能力. 因为它的本质是一个对象: 可以将它赋值给一个变量 可以拷贝它 增加属性 作为参数进行传递 可以在运行时动态地创建他们,可以在函数中创建类,只需要使用class关键字即可 当使用class关键字的时候,Python解释器会自动地创建这个对象,Python还提供了手动处理的方

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

译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理解,以及在什么情况下需要进行元编程.于是e-satis同学给出了神一般的回复,该回复获得了985点的赞同点数,更有人评论说这段回复应该加入到Python的官方文档中去.而e-satis同学本人在Stack Overflow中的声望积分也高达6

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

本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理解,以及在什么情况下需要进行元编程.于是e-satis同学给出了神一般的回复,该回复获得了9

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

译注:这是一篇在Stack overflow上 很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子 和代码片段以帮助理解,以及在什么情况下需要进行元编程.于是e-satis同学给出了神一般的回复,该回复获得了985点的赞同点数,更有人评论说这段 回复应该加入到Python的官方文档中去.而e-satis同学本人在Stack Overflow中的声望积分也

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

非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stackoverflow.欢迎加入翻译组. 译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理解,以及

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

注:本文原稿来自stackoverflow,原文链接,目前已收获5k高赞. 一.类也是对象 在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍然成立: >>> class ObjectCreator(object): … pass … >>> my_object = ObjectCreator() >>>

python中的元类metaclass

元类MetaClass 元类是可以让你定义某些类是如何被创建的.从根本上说,赋予你如何创建类的控制权. 元类也是一个类,是一个type类. 元类一般用于创建类.在执行类定义时,解释器必须要知道这个类的正确的元类,如果此属性没有定义,它会向上查找父类中的__metaclass__属性.如果还没发现,就查找全局变量. 对于传统类来说,它们的元类是types.ClassType. 元类也有构造器,传递三个参数:类名,从基类继承数据的元组,和类属性字典 下面我们来定义一个元类,要求写类的时候必须给类提供

深刻理解Python中的元类(metaclass)--代码实践

根据http://blog.jobbole.com/21351/所作的代码实践. 这篇讲得不错,但以我现在的水平,用到的机会是很少的啦... #coding=utf-8 class ObjectCreator(object): pass my_object = ObjectCreator() # print my_object def echo(o): print o echo(ObjectCreator) print hasattr(ObjectCreator, 'new_attribute'