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'>
如果你有一個自定義的類Person, 就會有
>>> 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
的子類,但是同時, 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__': <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
關鍵字聲明的類長得一樣。這對某些靜態類型的語言來說簡直是天方夜譚!
未完待續……