1. 程式人生 > 實用技巧 >使用Python和Flask編寫Prometheus監控

使用Python和Flask編寫Prometheus監控

元類

1、什麼是元類

  創建出類的類,就是元類。例如:type就是元類

2、如何產生類

  產生類的方法有兩種:

    第一種:通過class關鍵字產生類

# 1.通過class關鍵字產生類
class Chinese(object):
    country = 'China'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex


p_obj = Chinese("張三", 87, "male")
print(type(p_obj))    #
<class '__main__.Chinese'> # 類本質上也是一個物件,因為在python中 一切皆物件 print(Chinese) # <class '__main__.Chinese'>

    第二種:通過type產生類 type()

# 2.通過呼叫type產生類:type()
code = """
country = 'China'
def __init__(self, name, age, sex):
    self.name = name
    self.age = age
    self.sex = sex
"""

class_attr 
= {} # 定義一個類的名稱空間class_attr # exec()是python的內建函式,可以將字串的程式碼新增到名稱空間中,名稱空間可以自定義; # 語法exec(字串形式的程式碼,全域性名稱空間,區域性名稱空間) exec(code, {}, class_attr) # 將code中的程式碼新增到全域性和區域性名稱空間中
# type()需要傳入的引數:what, bases=None, dict=None # what:在這裡指的是類名 bases:繼承的父類,也就是基類 dict:類的名稱空間 obj = type("Chinese", (object, ), class_attr) # 產生一個Chinese類的物件obj
print(obj) # <class '__main__.Chinese'>

3、元類的作用

  元類可以控制類的建立過程

  例:

    先建立一個元類,然後要求根據元類建立的類的類名字必須首字母大寫而且類內部必須要有註釋

# 自定義一個元類, 元類在此是“控制類”
class MyMetaClass(type):    # 繼承type類,然後重寫type類中的方法來建立類

    # 重寫type類的__init__方法
    # 將type()中需要傳入的三個引數:what, bases=None, dict=None 改為 class_name, class_bases, class_dict   (這裡僅僅只是改了個名字而已)
    def __init__(self, class_name, class_bases, class_dict):
        # print(class_name)
        # print(class_bases)
        # print(class_dict)
        if not class_name.istitle():    # .istitle():判斷首字母是否是大寫
            raise NameError("類的名字首字母必須大寫!!!")    # 丟擲異常

        if not class_dict.get("__doc__"):    # 判斷類的名稱空間中是否有__doc__屬性,即“註釋”
            raise TypeError("類必須寫註釋!!!")    # 丟擲異常

        # 必須將類中的類名、類的基類、類的名稱空間,一併返回給type中的__init__
        super().__init__(class_name, class_bases, class_dict)



    # 以下為呼叫類時,類內部如何產生空物件以及物件名稱空間的原理(不必懂):
    # __call__控制呼叫類的行為
    # 呼叫類時type內部一定會呼叫一次__call__,由__call__來幫你呼叫__new__建立空物件,然後__call__再呼叫__init__將類中傳入的引數放入物件的名稱空間中
    def __call__(self, *args, **kwargs):    # 重寫type類的__call__方法
        print(args)    # 列印的args為呼叫類傳入的引數

        # 呼叫object來建立一個空物件obj
        obj = object.__new__(self)

        # 呼叫類時,__call__會立馬呼叫  類名.__init__,並且將obj連同User括號內的引數一同傳給__init__,然後產生名稱空間
        self.__init__(obj, *args, **kwargs)
        return obj

# 自定義一個類,此類在此時是新建立的MyMetaClass元類的被控制類 # 被控制類在定義階段的 "metaclass=自定義的元類"引數,他會將當前被控制類的名稱、類的基類、類的名稱空間一併傳給自定義的元類(上面建立的MyMetaClass元類) # metaclass=自定義的元類,自定義的元類繼承了type元類,那麼他就會去呼叫type元類(名稱、類的基類、類的名稱空間) class User(object, metaclass=MyMetaClass): # 被控制類,MyMetaClass(User, (object, ), {"x": 10}) """y is very handsome~""" x = 10 pass
# obj
= User() # 此處呼叫被控制類不傳參,所以上面打印出的args引數為空,即 ()

  此例的需求是:控制建立類的類名字必須首字母大寫而且類內部必須要有註釋,下面開始演示(上面為按照元類的需求來寫,下面開始演示不按照需求來寫)

  演示一:被控制類名字首字母小寫

  執行結果:

  演示二:被控制類中不寫註釋

  執行結果: