• 奔跑的蜗牛
    2019-06-19
    看不懂了 😄
    
     43
  • 尘墨
    2019-06-20
    我尝试着自己写了一个例子,发现好像清晰多了,没有看懂的大家可以看一下
    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 中的一句话)。
    展开

    作者回复: 棒

     3
     28
  • 你曾是少年
    2019-06-19
    基础不够,之前没接触过metaclass,这一讲读起来太费劲了
    
     20
  • Hoo-Ah
    2019-06-19
    之前讲装饰器的时候讲到函数装饰器和类装饰器,而类装饰器就是在雷里面定义了__call__方法,之后在函数执行的时候会调用类的__call__方法。
    在metaclass中重载了__call__方法,在使用metaclass实例化生成类的时候也是调用了__call__方法,从这方面来讲是很像。
    要说不一样的话,一个是在执行层面,一个是在生成层面。
    可以讲讲type和object的区别吗以及可以用一篇专栏讲讲python的魔术方法。
    
     14
  • 程序员人生
    2019-06-19
    装饰器像AOP,metaclass像反射机制
     1
     9
  • 你看起来很好吃
    2019-06-19
    ‘用户自定义类,只不过是 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__?
    展开
     2
     6
  • SCAR
    2019-06-19
    哎,对metaclass的机制真是一知半解啊,是90%那坨的!
    metaclass和类装饰器都可以动态定制或修改类,类装饰器比metaclass以更简单的方式做到创建类时定制类,但它只能定制被装饰的这个类,而对继承这个类的类失效。metaclass的功能则是要强大的多,它可以定制类的继承关系。
    
     3
  • Wing·三金
    2019-06-22
    个人粗浅的理解是:metaclass 与 类装饰器相似,大多数情况下本质上都是重载了 __call__ 函数,但有一个明显的区别是前者对【继承了 metaclass 的子类本身】的属性造成了影响,而类装饰器是对【作为装饰器本身的类】造成影响而已,对【被装饰的类】的属性没有直接影响(间接影响就看被装饰的函数怎么操作了)。
     1
     2
  • Jon徐
    2019-06-20
    之前没有接触过 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]
    """)


    展开
     2
     2
  • 隔壁家老鲍
    2019-12-16
    感觉入门了,不过还是有一些问题
    @修饰符是在python里是怎么实现的呢
    老师如果看到了可以给点意见么

    作者回复: 问题很好,修饰器的确和metaclass有很多相似之处

    
     1
  • 建强
    2019-09-25
    1.metaclass拦截了类的构造,类似于黑客,改变了类的行为,在某些场合可简化程序设计。
    2.python装饰器:不会去改变类的行为,但通过装饰类,可以加强类的功能,通过不同的装饰器使类的功能更加丰富。
    
     1
  • 吴月月鸟
    2019-07-05
    这篇蛮好玩的,天堂和地狱只有一步之遥。
    
     1
  • Michael
    2019-07-02
    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')
    展开
    
     1
  • Geek_Wison
    2019-06-23
    老师你好,为什么我执行示例代码会一个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
            ^
    展开
     2
     1
  • 图·美克尔
    2019-06-21
    装饰器和metaclass都是给对象增加一些额外的公共配件,但装饰器不影响对象本身,而metaclass是将对象本身进行改造。是设计模式层面的东西。
    
     1
  • KaitoShy
    2019-06-19
    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"
    展开

    作者回复: 很好

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

    作者回复: 谢谢

     1
     1
  • jackstraw
    2020-01-12
    这代码跑都跑不通

    作者回复: 遇到什么问题?这些代码我都校验过

    
    
  • Sean
    2019-12-29
    再补充一段,忘记说“装饰器”和“metaclass”的区别了,装饰器就没有基因编辑那么神奇了,它是用来装饰用的,相当于一个外在的辅助功能,而且只对被装饰的函数有效果,好比美颜相机的功能,每一张要被装饰的面孔都需要用美颜相机进行一次装饰(@装饰函数),而且,你被装饰之后,你的子女不会被装饰,就不存在代代继承的效果了,使用起来也更加灵活,你可以选择美颜后再发圈,也可以选择不美颜直接发圈。
    
    
  • Sean
    2019-12-29
    每次学完后,都会看一遍大家的留言,很多留言都很精彩,本章内容特别有意思,也领略到了Python的神奇之处,我也留言一次吧,哈哈哈哈。
    个人对于metaclass认知,首先它包含了“超越类”和“变形类”含义。
    超越类:是因为继承了自定义metaclass的类,都会受到影响。
    变形类:类的运行机制跟普通类的机制不同,会增加某种功能。
    出现两种特性的根本原因就是因为Python本身的运行机制,每一个定义的类都涉及到继承、重载,中途修改了父类的特性,子类自然受影响,之前说Python里面,处处皆对象,看来可以修改为“Python中处处皆对象,处处皆对象的继承、重载”。举个例子,使用metaclass有点类似于基因编辑,对某一位孕妇采用了基因编辑的技术,如果编辑后可以提高母亲的智商,自然她的子子辈辈的智商都能提高(阿拉丁神灯的效果);如果编辑后会导致母亲的免疫力下降,自然她的子子辈辈的免疫力都会下降(潘多拉魔盒带来的灾难),所以,基因编辑也要慎重,当然,目前来说是明令禁止。
    展开
    
    
我们在线,来聊聊吧