Python 的 Metaclass 有沒有什麼好的 Best Practice 可以學習?


metaclass這個用的的確還是蠻少的啦,只有在Python這樣的語言當中才會有這麼瘋狂的主意,它是class的class。我們知道Python的新類本身也是個對象,這個對象的類型默認是type,metaclass就是允許我們修改這個類本身的類型。換句話來說,定義一個新類的語法:

class MyClass(MyBase, MyBase2):
myproperty = "abc"
def myfunction(self):
pass

大致相當於

metaclass = type # Use default metaclass
MyClass = metaclass(MyClass, # class name
(MyBase, MyBase2), # base classes
{myproperty: abc,
myfunction: _MyClass_myfunction} # members dictionary
)

那麼使用自定義的metaclass就是使用一個自己定義的類來替換type。一般來說我們不可能希望自己實現所有和type兼容的介面,所以我們簡單從type派生一個類出來:

class MyMetaclass(type):
pass

class MyClass(MyBase, MyBase2):
__metaclass__ = MyMetaclass
myproperty = "abc"
def myfunction(self):
pass

注意Python2與Python3的語法有所不同,Python3使用keyword argument的形式。

僅僅派生一個MyMetaclass類出來除了可以讓我們的type(MyClass)顯得特殊一點以外,並沒有什麼特別的作用,我們必須重寫MyMetaclass的某些方法,來實現一些功能——最瘋狂的功能。最常見的情況下,我們使用Metaclass都是為了自定義創建類的過程,也就是metaclass(...)這一步,所以最常見的情況下,我們會重載__new__方法,這樣在定義新類的時候,我們有機會修改這個類的名字、基類還有成員。修改前兩個會讓定義過程變得十分詭異,所以最常見的情況下,我們會給類自動添加新的成員,或者修改定義的成員。比如下面的例子中,我們自動給定義的類的每個_property_XXX的變數添加property描述符,並且如果類當中同時定義了XXX_changed的方法,我們會自動在set過程中調用這個方法:

class AutoProperty(type):
def __new__(cls, name, bases, d):
newmembers = {}
for k,v in d.items():
if k.startswith(_property_):
name = k[len(_property_):]
if not name:
continue
def _create_handlers(k, name):
# Use an extra function to create closures
# with independent (k, name)
def getter(self):
return getattr(self, k)
def setter(self, value):
oldvalue = getattr(self, k, None)
if oldvalue != value:
setattr(self, k, value)
if hasattr(self, name + _changed):
getattr(self, name + _changed)(oldvalue, value)
return getter, setter
getter, setter = _create_handlers(k, name)
newmembers[name] = property(getter, setter, None,
Automatic property + name +
, default to + repr(v))
d = dict(d)
d.update(newmembers)
return super(AutoProperty, cls).__new__(cls, name, bases, d)

class MyClass(object):
__metaclass__ = AutoProperty
_property_text = "Default text"
def text_changed(self, oldvalue, newvalue):
print "text changed from %r to %r" % (oldvalue, newvalue)

&>&>&> myobject = MyClass()
&>&>&> myobject.text = "new text"
text changed from Default text to new text

Metaclass並沒有標準的使用規範,如官方文檔中所說的那樣,The potential uses for metaclasses are boundless. 完全取決於你有多大的膽量。一般來說Metaclass用來解決一些非Metaclass不可的問題,比如說自動定義或者替換類的成員,比如說根據baseclass修改類的特性等等。一些不是那麼瘋狂的需求可以用其他技術來完成,比如說decorator,比如說合理的類的繼承關係等等。能創建出最瘋狂功能的語法同時也是一個雙刃劍,它也會創造出最不可理解的bug,所以要合理使用。


比較經典的例子就是ORM了,廖雪峰的教程裡面就有。


這個stack overflow上的答案應該會是你想要的.

深刻理解Python中的元類(metaclass)


推薦閱讀:

拆代碼學演算法之用python實現KNN過程詳解
Python黑帽編程 3.3 MAC洪水攻擊
Python黑帽編程 3.5 DTP攻擊
學習數據分析的8個 pandas資源

TAG:Python | 編程 | 最佳實踐 |