日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Python?Metaclass原理與實現過程詳細講解_python

作者:雕弓 ? 更新時間: 2022-12-26 編程語言

前言

學習python時,對 meta class 并不陌生,django 的model, form定義中經常會遇到class Meta 的代碼, 但 django中沒有介紹模型與表單中的 meta 屬性是怎么回事。 python的眾多教程,也很少有作者提到,或把meta class 講清楚,造成大家以為metaclass 很難理解。 今天我嘗試用實例代碼的方式,讓metaclass 更容易理解與使用。

class Person(models.Model):
    cname = models.CharField(max_length=30, verbose_name="姓名")
    user = models.ForeignKey(
        get_user_model(), null=True, on_delete=models.CASCADE)
    birth_date = models.DateField(verbose_name="出生日期")
    def __str__(self):
        return self.cname
    class Meta:
        verbose_name = "人員信息"
        db_table = "tbl_person"

Python與java 一樣,宣稱自己一切皆對象,且有過之而不及。python的數據類型是類對象,甚至函數本身也是對象。 Python object 是所有類型的基類,各種數據類型, 函數, class 都是object 的派生類,因此,從object的概念上推理,存在某些 class ,其可以生成其它class, 這種 class 就稱為meta class., 也稱元類.

本文將討論meta class的定義,以及使用方式。 內容共包含3個主題:

  • 用 type 定義類
  • 如何編寫 Metaclass
  • Metaclass 的實際應用

Type 來定義類

1個 class 也是1個object, 其包含若干屬性,以及一些方法。 type () 通常用來顯示 變量與函數的類型,但也可以用type 來創建 class. 下面我們來演示這一過程。

首先,先用標準的方式,class關鍵字來創建1個 Food 類。

class Food(object):
    def __init__(self, food):
        self.food = food
    def get_food(self):
        return self.food
def main():
    myfood = Food(food='蛋炒飯')
    print(myfood.get_food())
main()

output

蛋炒飯

下面演示如何用 type來創建1個Food 類

def init(self, food):
    self.food = food
def get_food(self):
    return self.food
Food = type("Food", (object,),  {
    '__init__': init,
    'get_food': get_food,
})
myfood = Food(food="蛋炒飯")
print(myfood.get_food())

output:

蛋炒飯

要創建一個class對象,type()函數依次傳入3個參數:

  • 第1個參數是string類型,class的名稱;
  • 第2個參數是1個tuple , (object, ) , 指定繼承的父類是 object,注意支持多重繼承,如果只有一個父類,后面是加個 , 號;
  • 第3個參數是 dictionary 類型, 指定 class的屬性與方法名稱,這里我們把函數init綁定到方法名__init__

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

用 type來增加1個子類VegFood, 其父類為Food

def init(self, food):
    self.food = food
def get_food(self):
    return self.food
Food = type("Food", (object,),  {
    '__init__': init,
    'get_food': get_food,
})
def get_vegfood(self):
    return {'清炒菠菜', '干煸豆角'}
# 新建子類,父類為Food
VegFood = type("VegFood", (Food,), {
    "get_vegfood": get_vegfood,
})
veg = VegFood(food="蛋炒飯")
print(veg.get_food())
print(veg.get_vegfood())

output:

蛋炒飯
{'干煸豆角', '清炒菠菜'}

可以看到,子類 VegFood可以繼承 父類Food的方法get_food(),也可以使用子類的方法 get_vegfood()

編寫 meta class

metaclass,直譯為元類,繼承自type. 因此,如前一節的示例 ,metaclass 也可以用來創建類。

用metaclass后, 關于類的編程過程: 先定義metaclass,就可以創建類,最后創建實例。

所以,metaclass允許你創建類或者修改類。換句話說,你可以把類看成是metaclass創建出來的“實例”。

metaclass的定義過程,主要是實現 __new__ 方法,有4個傳入參數, 與 type創建類的參數相似

  • metaclass 自身
  • 類名
  • 父類( tuple 類型)
  • 類的屬性與方法字典

metaclass還可以實現1個 __call__方法,在該類被調用時執行此方法。

metacalss 示例 :

class MetaCls(type):
    """metaclass的示例"""
    def __new__(cls, clsname, superclasses, attributedict):
        print("clsname:", clsname)
        print("superclasses:", superclasses)
        print("attrdict:", attributedict)
        return super(MetaCls, cls).__new__(cls,
                                           clsname, superclasses, attributedict)
def demo(self):
    print("Info from demo method")
# generate a class, Example 
Example = MetaCls('Example', (object, ), {"demo": demo, })
Example.clsname = "ExampleClass"  # 修改 metaclass的屬性值 
print("class type:", type(Example))
myexample = Example()             # 新建1個Example的實例對象
print(myexample.clsname)          # 打印父類屬性值
myexample.demo()                  # 打印子類方法

output

clsname: Example
superclasses: (<class 'object'>,)
attrdict: {'demo': <function demo at 0x00000169DF2CC280>}
class type: <class '__main__.MetaCls'>
ExampleClass
Info from demo method

從上例 可以看到, Example類的生成方式,就是 MetaCls類的實例 化過程,example可以添加自己的方法,可以修改從父類繼承的屬性。

metaclass應用

實際開發中遇到的metaclass是django中定義model, form時,可以定義metaclass的屬性,其實就是django的ORM使用了 metaclass的編程方式,由于其實現較復雜,就不深入討論。

這里我們來看1個更簡單,而且非常實用的metaclass的例子: 用metaclass實現單例模式。

單例模式提供了這樣一個機制,即確保類有且只有一個特定類型的對象,并提供全局 訪問點。因此,單例模式通常用于下列情形,例如日志記錄或數據庫操作、打印機后臺處 理程序,以及其他程序—該程序運行過程中只能生成一個實例,以避免對同一資源產生 相互沖突的請求。

class SingletonMeta(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(
                SingletonMeta, cls).__call__(*args, **kwargs)
        return cls._instances[cls]
class SingletonClass(metaclass=SingletonMeta):
    pass
s = SingletonClass()
print("Object created", s)
s1 = SingletonClass()
print("Object created", s1)

output :

Object created <__main__.SingletonClass object at 0x0000020CF1F20130>
Object created <__main__.SingletonClass object at 0x0000020CF1F20130>

可以看到,SingletonMeta用metaclass的方法定義了1個單例類, SingletonClass繼承自SingletonMeta, s 與 s1 雖然分別實例化,但內存中的地址都指向同1個SingletonClass對象,這樣就實現了單例化。

而且metaclass實現單例模式,比 object方式實現的單例化有明顯的優勢,任何類都可以通過繼承SingletonMeta實現單例模式, 是不是很酷.

原文鏈接:https://blog.csdn.net/captain5339/article/details/128016007

欄目分類
最近更新