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