使用 type() 動態建立類...LOGIN

使用 type() 動態建立類別

因為類別也是對象,所以我們可以在程式運行的時候創建類別。 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 在幕後做的事情,而這就是透過元類別來實現的。

下一節
章節課件