python筆記6:元類

Table of Contents

 

01 全局對象與內嵌模塊

02 元類

03 type使用

04 元類應用補充


01 全局對象與內嵌模塊

什麼是類?類是一個對象(類對象-創建實例對象的模子對象),用它創建的對象爲實例對象

class ObjectCreater(object):

Py中萬物皆對象,Linux萬物皆文件

Python中有內嵌函數(可以直接調用的函數),如:

input("請輸入>>")

print("XXX")

list()

tuple()

dict()

set()

Python運行時默認加載了內建/內嵌模塊,其中帶有這些常用函數

查看到底有哪些函數可以直接用,globals返回可調用的一個字典:

globals()

新定義一個全局變量:

a=100

再查看globals,會增加一行

'a':100,

新定義一個全局函數:

def AA():

       pass

再查看globals,最新一行會增加

'AA':<function __main__.AA>

新定義一個類:

class BB():

       pass

globals

'BB':__main__.BB

定義類時,會給這個類創建內存空間,globals中的名字指向剛剛創建的對象空間

 

萬物皆對象,這個變量也是對象

在字典中不能出現兩個相同的key,所以最後導入的、最後賦引用的會覆蓋,類、函數、變量不能重名

同理,類的名字指向了這個類對象

類與普通對象的區別只是,它擁有創建其他實例對象空間的能力

但是這個globals中沒有print函數,在內嵌模塊builtin中。查看這個模塊:

xx=globals()#xx指向了這個字典

xx['__builtin__'].__dict__

'input':<function input>

'print':<function print>

調用其中函數

yy=xx['__builtin__'].__dict__#保存這個字典

yy['print']("hah")

輸出:hah

 

ipython比單用python時有更多命令可以直接用

把所有輸出過的東西存儲在Out字典中,把所有輸入過的東西存儲在In字典中

ipython有一個sqlite數據庫,內嵌型(它不需要建立服務器,讀取時打開文件)

02 元類

需求-改變類空間內容,如:添加一個屬性

類:創建實例對象,實例對象有自己的內存空間,同時也有一部分共享類對象中的數據

元類(python造物主):可以創建類

類也是對象,你可以在運行時創建它們,就像其他任何對象一樣。

可以在函數中創建類,使用class關鍵字即可

>>> def choose_class(name):

       if name == 'foo':

           class Foo(object):

               pass

           return Foo     # 返回的是類,不是類的實例

       else:

           class Bar(object):

               pass

           return Bar

 

>>> MyClass = choose_class('foo')

>>> print(MyClass)  # 函數返回的是類,不是類的實例

<class '__main__'.Foo>

>>> print(MyClass())  # 可以通過這個類創建類實例,也就是對象

<__main__.Foo object at 0x89c6d4c>

比較標準的創建類的方式是type(一般type用來返回一個對象的類型type(100)

type(類名, 由父類名稱組成的元組(針對無繼承的情況,可以爲空),包含屬性的字典(名稱和值))

B = type("B", (), {"num":100,"num2":200})

查看類:

print(help(B))

輸出:

num=100

num2=200

Type是一個元類,Type的返回值是一個類對象

字典不一樣,則屬性不一樣

03 type使用

如果元類創建類時需要繼承

B = type("B", (), {"num":100,"num2":200})

Test22=type("Test22",(B,),{})#元組中至少要放一個','

查看新類

print(help(Test22))

class Test22(B)

...

num = 100

num2 = 200

有繼承的類、屬性

添加方法:添加屬性時指向方法引用

def test_2(self):

       print(">>實例方法")

Test3=type("Test3",(),{"test_2":test_2})

創建實例對象

t3=Test3()

t3.test_2()

輸出:

>>實例方法

添加類方法

#類方法

@classmethod

def test_3(cls):

       print(">>類方法")

Test4=type("Test4",(),{"test_2":test_2,"test_3":test_3})

添加靜態方法

#靜態方法

@staticmethod

def test_4():

       print(">>靜態方法")

Test5=type("Test5",(),{"test_2":test_2,"test_3":test_3,"test_4":test_4})

Demo

class T(object):

       pass

t=T()

t.__class__#查看是哪個類創建的

輸出

__main__.T

t.__class__.__class__

輸出

type

即使直接寫,類還是type創建的

元類創建類對象,類對象創建實例對象

元類的功能:

#-*- coding:utf-8 -*-

def upper_attr(class_name, class_parents, class_attr):

 

    # 遍歷屬性字典,把不是__開頭的屬性名字變爲大寫

    new_attr = {}

    for name,value in class_attr.items():

        if not name.startswith("__"):#過濾掉隱藏的默認屬性

            new_attr[name.upper()] = value

 

    # 調用type來創建一個類

    return type(class_name, class_parents, new_attr)

 

class Foo(object, metaclass=upper_attr):

    bar = 'bip'

 

print(hasattr(Foo, 'bar'))

print(hasattr(Foo, 'BAR'))

 

f = Foo()

print(f.BAR)

在定義普通類Foo時,如果形如:

class Foo(object):

    bar = 'bip'

就調用默認的Type創建類對象,等價於:

Foo=type("Foo",(object,),{"bar":'bip'})

Python3:添加參數metaclass=upper_attr:不管在類中定義什麼屬性名,通通變成大寫

Python2:

class Foo(object):

    __metaclass__ = upper_attr  # 設置Foo類的元類爲upper_attr

不直接調用默認type創建,調用自定義函數創建

自定義函數的返回值:一個類對象

# 調用type來創建一個類

    return type(class_name, class_parents, new_attr)

函數被調用後能像type一樣獲取類名、父類、類屬性,就可以在創建時對他們進行修改後再給type

04 元類應用補充

一般情況不會使用元類

裝飾器在不修改原來函數條件下,調用函數前後加新功能

元類不修改原來類定義中內容,但可以修改類屬性等

之前一直使用的函數當作元類使用,修改爲類:

class UpperAttrMetaClass(type):

    # __new__ 是在__init__之前被調用的特殊方法

    # __new__是用來創建對象並返回的方法

    # 而__init__只是用來將傳入的參數初始化給對象

    # 你很少用到__new__,除非希望能夠控制對象的創建

    # 這裏,創建的對象是類,我們希望能夠自定義它,所以改寫__new__

    # 還有一些高級的用法會涉及到改寫__call__特殊方法,但是這裏不用

    def __new__(cls, class_name, class_parents, class_attr):

        # 遍歷屬性字典,把不是__開頭的屬性名字變爲大寫

        new_attr = {}

        for name, value in class_attr.items():

            if not name.startswith("__"):

                new_attr[name.upper()] = value

 

        return type(class_name, class_parents, new_attr)

在定義了多個類,想要統一修改某些功能屬性時,可以考慮元類

__new__也涉及到單例

Python中沒有數組

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章