學習元類的時候,對__prepare__不是很理解,書上講解的也不是很詳細,最后通過查看stackoverflow的一些帖子對該方法有了一些理解,記錄如下:
先看代碼:
class member_table(dict):
def __init__(self):
self.member_names = []
def __setitem__(self, key, value):
if key not in self:
self.member_names.append(key)
dict.__setitem__(self, key, value)
class OrderedClass(type):
@classmethod
def __prepare__(metacls, name, bases):
classdict = member_table()
print("prepare return dict id is:", id(classdict))
return classdict
def __new__(metacls, name, bases, classdict):
print("new get dict id is:", id(classdict))
result = type.__new__(metacls, name, bases, dict(classdict))
result.member_names = classdict.member_names
print("the class's __dict__ id is:", id(result.__dict__))
return result
def __init__(cls, name, bases, classdict):
print("init get dict id is ", id(classdict))
super().__init__(name, bases, classdict)
class MyClass(metaclass=OrderedClass):
def method1(self):
pass
def method2(self):
pass
print("MyClass locals() id is ", id(locals()))
輸出為:
prepare return dict id is: 2093480992528
MyClass locals() id is 2093480992528
new get dict id is: 2093480992528
the class's __dict__ id is: 2093482830200
init get dict id is 2093480992528
可見,執行順序為:
prepare(創建命名空間)-> 依次執行類定義語句 -> new(創建類)-> init(初始化類)
元類定義了prepare以后,會最先執行prepare方法,返回一個空的定制的字典,然后再執行類的語句,類中定義的各種屬性被收集入定制的字典,最后傳給new和init方法。
再來看其它輸出:
MyClass.member_names
['__module__', '__qualname__', 'method1', 'method2']
MyClass.attr1 = 'attr1'
MyClass.__dict__
mappingproxy({'__dict__': <attribute '__dict__' of 'MyClass' objects>,
'__doc__': None,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
'attr1': 'attr1',
'member_names': ['__module__',
'__qualname__',
'method1',
'method2'],
'method1': <function __main__.MyClass.method1>,
'method2': <function __main__.MyClass.method2>})
id(MyClass.__dict__)
2093482829864
MyClass.member_names
['__module__', '__qualname__', 'method1', 'method2']
上面的例子,在new方法中,dict被替換成一個普通的dict。所以MyClass.member_names不會記錄class創建以后新增的屬性。同時__dict__屬性是類命名空間的一個代理,每次查看其id都不同。
3.6版本以前,prepare方法主要用來返回一個orderdict對象,以保存類中屬性的添加順序。而3.6版本以后,默認已經是保持順序的了。
stackoverflow上的討論帖
平時學習的一些筆記正在慢慢上傳至github,歡迎大家交流。
地址是:https://github.com/telecomshy/python-study