使用 type() 動(dòng)態(tài)建立類(lèi)別
因?yàn)轭?lèi)別也是對(duì)象,所以我們可以在程式運(yùn)行的時(shí)候創(chuàng)建類(lèi)別。 Python 是動(dòng)態(tài)語(yǔ)言。動(dòng)態(tài)語(yǔ)言和靜態(tài)語(yǔ)言最大的不同,就是函數(shù)和類(lèi)別的定義,不是編譯時(shí)定義的,而是在執(zhí)行時(shí)動(dòng)態(tài)創(chuàng)建的。在之前,我們先了了解下 type() 函數(shù)。
首先我們新建一個(gè) hello.py 的模組,然後定義一個(gè) Hello 的 class ,
class Hello(object): def hello(self, name='Py'): print('Hello,', name)
然後在另一個(gè)模組中引用 hello 模組,並輸出對(duì)應(yīng)的資訊。其中 type() 函數(shù)的作用是可以查看一個(gè)型別和變數(shù)的型別。
#!/usr/bin/env python3 # -*- coding: UTF-8 -*- from com.twowater.hello import Hello h = Hello() h.hello() print(type(Hello)) print(type(h))
輸出的結(jié)果是怎麼樣的呢?
Hello, Py <class 'type'> <class 'com.twowater.hello.Hello'>
上面也提到過(guò),type() 函數(shù)可以查看一個(gè)型別或變數(shù)的型別,Hello 是一個(gè)class ,它的型別就是type ,而h 是一個(gè)實(shí)例,它的型別就是com.twowater .hello.Hello。前面的 com.twowater 是我的包名,hello 模組在該包名下。
在這裡還要細(xì)想一下,在上面的範(fàn)例中,我們使用 type() 函數(shù)來(lái)查看一個(gè)型別或變數(shù)的型別。其中查看了一個(gè) Hello class 的類(lèi)型,列印的結(jié)果是: <class 'type'> 。其實(shí) type() 函數(shù)不僅可以傳回一個(gè)物件的類(lèi)型,也可以建立出新的類(lèi)型。 class 的定義是執(zhí)行時(shí)期動(dòng)態(tài)建立的,而建立 class 的方法就是使用 type() 函數(shù)。例如我們可以透過(guò)type() 函數(shù)來(lái)建立出上面範(fàn)例中的Hello 類(lèi),具體看下面的程式碼:
# -*- coding: UTF-8 -*- def printHello(self, name='Py'): # 定義一個(gè)打印 Hello 的函數(shù) print('Hello,', name) # 創(chuàng)建一個(gè) Hello 類(lèi) Hello = type('Hello', (object,), dict(hello=printHello)) # 實(shí)例化 Hello 類(lèi) h = Hello() # 調(diào)用 Hello 類(lèi)的方法 h.hello() # 查看 Hello class 的類(lèi)型 print(type(Hello)) # 查看實(shí)例 h 的類(lèi)型 print(type(h))
輸出的結(jié)果如下:
Hello, Py <class 'type'> <class '__main__.Hello'>
在這裡,要先了解下通過(guò)type() 函數(shù)建立class 物件的參數(shù)說(shuō)明:
1、class 的名稱(chēng),例如範(fàn)例中的起名為Hello
2、繼承的父類(lèi)別集合,注意Python 支援多重繼承,如果只有一個(gè)父類(lèi),tuple 要使用單元素寫(xiě)法;例子中繼承object 類(lèi),因?yàn)槭菃卧氐膖uple ,所以寫(xiě)成(object,)
3、class 的方法名稱(chēng)與函數(shù)綁定;範(fàn)例中將函數(shù)printHello 綁定在方法名稱(chēng)hello 中
具體的模式如下:
type(類(lèi)別名稱(chēng), 父類(lèi)別的元組(針對(duì)繼承的情況,可以為空),包含屬性的字典(名稱(chēng)和值))
好了,了解完具體的參數(shù)使用之外,我們看看輸出的結(jié)果,可以看到,透過(guò)type() 函數(shù)創(chuàng)建的類(lèi)別和直接寫(xiě)class 是完全一樣的,因?yàn)镻ython 解譯器遇到class 定義時(shí),只是掃描一下class 定義的語(yǔ)法,然後呼叫type() 函數(shù)會(huì)建立出class 的 。
不過(guò)一般的情況下,我們都是使用 class ***... 的方法來(lái)定義類(lèi)別的,不過(guò) type() 函數(shù)也可以讓我們建立出類(lèi)別來(lái)。也就是說(shuō),動(dòng)態(tài)語(yǔ)言本身支援運(yùn)行期間動(dòng)態(tài)創(chuàng)建類(lèi),這和靜態(tài)語(yǔ)言有非常大的不同,要在靜態(tài)語(yǔ)言運(yùn)行期創(chuàng)建類(lèi),必須構(gòu)造源代碼字符串再調(diào)用編譯器,或者藉助一些工俱生成字節(jié)碼實(shí)現(xiàn),本質(zhì)上都是動(dòng)態(tài)編譯,會(huì)非常複雜。
可以看到,在 Python 中,類(lèi)別也是對(duì)象,你可以動(dòng)態(tài)的創(chuàng)建類(lèi)別。其實(shí)這也就是當(dāng)你使用關(guān)鍵字 class 時(shí) Python 在幕後做的事情,而這就是透過(guò)元類(lèi)別來(lái)實(shí)現(xiàn)的。