Python核心技术与实战
景霄
Facebook资深工程师
立即订阅
13891 人已学习
课程目录
已完结 46 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 从工程的角度深入理解Python
免费
基础篇 (14讲)
01 | 如何逐步突破,成为Python高手?
02 | Jupyter Notebook为什么是现代Python的必学技术?
03 | 列表和元组,到底用哪一个?
04 | 字典、集合,你真的了解吗?
05 | 深入浅出字符串
06 | Python “黑箱”:输入与输出
07 | 修炼基本功:条件与循环
08 | 异常处理:如何提高程序的稳定性?
09 | 不可或缺的自定义函数
10 | 简约不简单的匿名函数
11 | 面向对象(上):从生活中的类比说起
12 | 面向对象(下):如何实现一个搜索引擎?
13 | 搭建积木:Python 模块化
14 | 答疑(一):列表和元组的内部实现是怎样的?
进阶篇 (11讲)
15 | Python对象的比较、拷贝
16 | 值传递,引用传递or其他,Python里参数是如何传递的?
17 | 强大的装饰器
18 | metaclass,是潘多拉魔盒还是阿拉丁神灯?
19 | 深入理解迭代器和生成器
20 | 揭秘 Python 协程
21 | Python并发编程之Futures
22 | 并发编程之Asyncio
23 | 你真的懂Python GIL(全局解释器锁)吗?
24 | 带你解析 Python 垃圾回收机制
25 | 答疑(二):GIL与多线程是什么关系呢?
规范篇 (7讲)
26 | 活都来不及干了,还有空注意代码风格?!
27 | 学会合理分解代码,提高代码可读性
28 | 如何合理利用assert?
29 | 巧用上下文管理器和With语句精简代码
30 | 真的有必要写单元测试吗?
31 | pdb & cProfile:调试和性能分析的法宝
32 | 答疑(三):如何选择合适的异常处理方式?
量化交易实战篇 (8讲)
33 | 带你初探量化世界
免费
34 | RESTful & Socket: 搭建交易执行层核心
35 | RESTful & Socket: 行情数据对接和抓取
36 | Pandas & Numpy: 策略与回测系统
免费
37 | Kafka & ZMQ:自动化交易流水线
38 | MySQL:日志和数据存储系统
39 | Django:搭建监控平台
40 | 总结:Python中的数据结构与算法全景
技术见闻与分享 (4讲)
41 | 硅谷一线互联网公司的工作体验
42 | 细数技术研发的注意事项
加餐 | 带你上手SWIG:一份清晰好用的SWIG编程实践指南
43 | Q&A:聊一聊职业发展和选择
结束语 (1讲)
结束语 | 技术之外的几点成长建议
Python核心技术与实战
登录|注册

18 | metaclass,是潘多拉魔盒还是阿拉丁神灯?

