元编程

作者: EvinK | 来源:发表于2018-09-21 22:22 被阅读0次
    
        physics,即物理学,是研究物质、能量的本质与性质,以及它们彼此之间相互作用的自然科学。
        metaphysics, 被翻译为「形而上学」,由日本人 井上哲次郎 于 明治时代 翻译为汉字词语,指研究事物本身的学问。通常人们在谈论形而上学时,往往将它作为一种哲学上的讨论--关于根本(或者存在)本身的意义。
    
        meta前缀,源于希腊语,其本意是「在…后,越过…的」,而后在西方哲学界的发展中渐渐赋予该词缀一种全新的意义:关于某事自身的某事。比如 meta-knowledge 就是「关于知识本身的知识」,meta-data 就是「关于数据的数据」,meta-language 就是「关于语言的语言」,而 meta-programming 也是由此而来,是「关于编程的编程」。
    
    

    meta在中国大陆多被翻译为「元」,在台湾多被翻译为「后设」

    什么是元编程

    元编程的目的是操作其他的程序(或自身)作为它自身的数据,在运行时完成它本应该在编译时应该完成的任务。

    一个使用bash脚本描述的元程序

    
    #!/bin/bash
    # metaprogram
    echo '#!/bin/bash' >program
    for ((I=1; I<=992; I++)) do
        echo "echo $I" >>program
    done
    chmod +x program
    
    

    元编程的能力在很大的程度上也和选择的语言有关系,比如:C/C++ 的宏, Java的反射和动态代理……
    而像Python这种动态性强的语言,给对象加个属性、方法啥的,简直不值一提。

    一切都是对象……吗?

    继在(类)Unix世界喊出了「一切皆是文件」的口号之后,Python世界也喊出了「一切皆是对象」的口号。

    不信?打开终端,随便输入点什么,来看看结果

    
    >>> type("a")
    <class 'str'>
    >>> type(1)
    <class 'int'>
    >>> type([])
    <class 'list'>
    >>> type({})
    <class 'dict'>
    >>> type(Exception())
    <class 'Exception'>
    >>> type(object())
    <class 'object'>
    
    

    如果你有一个自定义的类<e>Person</e>, 就会有

    
    >>> EvinK = Person()
    >>> type(EvinK)
    <class 'Person'>
    
    

    上面所有的东西,都被type()识别为某个class(对象)的实例。

    对象的对象

    Python世界里所有的对象都继承于object对象,使用isinstance(instance, object)就可以验证这一点。但是,object又是什么类型呢?按照直觉的话,它应该还是一个object类型,多说无益,开一个终端来测试一下吧!

    
    >>> type(object)
    <class 'type'>
    >>> type(type)
    <class 'type'>
    >>> isinstance(object, object)
    True
    >>> isinstance(object, type)
    True
    >>> isinstance(type, object)
    True
    >>> isinstance(type, type)
    True
    
    

    原来,object 是一个 type 类型。

    type 不光作为一个类型鉴定函数,居然是一个类。那既然是类,肯定也 object 的子类,但是同时, objecttype 的一个实例,于是间接地 object 也成为了自身的实例(由于 typeobject 的继承关系)。

    python-type-instance.png

    由此推论,所有继承于 object 的类(即Python中的所有对象),都是 type 的一个实例。

    type 在此就作为这些类的类之存在,并用来定义这些类中的属性的方法。它是Python世界里最为特殊的一个对象,一个用来操纵对象的对象。它是 object 的子类, object 是它的实现。

    使用type来定义一个类

    一个已知的定义类的方式(如下),已经写入了各种文章中

    
    class Person:
        """
        Person Document
        """
        # 类变量
        name = "EvinK"
        # 私有类变量
        __private_var = 1
    
        # 实际上的构造函数
        def __new__(cls, *args, **kwargs):
            cls.age = kwargs["age"]
            return cls
    
        # 此方法将不会被执行
        def __init__(self, age):
            self.age_ = age
    
        # 静态方法
        @staticmethod
        def get_private_var():
            return Person.__private_var
    
        # 类方法
        @classmethod
        def get_last_age(cls):
            # 返回最后一个实例的age
            return cls.age
    
    if __name__ == "__main__":
    
        print(Person.__dict__)
    
        {
            '__module__': '__main__',
            '__doc__': '\n    Person Document\n    ',
            'name': 'EvinK',
            '_Person__private_var': 1,
            '__new__': <staticmethod object at 0x7f98aec409b0>,
            '__init__': <function Person.__init__ at 0x7f98acf25840>,
            'get_private_var': <staticmethod object at 0x7f98aec40908>,
            'class_method': <classmethod object at 0x7f98aec40ac8>,
            '__dict__': <attribute '__dict__' of 'Person' objects>,
            '__weakref__': <attribute '__weakref__' of 'Person' objects>
        }
    
        evink = Person(age=13)
        print(evink.__dict__)
    
        {
            '__module__': '__main__',
            '__doc__': '\n    Person Document\n    ',
            'name': 'EvinK',
            '_Person__private_var': 1,
            '__new__': <staticmethod object at 0x7f4e297d8d30>,
            '__init__': <function Person.__init__ at 0x7f4e297db840>,
            'get_private_var': <staticmethod object at 0x7f4e2b4f6ac8>,
            'class_method': <classmethod object at 0x7f4e2b4f69b0>,
            '__dict__': <attribute '__dict__' of 'Person' objects>,
            '__weakref__': <attribute '__weakref__' of 'Person' objects>,
            'age': 13
        }
    
    

    上述的类被一个字典给描述,其中包含有这个类的类变量 , 静态方法类方法 , 方法构造方法 。而类的实例也可以被一个字典描述,只不过多了写 实例变量 而已。这两者的结构看上去是如此的相似,但是一个是类型(type的实例),一个是(类的)实例。

    既然通过类的构造方法就可以生成实例,那作为 type 实例的类,是不是也可以由 type 生成呢?

    
    Person = type("Person", (), dict(
            name="EvinK",
            # 使用type生成的类声明将不会被转换为 _Person__private_var 这种形式
            __private_var=1
        ))
    
    Person.__doc__ = \
            """
                Person
            """
    
    @staticmethod
    def new(cls, *args, **kwargs):
            return cls
    
    # 出现__new__方法时, 此构造将不会被执行
    def init(self, age):
            self.age = age
    
    Person.__init__ = init
    Person.__new__ = new
    
    

    上面由type生成的类,使用 __dict__ 属性时,可以看到,基本和我们使用 class 关键字声明的类长得一样。这对某些静态类型的语言来说简直是天方夜谭!

    未完待续……

    原文地址: https://code.evink.me/2018/09/post/Meta-Programming/

    相关文章

      网友评论

          本文标题:元编程

          本文链接:https://www.haomeiwen.com/subject/fezznftx.html