Python元類

Python元類

上一篇文章: Python==與is對比
下一篇文章: Python是動態語言:動態編輯屬性、動態編輯方法

本篇內容只供瞭解,實際上99%的python程序員都用不到元類喲,不過你要想成爲那1%,請隨意享用,別客氣😆python

元類做用:攔截類的建立、修改類、返回修改以後的類程序員

萬物皆對象,類建立了實例對象,那既然萬物皆對象,類也是對象,那什麼建立了類呢,啦啦啦,固然就是本篇的主人翁:元類。編程

一、類也是對象

既然類也是一個對象,那就應該具備對象共有的特性:

能夠將其賦給變量segmentfault

能夠拷貝函數

能夠增長屬性指針

能夠做爲函數參數進行傳遞code

實例:對象

class A:
    def hello_fun(self):
        print("Hello World")

def test(a):
    print("類做爲函數參數傳遞:",a)

#類也是對象,因此能夠打印
print(A)

#由於類也是對象,因此能夠做爲函數參數進行傳遞
test(A)

#hasattr用來判斷指定類中是有有對應屬性
print(hasattr(A,"mark"))#哼,我就是一個屬性,來打我呀

#添加屬性而且賦值
A.mark="帥"#mark是屬性名稱,帥是值
print(hasattr(A,"mark"))
print("mark屬性值:",A.mark)

#由於類是一個對象,因此能夠拷貝
B=A#拷貝
print(B)

運行結果:繼承

<class '__main__.A'>
類做爲函數參數傳遞: <class '__main__.A'>
False
True
mark屬性值: 帥
<class '__main__.A'>

二、動態(函數內部)建立類

既然類也是對象,固然能夠動態建立,好比在函數內部建立。

實例:內存

def test():
    class A:
        def hello_fun(self):
            print("Hello World")
    print("函數內部建立的類:",A)


test()

運行結果:

函數內部建立的類: <class '__main__.test.<locals>.A'>

三、type動態建立類

type函數除了能夠檢查類型外,另外一個高大上的用途就是動態建立類。

語法:type(類名,由父類名稱組成的元組(能夠爲空),包含屬性的字典(名稱和值))

實例:

#定義一個沒有方法,沒有屬性的類:A
A=type("A",(),{})

#打印A
print(A)
#打印A的實例
print(A())

print("*"*30)

#定義一個帶兩個屬性的類:B
B=type("B",(),{"name":"mark","age":18})
print(B.name)
print(B.age)

print("*"*30)

#定義一個帶普通方法的類:C
def test_for_c(self):
    print(self.name)
C=type("C",(),{"name":"mark","age":18,"test_for_c":test_for_c})
c=C()
c.test_for_c()

print("*"*30)

#添加靜態方法
@staticmethod
def static_method_test():
    print("static method test")
D=type("D",(),{"name":"mark","age":18,"static_method_test":static_method_test})
D.static_method_test()


print("*"*30)
#添加類方法
@classmethod
def class_method_test(cls):
    print(cls.name)
E=type("E",(),{"name":"mark","age":18,"class_method_test":class_method_test})
e=E()
e.class_method_test()
E.class_method_test()

結果:

<class '__main__.A'>
<__main__.A object at 0x10b7ac0f0>
******************************
mark
18
******************************
mark
******************************
static method test
******************************
mark
mark

四、__metaclass__

實例:

class A(object,metaclass=xxxx):
    pass

滴答滴答,想象一下,解析指針如今運行到這個類的上面,此處類還沒加載到內存中,而後開始解析A,首先去A的定義中找,有沒有指定__metaclass__屬性,若是指定了,就利用這個指定的屬性來建立類,沒有指定就會用type開生成類。具體步驟以下:

  1. 類中有這個__metaclass__屬性嗎,若是有,利用這個屬性來建立類。
  2. 若是類中不存在,判斷父類是否存在,若是存在,就利用這個屬性建立類。
  3. 父類也沒有,就去模塊層次尋找這個屬性,存在的話就利用這個屬性建立類,
  4. 若是尚未找到,就使用type來建立類。

五、自定義元類(經過定義方法)

如今自定義一個元類,保證全部的屬性名都大寫

實例:

def upper_attr(class_name,class_parent,class_attr):
    #遍歷屬性字典,把不是__開頭的屬性名稱都編程大寫
    newAttr={}
    for name,value in class_attr.items():
        if not name.startswith("__"):
            newAttr[name.upper()]=value
    #調用type來建立類
    return type(class_name,class_parent,newAttr)
class A(object,metaclass=upper_attr):
    mark="帥哥"

print(hasattr(A,"mark"))
print(hasattr(A,"MARK"))

print(A.MARK)

結果:

False
True
帥哥

六、自定義元類(經過繼承type)

如今自定義一個元類,保證全部的屬性名都大寫

實例:

class UpperAttrMetaClass(type):
    #__new__是在__init__以前被調用的特殊方法,用來建立對象並返回,
    #而__init__只是將傳遞的參數賦給對象
    def __new__(cls,class_name,class_parent,class_attr):
        # 遍歷屬性字典,把不是__開頭的屬性名稱都編程大寫
        newAttr = {}
        for name, value in class_attr.items():
            if not name.startswith("__"):
                newAttr[name.upper()] = value
        # 方法1:調用type來建立類
        #return type(class_name, class_parent, newAttr)

        #方法2:複用type.__new__方法
        #return type.__new__(cls,class_name,class_parent,newAttr)

        #方法3:使用super方法
        return super(UpperAttrMetaClass,cls).__new__(cls,class_name,class_parent,newAttr)



class A(object,metaclass=UpperAttrMetaClass):
    mark="帥哥"

print(hasattr(A,"mark"))
print(hasattr(A,"MARK"))

print(A.MARK)

結果:

False
True
帥哥
相關文章
相關標籤/搜索