蔡元楠 2019-06-19
你好,我是蔡元楠,极客时间《大规模数据处理实战》专栏的作者。今天我想和你分享的主题是:metaclass,是潘多拉魔盒还是阿拉丁神灯?
Python 中有很多黑魔法,比如今天我将分享的 metaclass。我认识许多人,对于这些语言特性有两种极端的观点。
一种人觉得这些语言特性太牛逼了,简直是无所不能的阿拉丁神灯,必须找机会用上才能显示自己的 Python 实力。
另一种观点则是认为这些语言特性太危险了,会蛊惑人心去滥用,一旦打开就会释放“恶魔”,让整个代码库变得难以维护。
其实这两种看法都有道理,却又都浅尝辄止。今天,我就带你来看看,metaclass 到底是潘多拉魔盒还是阿拉丁神灯?
市面上的很多中文书,都把 metaclass 译为“元类”。我一直认为这个翻译很糟糕,所以也不想在这里称 metaclass 为元类。因为如果仅从字面理解,“元”是“本源”“基本”的意思,“元类”会让人以为是“基本类”。难道 Python 的 metaclass,指的是 Python 2 的 Object 吗?这就让人一头雾水了。
事实上,meta-class 的 meta 这个词根,起源于希腊语词汇 meta,包含下面两种意思:
“Beyond”,例如技术词汇 metadata,意思是描述数据的超越数据;
“Change”,例如技术词汇 metamorphosis,意思是改变的形态。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Python核心技术与实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(37)

  • 奔跑的蜗牛
    看不懂了 😄
    2019-06-19
    40
  • 尘墨
    我尝试着自己写了一个例子,发现好像清晰多了,没有看懂的大家可以看一下
    class Mymeta(type):
        def __init__(self, name, bases, dic):
            super().__init__(name, bases, dic)
            print('===>Mymeta.__init__')
            print(self.__name__)
            print(dic)
            print(self.yaml_tag)

        def __new__(cls, *args, **kwargs):
            print('===>Mymeta.__new__')
            print(cls.__name__)
            return type.__new__(cls, *args, **kwargs)

        def __call__(cls, *args, **kwargs):
            print('===>Mymeta.__call__')
            obj = cls.__new__(cls)
            cls.__init__(cls, *args, **kwargs)
            return obj
        
    class Foo(metaclass=Mymeta):
        yaml_tag = '!Foo'

        def __init__(self, name):
            print('Foo.__init__')
            self.name = name

        def __new__(cls, *args, **kwargs):
            print('Foo.__new__')
            return object.__new__(cls)

    foo = Foo('foo')
    把上面的例子运行完之后就会明白很多了,正常情况下我们在父类中是不能对子类的属性进行操作,但是元类可以。换种方式理解:元类、装饰器、类装饰器都可以归为元编程(引用自 python-cook-book 中的一句话)。

    作者回复: 棒

    2019-06-20
    1
    24
  • 你曾是少年
    基础不够,之前没接触过metaclass,这一讲读起来太费劲了
    2019-06-19
    19
  • Hoo-Ah
    之前讲装饰器的时候讲到函数装饰器和类装饰器,而类装饰器就是在雷里面定义了__call__方法,之后在函数执行的时候会调用类的__call__方法。
    在metaclass中重载了__call__方法,在使用metaclass实例化生成类的时候也是调用了__call__方法,从这方面来讲是很像。
    要说不一样的话,一个是在执行层面,一个是在生成层面。
    可以讲讲type和object的区别吗以及可以用一篇专栏讲讲python的魔术方法。
    2019-06-19
    14
  • 程序员人生
    装饰器像AOP,metaclass像反射机制
    2019-06-19
    1
    9
  • 你看起来很好吃
    ‘用户自定义类,只不过是 type 类的__call__运算符’
    景老师,这里这段是不是有点问题,我做了以下实验:

    class MyMeta(type):
        def __init__(cls, name, bases, dict):
            print('MyMeta __init__')

        def __new__(cls, name, bases, dict):
            print('MyMeta __new__')
            return type.__new__(cls, name, bases, dict)

        def __call__(cls):
            print('MyMeta __call__')
            return type.__call__(cls)

    class Test(metaclass=MyMeta):
        a = 10

        def __init__(self):
            pass

        def __new__(cls):
            return super(Test, cls).__new__(cls)

    test = Test()
    我发现在使用class Test()定义类时,会依次调用MyMeta的__new__和__init__方法构建Test类,然后在使用test = Test()创建类对象时,才会调用MyMeta的__call__方法来调用Test类的__new__和__init__方法。好像和您说的不一样?
    我看您说的意思是,在使用class定义类的时候,先调用metaclass的__call__,然后再调用metaclass的__new__和__init__?
    2019-06-19
    2
    6
  • SCAR
    哎,对metaclass的机制真是一知半解啊,是90%那坨的!
    metaclass和类装饰器都可以动态定制或修改类,类装饰器比metaclass以更简单的方式做到创建类时定制类,但它只能定制被装饰的这个类,而对继承这个类的类失效。metaclass的功能则是要强大的多,它可以定制类的继承关系。
    2019-06-19
    3
  • Wing·三金
    个人粗浅的理解是:metaclass 与 类装饰器相似,大多数情况下本质上都是重载了 __call__ 函数,但有一个明显的区别是前者对【继承了 metaclass 的子类本身】的属性造成了影响,而类装饰器是对【作为装饰器本身的类】造成影响而已,对【被装饰的类】的属性没有直接影响(间接影响就看被装饰的函数怎么操作了)。
    2019-06-22
    1
    2
  • Jon徐
    之前没有接触过 metaclass,感觉用metaclass的作用就是超动态生成类。这节课感觉确实比较魔术,跟上一节装饰器还要再细想一下。

    pyyaml 5.1以上,这段代码会报错,要把 yaml.load() 改成 yaml.load_all()
    yaml.load("""
    --- !Monster
    name: Cave spider
    hp: [2,6] # 2d6
    ac: 16
    attacks: [BITE, HURT]
    """)


    2019-06-20
    2
    2
  • 建强
    1.metaclass拦截了类的构造,类似于黑客,改变了类的行为,在某些场合可简化程序设计。
    2.python装饰器:不会去改变类的行为,但通过装饰类,可以加强类的功能,通过不同的装饰器使类的功能更加丰富。
    2019-09-25
    1
  • 吴月月鸟
    这篇蛮好玩的,天堂和地狱只有一步之遥。
    2019-07-05
    1
  • Michael
    class TestMetaClass(type):

        def __new__(mcs, *args, **kwargs):
            print('TestMetaClass.__new__', mcs)
            return type.__new__(mcs, *args, **kwargs)

        def __init__(cls, name, bases, kwds):
            print('TestMetaClass.__init__', cls)
            super(TestMetaClass, cls).__init__(name, bases, kwds)

        def __call__(cls, *args, **kwargs):
            print('TestMetaClass.__call__')
            return super(TestMetaClass, cls).__call__(*args, **kwargs)


    class A(metaclass=TestMetaClass):

        def __new__(cls, *args, **kwargs):
            print('A.__new__')
            return super(A, cls).__new__(cls)

        def __init__(self, name=None):
            self.name = name
            print('A.__init__')


    A('hello')
    2019-07-02
    1
  • Geek_Wison
    老师你好,为什么我执行示例代码会一个constructor错误,查了好久资料都解决不了。
    import yaml
    class Monster(yaml.YAMLObject):
      yaml_tag = u'!Monster'
      def __init__(self, name, hp, ac, attacks):
        self.name = name
        self.hp = hp
        self.ac = ac
        self.attacks = attacks
      def __repr__(self):
        return "%s(name=%r, hp=%r, ac=%r, attacks=%r)" % (
           self.__class__.__name__, self.name, self.hp, self.ac,
           self.attacks)

    yaml.load("""
    --- !Monster
    name: Cave spider
    hp: [2,6] # 2d6
    ac: 16
    attacks: [BITE, HURT]
    """)

    错误信息:
    ConstructorError: could not determine a constructor for the tag '!Monster'
      in "<unicode string>", line 2, column 5:
        --- !Monster
            ^
    2019-06-23
    2
    1
  • 图·美克尔
    装饰器和metaclass都是给对象增加一些额外的公共配件,但装饰器不影响对象本身,而metaclass是将对象本身进行改造。是设计模式层面的东西。
    2019-06-21
    1
  • KaitoShy
    yaml.load("""
    --- !Monster
    name: Cave spider
    hp: [2,6] # 2d6
    ac: 16
    attacks: [BITE, HURT]
    """)
    运行时报错,pyyaml版本PyYAML-5.1,将语句改成
    yaml.load("""
    --- !Monster
    name: Cave spider
    hp: [2,6] # 2d6
    ac: 16
    attacks: [BITE, HURT]
    """,Loader=yaml.Loader)即可,参见"https://github.com/yaml/pyyaml/issues/266"

    作者回复: 很好

    2019-06-19
    1
  • Destroy、
    一开始还以为我打开错专栏了。 目前看了好多解释metaclass的文章,感觉这一篇看起来最明了。

    作者回复: 谢谢

    2019-06-19
    1
    1
  • Paul Shan
    Python :创建普通类型对象,调用的是系统定义的type(classname, superclasses, attributedict)
    创建metaclass,调用的是自定义的MyMeta(classname, superclasses, attributedict),这个时候可以做很多手脚。
    但是这些手脚明显违背封装的特性,不是特别必要还是不要用。
    2019-11-18
  • 沢民
    老师,这段代码有Python3的版本的吗?运行不通呢。
    2019-11-04
  • 自由民
    思考题:装饰器是不改变函数,而为函数增加新的功能,在函数和类上都能用。metaclass是改变自定义类型的metaclass,使其不再重载默认的type的__call__而是转而重载自定义的metaclass的__call__。
    总结:慎用metaclass。
    2019-10-06
  • Geek_54edc1
    个人感觉,metaclass通过重载__call__来修改类的行为,而装饰器是通过将原函数进行包装来修改原函数的功能,两者都对原有的功能进行了扩展,但是实现思路不一样,metaclass是从类型机制这个角度,而装饰器主要从函数的角度,个人感觉装饰器更加轻量级(因此更加适合业务应用层面),而metaclass更加重量级一些(可以看成是“大招”,也因此更加适合框架层面)
    2019-09-13
收起评论
37
返回
顶部