• <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 閱讀(523) 評論(0)  編輯 收藏 引用 所屬分類: python

            亚洲一区精品伊人久久伊人| 久久国产成人午夜AV影院| 久久久久精品国产亚洲AV无码 | 色成年激情久久综合| 国产亚洲美女精品久久久| 麻豆精品久久久久久久99蜜桃| 国产成人精品综合久久久久| 国产精品久久久天天影视| 亚洲精品成人网久久久久久| 久久亚洲中文字幕精品有坂深雪 | 大香伊人久久精品一区二区| 久久精品人人做人人爽电影蜜月| 久久久精品视频免费观看 | 久久亚洲电影| 久久成人精品视频| 午夜久久久久久禁播电影| 99久久精品久久久久久清纯| 久久国产欧美日韩精品| 久久人人爽人人爽人人片AV高清| 很黄很污的网站久久mimi色| 国产精品久久毛片完整版| 久久综合狠狠综合久久| 久久久久99精品成人片牛牛影视 | 久久久久精品国产亚洲AV无码 | 国产精品久久久久乳精品爆 | 亚洲精品成人久久久| 久久最近最新中文字幕大全| 久久国产热精品波多野结衣AV| 亚洲AV无码成人网站久久精品大| 亚洲国产天堂久久综合| 欧美久久一级内射wwwwww.| 久久99国产一区二区三区| 品成人欧美大片久久国产欧美...| 久久免费美女视频| 91精品日韩人妻无码久久不卡 | 久久99国产精品二区不卡| 久久精品亚洲中文字幕无码麻豆 | 中文字幕人妻色偷偷久久| 国产成人综合久久精品红| 精品综合久久久久久97| 色偷偷88888欧美精品久久久|