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")
>>> type(1)
>>> type([])
>>> type({})
>>> type(Exception())
>>> type(object())
如果你有一个自定义的类
>>> EvinK = Person()
>>> type(EvinK)
上面所有的东西,都被type()
识别为某个class(对象)的实例。
对象的对象
Python世界里所有的对象都继承于object
对象,使用isinstance(instance, object)
就可以验证这一点。但是,object又是什么类型呢?按照直觉的话,它应该还是一个object类型,多说无益,开一个终端来测试一下吧!
>>> type(object)
>>> type(type)
>>> isinstance(object, object)
True
>>> isinstance(object, type)
True
>>> isinstance(type, object)
True
>>> isinstance(type, type)
True
原来,object
是一个 type
类型。
而 type
不光作为一个类型鉴定函数,居然是一个类。那既然是类,肯定也 object
的子类,但是同时, object
是 type
的一个实例,于是间接地 object
也成为了自身的实例(由于 type
和 object
的继承关系)。
由此推论,所有继承于 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__': ,
'__init__': ,
'get_private_var': ,
'class_method': ,
'__dict__': ,
'__weakref__':
}
evink = Person(age=13)
print(evink.__dict__)
{
'__module__': '__main__',
'__doc__': '\n Person Document\n ',
'name': 'EvinK',
'_Person__private_var': 1,
'__new__': ,
'__init__': ,
'get_private_var': ,
'class_method': ,
'__dict__': ,
'__weakref__': ,
'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/