Python深入淺出分析元類

一、類和對象

Python屬於動態類型的語言,而動態語言和靜態語言最大的不同,就是函數和類的定義,不是編譯時創建的,而是運行時動態創建的,比方說我們要定義一個 Person 的class,就寫一個 Person.py 模塊:

# -*- coding: utf-8 -*-
# 文件名  : Person.py
class Person(object):
    def say(self, s='元類'):
        print('今日學習:%s' % s)
if __name__ == '__main__':
    p = Person()
    p.say()

當Python解釋器載入 Person 模塊時,就會依次執行該模塊的所有語句,執行結果就是動態創建出一個 Person 的class對象,測試如下,(註意,是引入一個Person.py腳本)

# 文件名 :測試.py
# 引入模塊,需要模塊的路徑
from Person import Person
# 創建一個Person類的實例
p = Person()  
p.say('Python中的元類')  # 調用say方法
# 今日學習:Python中的元類
print(type(p))  # 把實例 p 的類型打印出來
# <class 'say.Person'>
print(type(Person))  # Person 類的類型打印出來
# <class 'type'>

這裡是用來 type() 函數,可以查看一個類型或變量,的類型, Person 是一個class,它的類型就是 type ,而 p是一個實例,它的類型就是class Person

二、type類

我們說class的定義是運行時動態創建的,而創建class的方法就是使用 type() 函數

type() 函數既可以返回一個對象的類型,又可以創建出新的類型,比如,我們可以通過 type() 函數創建出Person 類,而無需通過 class Person(object)... 的定義,此時type的第二種用法,我們隻要type傳object是可以返回該對象類型的,但是當我們的type存在三位參數存在時

# type 類
class type(object):
    """
    type(object_or_name, bases, dict)
    type(object) -> the object's type
    type(name, bases, dict) -> a new type
    """
#參數介紹
"""    
type(object_or_name, bases, dict)
object-or-name -- 對象或類的名稱。
bases -- 基類的元組。
dict -- 字典,類內定義的命名空間變量。
"""
# 返回新的類型對象。
# -*- coding: utf-8 -*-
def fun(self, s):
    print('hello'+s)
Hello = type('hello', (object,), dict(func=fun))
if __name__ == '__main__':
    h = Hello()
    h.func(' word')
    # hello word
    print(type(h))
    # <class '__main__.hello'>
    print(type(Hello))
    # <class 'type'>  

我們通過 type() 函數創建的類和直接寫class是完全一樣的,因為Python解釋器遇到class定義時,僅僅是掃描一下class定義的語法,然後調用 type() 函數創建出class

在正常情況下,我們都用 class Xxx... 來定義類,但是, type() 函數也允許我們動態創建出類來,也就是說,動態語言本身支持運行期動態創建類,這和靜態語言有非常大的不同,要在靜態語言運行期創建類,必須構造源代碼字符串再調用編譯器,或者借助一些工具生成字節碼實現,本質上都是動態編譯,會非常復雜

三、元類Metaclass

除瞭使用 type() 動態創建類以外,要控制類的創建行為,還可以使用metaclass,也就是元類

當我們定義瞭類以後,就可以根據這個類創建出實例,所以:先定義類,然後創建實例

但是如果我們想創建出類呢?那就必須根據metaclass創建出類,所以:先定義metaclass,然後創建類,元類就是用來創建這些類(對象)的,元類就是類的類

我們先看一個簡單的例子,這個metaclass可以給自定義的類增加一個 add 方法定義 ListMetaclass ,按照默認習慣,metaclass的類名總是以Metaclass結尾,以便清楚地表示這是一個metaclas。

四、自定義一個元類

class UpperMetaclass(type):
    def __new__(mcs, class_name, class_parents, class_attrs):
        new_attrs = {}
        for name, value in class_attrs.items():
            if not name.startswith('__'):  # 判斷是否為非私有屬性
                new_attrs[name.upper()] = value
        # 直接調用type 來創建一個類
        return type.__new__(mcs, class_name, class_parents, class_attrs)
# 測試
class Emp(object, metaclass=UpperMetaclass):
    name = '張三'
    acl = 500
if __name__ == '__main__':
    print(hasattr(Emp, 'name'))  # 判斷Emp中是否有名字為name
    print(hasattr(Emp, 'NAME'))  # 判斷Emp中是否有名字為NAME

到此這篇關於Python深入淺出分析元類的文章就介紹到這瞭,更多相關Python元類內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: