日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python元类简述

發布時間:2025/3/20 python 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python元类简述 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

面向對象編程

python 是一門按照面向對象思維設計的一門編程語言,而理解面向對象的語言關鍵在于一句話,“一切皆對象”,函數是一個對象,一個實例是對象,一個類也是對象。如果對象被創建了,那么在這個程序管理的內存區域中,就會真實的存在一片區域去保存這個對象的信息。因此,我們在代碼中定義一個函數,定義一個類,即使我們并沒有調用這個函數或者去實例化這個類,在內存空間中,也已經存在了這個函數對象和類對象。例如下面的代碼。

class A:def __init__(self, a, b):self.a = aself.b = b

代碼執行后,內存中會創建一個類對象,且類對象上顯式的綁定了__init__方法。

我們使用class A: pass這樣的語句可以定義一個類,但是我們并沒有在意它是如何被創建的,實際上這個語句的完整寫法為

class A(metaclass=type):pass

這里metaclass=type 的意思是這個A類使用type類來創造,也就是使用type類作為他的元類,如果我們不聲明,就默認使用type來創建這個類,而type也是一個類對象,這個類對象的功能,就是創建一個類,所以他與我們自己定義的普通的類又有所區別,所以有了metaclass,也就是元類的稱呼。

何為元類

元類:簡單的一句話就是創建類的類。首先元類也是一個類,,所以元類也是由另一個元類創建的,但是創建一個元類必須指定這個元類將繼承哪個元類。下面看一些元類和普通類的區別。

''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class MetaclassA(type): # 繼承type類,并由type類創建,定義了一個元類passclass MetaclassB(MetaclassA): # 繼承MetaclassA,由type創建,定義了一個元類passclass MetaclassB(MetaclassA, metaclass=MetaclassB): # 繼承MetaclassA,由MetaclassBpass class C: # 由type 類創建,繼承object。是一個普通類passclass D(metaclass=MetaclassA): # 由metaclassA 創建,繼承object,是一個普通類pass

總結為兩點

  • 類在創建時可以指定自己被哪個元類創建,使用metaclass參數指定一個元類即可,沒指定默認為type元類
  • 定義的類是普通類還是元類,看他是直接繼承自元類及其子類,還是繼承自object及其子類。

元類的作用

元類的各類框架中使用較為廣泛,由于自定義元類的參與,使得我們自己定義的類在創建時候,可以方便的進行一些自定義的初始化,完成我們想要的功能。在日常的編碼中的一般很少使用元類,但是在閱讀源碼的過程中卻常遇到,作者利用元類做一些非常精巧的設計去實現使用其他方法很難完成得功能。從下面的使用中體會元類的使用

元類的使用

默認情況下,類的創建都是交給 type元類 去創建,創建后的類有自己的默認的一些屬性和方法,也有一部分從object類繼承的屬性和方法。如果我們想要在需要定義一個元類來實現類的自定義初始化,就必須繼承自type或者及其子類。type類中默認創建類對象的方法為__new__(cls) 方法。我們可以重寫這個方法。

class MetaClassA(type):def __new__(mcs, name, base, attrs):'''mcs,這個元類對象自己name:將要被創建的類的名字,下面的代碼中 定義了一個 A 類,則這個name 為 "A" 這個字符串base: 被創建的類如果指定了需要繼承某個類,base中將會紀錄他所有的父類對象。attrs:被創建的類中定義的類屬性和方法的字典,字典的key 為屬性的變量名,value為對應的屬性值'''# 查看這四個參數的值print(mcs, name, base, attrs) # 類名,父類元組,類屬性字典。'''輸出的值msc: <class '__main__.Metaclass'>name: Abase: (<class 'object'>,)attrs: {'__module__': '__main__', '__qualname__': 'A', 'xxx': 1, 'x': <function A.<lambda> at 0x00000232DFF34620>, 'Meta': <class '__main__.A.Meta'>, '__init__': <function A.__init__ at 0x00000232DFF346A8>}'''# 查看參數值后,需要調用type類的new方法創建因為python 只提供了type元類來調用系統調用來申請內存空間,創建一個類對象并返回cls = type.__new__(mcs, name, base, attrs)# 返回值則是 A 這個類對象,我們可以使用dir查看類中的屬性和方法,可以看到 上面attrs中的值,并新增了很多k-v對print(cls, dir(cls))return cls # 必須使用 return 將這個類對象的返回,下面定義的class A 的 A 變量才能收到這個cls 對象,否則 A 的值為None, 即使使用了class A這個語法。# 我們使用MetaClassA 創建 類A class A(object, metaclass=MetaclassA):# 為 A定義兩個類屬性xxx = 1yyy = lambda x: x + 1# 定義一個類, 這個類的也是A類的一個屬性,可以通過A.Meta訪問到這個類對象class Meta:x = []y = 1# 定義一個方法def __init__(self):self.a = 1 self.b = 2

通過上面的代碼可以了解 一個類創建 的過程,在metaclassA的 ?__new__()?方法中,我們獲取到了在 A 類中定義的所有類屬性和方法,這些屬性和方法都被收集到attrs 這個字典中,并交給type.__new__()方法用于創建類,所以想要操作類中的屬性和方法,可以對attr字典進行想要的操作。例如我們為所有的類都添加一個方法。

''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' def func():print("我是被 MetaClassA 創建的")class MetaClassA(type):def __new__(mcs, name, base, attrs):print(mcs, name, base, attrs) # 類名,父類元組,類屬性字典。attrs["show"] = func # 將func 這個函數添加到A 的方法中,這樣 A 類會有一個show方法,調用后會執行func函數。return type.__new__(mcs, name, base, attrs)

動態的創建類

動態的創建類 是指 直接通過 元類的方法來創建類,而不在使用 class 這個關鍵字來創建類對象。
使用關鍵字定義

class A:a = 1b = 2def show(self):pass

動態的創建

A = type.__new__(type, "A", (), {"a":1, "b":2, "show": lambda :pass})

這樣的代碼和上述的結果是相同的,或者還可以使用更直接的方法。我們知道普通類創建實例時候,可以ins = ClassName(*args)的方式創建一個實例對象 ins,同樣,元類也可以如此創造一個類

A = type("A", (), {"a":1, "b":2, "show": lambda :pass})

對一個元類使用類似實例化的方法,得到了一個類對象。

綜合一下:

''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:778463939 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' class Metaclass(type):def __new__(cls, class_name: str, bases: tuple, attrs: dict):print(1, cls)print(2, class_name)print(3, bases)return type.__new__(cls, class_name, bases, attrs)# 1. 創建一個類名為 A 的類, class A(metaclass=Metaclass):a = 100# 2. 創建一個類名為 B 的類,使用 BClass變量接收 BClass = Metaclass.__new__(Meta, 'B', (), {"a":100}) # 創建一個B類 print(BClass)# 3. 創建一個類名為 C 的類,,使用 CClass變量接收 CClass = Metaclass("C", (BClass, ), {"a": 100}) # 創建一個C類,并繼承B類 print(CClass)

上面三個類的創建過程完全一致,處理類名不同和內存中的儲存的地址不同,所擁有的屬性和方法都是一樣的。

元類的使用實例(django-orm中元類的簡單使用原理)

Django的ORM中的Model類使用了元類來實現“表-類”,“實例-一條記錄”,“實例屬性-字段”的對應關系

class MetaModel(type):def __new__(mcs, class_name: str, bases: tuple, attrs: dict):# 收集所有的字段,并添加一些默認需要的屬性,并提取設置為主鍵的 字段attrs.setdefault("db_table", class_name.lower()) # 設置表名for key, field in attrs:if isinstance(field, Field):if field.pk: # 該字段被設置了主鍵,定義設置主鍵名字__primary__ = field.name or key if not field.name: # 沒有自定義名字,使用屬性名作為在field.name = keyreturn type.__new__(mcs, class_name, bases, attrs)# 字段對象,記錄可字段的名字,類型,是否為null, 是否為主鍵等等元信息,和數據庫中字段的元數據對應 class Field:def __init__(self, name=None, typ="varchar", null=None, primary_key=False):self.name = nameself.type = typself.null = nullself.pk = primary_keydef __repr__(self):return "<{}-{}-{}-{}>".format(self.name, self.type, self.null, self.pk)# 表對象,每一個類屬性就是一個字段對象 class Person(metaclass=MetaModel):# 創建這個類時候,將會調用 MetaModel的new方法,這樣定義的每個字段都會被 metaclass中attrs 收集并操作id = Field("id", primary_key=True)name = Field("name", )age = Field("age", null=False)

通過使用元類,在我們將這個Person類屬性字典進行了操作,自動建立了一些屬性信息,例如db_table將使用該名字作為數據庫中表名,指定了屬性__primary__作為主鍵。類似于Django中的做法,這里只是簡單的演示元類的應用。

總結

以上是生活随笔為你收集整理的python元类简述的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。