• <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| 亚洲人成无码网站久久99热国产| 久久久久久毛片免费看| 久久91精品国产91| 久久久久久九九99精品| 国产巨作麻豆欧美亚洲综合久久| 无码人妻少妇久久中文字幕 | 国产午夜免费高清久久影院| 久久99精品国产麻豆宅宅| 久久亚洲视频| 国产成人精品免费久久久久| 久久天天躁狠狠躁夜夜av浪潮| 狠狠色婷婷久久综合频道日韩| 久久er国产精品免费观看2| 日韩电影久久久被窝网| 91精品国产综合久久香蕉| 无码国产69精品久久久久网站| 91久久精品国产91性色也| 色天使久久综合网天天| 欧美一区二区精品久久| 亚洲国产精品无码久久SM| 四虎亚洲国产成人久久精品| 狠狠人妻久久久久久综合| 久久香蕉一级毛片| 久久久久久九九99精品| 一本久久知道综合久久| 97精品国产97久久久久久免费| 久久综合伊人77777麻豆| 国产精品美女久久久免费| 久久久久久国产精品免费无码| 久久人做人爽一区二区三区| 久久无码国产| 久久成人18免费网站| 亚洲国产成人久久综合一| 国产精品美女久久久久av爽| 2021国产成人精品久久| 国产精品99久久久久久www| 久久久久久av无码免费看大片| 久久婷婷五月综合成人D啪 | 精品久久久久久国产|