• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Benjamin

            靜以修身,儉以養德,非澹薄無以明志,非寧靜無以致遠。
            隨筆 - 397, 文章 - 0, 評論 - 196, 引用 - 0
            數據加載中……

            python中的MetaClass(元類)

            MetaClass元類,本質也是一個類,但和普通類的用法不同,它可以對類內部的定義(包括類屬性和類方法)進行動態的修改。可以這么說,使用元類的主要目的就是為了實現在創建類時,能夠動態地改變類中定義的屬性或者方法。
            一、type() 函數還有一個更高級的用法,即創建一個自定義類型(也就是創建一個類)。
            type() 函數的語法格式有 2 種,分別如下:
            type(obj)
            type(name, bases, dict)
            class type(name, bases, dict)
            使用1個參數,返回對象的類型。就像object.__class__。內置函數isinstance()被用來測試對象的類型,因為他會考慮到子類。
            用3個參數,返回一個新類型對象。本質上,這是類聲明的一種動態形式。
            參數name是一個字符串,表示類名稱,并記錄為__name__屬性;
            參數bases是一個元組,一個個記下基礎類,并記錄為__bases__屬性,
            參數dict是一個字典,包含類本體的命名空間并被賦值到標準字典。并記錄為__dict__屬性。
            示例:
            #定義一個實例方法
            def say(self):
                print("這是 Python!")
            #使用 type() 函數創建類
            CLanguage = type("CLanguage",(object,),dict(say = say, name = "python語言"))
            #創建一個 CLanguage 實例對象
            clangs = CLanguage()
            #調用 say() 方法和 name 屬性
            clangs.say()
            print(clangs.name)

            二、MetaClass元類,本質也是一個類,但是它可以動態的定制或修改繼承它的子類。
            metaclass 是 type 的子類,通過替換 type 的 __call__ 運算符重載機制
            用戶自定義類,只不過是 type 類的 __call__ 運算符重載
            一個類設計成 MetaClass 元類,其必須符合以下條件:
            必須顯式繼承自 type 類;
            類中需要定義并實現 __new__() 方法,該方法一定要返回該類的一個實例對象,因為在使用元類創建類時,該 __new__() 方法會自動被執行,用來修改新建的類
            #定義一個元類
            class FirstMetaClass(type):
                # cls代表動態修改的類
                # name代表動態修改的類名
                # bases代表被動態修改的類的所有父類
                # attr代表被動態修改的類的所有屬性、方法組成的字典
                def __new__(cls, name, bases, attrs):
                    # 動態為該類添加一個name屬性
                    attrs['name'] = "python語言"
                    attrs['say'] = lambda self: print("調用 say() 實例方法")
                    return super().__new__(cls,name,bases,attrs)
                    #定義類時,指定元類
            class CLanguage(object,metaclass=FirstMetaClass):
                pass
            clangs = CLanguage()
            print(clangs.name)
            clangs.say()
            用方法來創建元類
            def upper_attr(future_class_name, future_class_parents, future_class_attr):
                '''返回一個類對象,將屬性都轉為大寫形式'''
                #  選擇所有不以'__'開頭的屬性
                attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
            # 將它們轉為大寫形式
                uppercase_attr = dict((name.upper(), value) for name, value in attrs)
                # 通過'type'來做類對象的創建
                return type(future_class_name, future_class_parents, uppercase_attr)
            __metaclass__ = upper_attr  #  這會作用到這個模塊中的所有類
            class Foo(object):
                # 我們也可以只在這里定義__metaclass__,這樣就只會作用于這個類中
                bar = 'bip'

            print(hasattr(Foo, 'bar'))
            # 輸出: False
            print(hasattr(Foo, 'BAR'))
            # 輸出:True
            f = Foo()
            print(f.BAR)、
            元類定義了__prepare__以后,會最先執行__prepare__方法,返回一個空的定制的字典,然后再執行類的語句,類中定義的各種屬性被收集入定制的字典,最后傳給new和init方法
            3.6版本以前,__prepare__方法主要用來返回一個orderdict對象,以保存類中屬性的添加順序。而3.6版本以后,默認已經是保持順序的了。
            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()))
            在python中,類的__new__、__init__、__call__等方法不是必須寫的,會默認調用,如果自己定義了,就是override,可以custom。既然override了,通常也會顯式調用進行補償以達到extend的目的。
            __call__ : 對象可call,注意不是類,是對象。
            如果元類中定義了__call__,此方法必須返回一個對象,否則類的實例化就不會起作用。(實例化得到的結果為__call__的返回值)
            三、類的__slots__ 屬性只能限制為實例對象動態添加屬性和方法,而無法限制動態地為類添加屬性和方法。
            __slots__ 屬性值其實就是一個元組,只有其中指定的元素,才可以作為動態添加的屬性或者方法的名稱。舉個例子
            class CLanguage:
                __slots__ = ('name','add','info')
                這意味著,該類的實例對象僅限于動態添加 name、add、info 這 3 個屬性以及 name()、add() 和 info() 這 3 個方法。
                注意,對于動態添加的方法,__slots__ 限制的是其方法名,并不限制參數的個數。
                __slots__ 屬性對由該類派生出來的子類,也是不起作用的,因為_slots__ 屬性限制的對象是類的實例對象,而不是類

            posted on 2020-06-28 14:40 Benjamin 閱讀(528) 評論(0)  編輯 收藏 引用 所屬分類: python

            97久久国产露脸精品国产| 亚洲精品NV久久久久久久久久| 伊人色综合九久久天天蜜桃| 亚洲国产综合久久天堂 | 久久精品免费网站网| 久久露脸国产精品| 精品国产乱码久久久久久1区2区| 久久99国产精一区二区三区| 国内精品伊人久久久久影院对白| 九九精品久久久久久噜噜| 精品一区二区久久| 久久99精品久久久大学生| 一本大道久久a久久精品综合| 青青草原综合久久大伊人| 一本大道久久a久久精品综合| 久久久久亚洲国产| 国产高潮国产高潮久久久91 | 久久这里只有精品18| 国内精品久久久久久久久电影网 | 99久久精品费精品国产一区二区| 欧美成a人片免费看久久| 成人综合伊人五月婷久久| 久久久久一级精品亚洲国产成人综合AV区 | 亚洲午夜久久久影院伊人| 久久99精品国产麻豆蜜芽| 久久精品国产99久久久| 久久亚洲AV成人无码| 久久青青草原精品国产软件| 婷婷综合久久狠狠色99h| 无码人妻久久一区二区三区| 亚洲国产成人精品女人久久久 | 久久国产乱子伦免费精品| 2019久久久高清456| 欧美精品九九99久久在观看| 亚洲国产成人精品91久久久| 久久黄色视频| 亚洲国产成人精品91久久久| 亚洲欧洲久久久精品| 无码国内精品久久综合88| 久久亚洲AV无码精品色午夜麻豆| 久久伊人精品一区二区三区|