1. 程式人生 > >簡要介紹python的超程式設計的metaclass

簡要介紹python的超程式設計的metaclass

平時經常看到超程式設計、DSL這樣的字眼,它到底是什麼意思?
我的理解來看。超程式設計就是“程式碼生成器”,你可以通過一些程式碼生成另一些程式碼(動態地、按需的)。DSL則是domain special language:為了解決某個問題而發明的語言,比如HTML SQL YACC,它的反面是C JAVA Python這些通用語言。與DSL經常提到的是ruby,為什麼說ruby可以DSL呢?因為它語法豐富,支援各種簡寫,lamba,閉包,block等等,通過自定義的一套高階API從而實現一門特定領域的方言。這種方言是可以交給客戶寫的。


python中超程式設計的目標是:動態生成需要的類class。我們知道class例項化後就是instance,而python中的metaclass例項化後就是class了。先看一個例子
class MyMeta(type):  
def __new__(cls, name, parents, attrs):
print("new info: ", cls, name, parents, attrs)
attrs['abcde'] = 'fghijk'
return type.__new__(cls, name, parents, attrs)

class C(metaclass=MyMeta):
pass

print(C.abcde)

輸出結果是:
[quote]fghijk[/quote]
通過修改__new__裡面的attrs就可以更改類的屬性

python類在初始化的時候,經歷了兩個階段,第一個階段是分配空間__new__(),第二個階段是初始化值__init__()。當類被建立時,python2會首先尋找__metaclass__是否存在,如果存在則呼叫__metaclass__。如果此類沒定義__metaclass__就去看父類,父類沒有就去模組裡找(全域性變數__metaclass__),包裡再沒有就把__metaclass__ = type作為類的metaclass。而python3先看自己metaclass有沒有定義,如果沒有就看父類,父類沒有就用type

再介紹下__new__中各個引數的意思:cls代表呼叫__new__函式的class,name代表物件的__name__值,也就是名稱,parents代表物件的父類元組,attrs代表類的屬性字典。

metaclass功能就是這麼簡單,一般來說是用不上的,除非要大批量的修改類的屬性。其實python本身就是動態語言,在執行時就可以更改屬性。而且decorator也可以很好的修改呼叫物件前後的行為。所以metaclass瞭解就行。

metaclass還有一些比較邊邊角角的知識點,比如說MyMeta這裡還會引入一個__prepare__函式:
    #官方文件說要是classmethod型別
@classmethod
def __prepare__(self, *args, **kwargs):
print("__prepare__ called")
# return type.__prepare__(self, *args, **kwargs)
return kwargs

這個函式還要在__new__函式呼叫之前呼叫,這個函式必須返回一個用於存放類屬性(namespace)的資料結構,預設情況下就是字典型別了。我在這裡直接就把kwargs返回就可以,沒問題的,極端點,return {}都是可以的。這裡可以玩一下,比如說
return {'xx': 'yy'}

你會發現整個類中都會被新增xx這個屬性……

最後附上幾個小知識點:
#可以使用type動態建立一個類
myclass = type("MyClass", (), {})
print(myclass)
s = super(myclass, myclass())
#super其實返回一個super object
print(s)
#輸出結果是:
<super: <class 'MyClass'>, <MyClass object>>