Python元類__prepare__方法深入理解


學習元類的時候,對__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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM