簡單定義“元編程是一種編寫計算機程序的技術,這些程序可以將自己看做數據,因此你可以在運行時對它進行內審、生成和/或修改”,本博參考<<Python高級編程>>將對元編程內容進行詳細描述,若有不正確之處希望大家指出。
1. 概述
Python元編程有兩種方法,一是采用類似“裝飾器”的工具對基本元素(例如函數、類、類型)內審和對其進行實時創建和修改,二是運用類型"元類"的方式對類實例的創建過程進行修改,甚至於允許重新設計Python面對對象編程范式的實現。
2. 裝飾器
關於裝飾器的內容可以閱讀上篇博客<<Python裝飾器>>,鏈接:http://www.cnblogs.com/xiaobingqianrui/p/8435074.html
對wraps裝飾器的使用進行補充說明,在類裝飾器中使用閉包會導致生成的對象不再是被裝飾的類的實例,二是在裝飾器函數創建的子類的實例,這會影響__name__和__doc__等屬性,在上篇我們使用@wraps裝飾器對函數裝飾器進行操作讓問題得到解決,但在類裝飾器中這一方法無效。
3. 元類
元類是Python的一個重要特性,是定義其他類的類,理解其工作方式,最重要的是要知道定義了對象實例的類也是對象,那么它一定有與其相關聯的類,所有的類定義的基類都是內置的type類。
#coding=utf-8 class MyClass: pass if __name__ == "__main__": myclass = MyClass() print ("type of myclass:", type(myclass)) print ("type of MyClass:", type(MyClass))
>>> type of myclass: <class '__main__.MyClass'>
>>> type of MyClass: <class 'type'>
3.1 type()語法
type()類作為class語句的動態等效,給定類名,基類名和屬性映射會創建一個新類
#coding=utf-8 def func1(self): print (1) def func2(*argv): print (argv) if __name__ == "__main__": MyClass = type("MyClass",(object, ), {"func1":func1, "func2":func2}) a = MyClass() print (type(a)) a.func1() a.func2(2)
>>> <class '__main__.MyClass'>
>>> 1
>>> (<__main__.MyClass object at 0x01A02270>,2)
3.2 元類的常用模板
#coding=utf-8 '''元類模板 ''' class MyClass(type): #創建一個空的命名空間,返回一個空的dict @classmethod def __prepare__(mcs, name, bases, **kwargs): print ("MyClass __prepare__") return super().__prepare__(name, bases, **kwargs) def __new__(mcs, name, bases, namespace): print ("MyClass __new__") return super().__new__(mcs, name, bases, namespace) def __init__(cls, name, bases, namespace, **kdargv): print ("MyClass __init__") super().__init__(name, bases, namespace) def __call__(cls, *argv, **kdargv): print ("MyClass __call__") return super().__call__(*argv, **kdargv) class _MyClass(metaclass=MyClass): def __new__(cls): print ("_MyClass __new__") return super().__new__(cls) def __init__(self): print("__MyClass __init__") super().__init__() if __name__ == "__main__": a = _MyClass()
>>> MyClass __prepare__
>>> MyClass __new__
>>> MyClass __init__
>>> MyClass __call__
>>> _MyClass __new__
>>> __MyClass __init_
用class語句創建的每個類都隱式的使用type作為元類,可以用metaclass=“指定元類”的方式改變這一默認行為。
3.3 元類的使用
元類是一種非常強大的特性,但總是會是代碼更加復雜,將其用於任意類型的類時,這可能會降低代碼的魯棒性,我們必須靈活的使用元類。
#coding=utf-8 class OrderedMeta(type): @classmethod def __prepare__(mcs, name, bases, **kdargv): return super().__prepare__(mcs, name, bases, **kdargv) def __new__(mcs, name, bases, namespace): namespace["orderofattr"] = list(namespace.keys()) return super().__new__(mcs, name, bases, namespace) class test(metaclass = OrderedMeta): first = 8 secord = 2 if __name__ == "__main__": print (test.orderofattr) print (test.__dict__.keys())
>>> ['__module__', '__qualname__', 'first', 'secord']
>>> dict_keys(['__module__', 'first', 'secord', 'orderofattr', '__dict__', '__weakre
>>> f__', '__doc__'])