網(wǎng)站首頁 編程語言 正文
前言
學(xué)習(xí)python時,對 meta class 并不陌生,django 的model, form定義中經(jīng)常會遇到class Meta 的代碼, 但 django中沒有介紹模型與表單中的 meta 屬性是怎么回事。 python的眾多教程,也很少有作者提到,或把meta class 講清楚,造成大家以為metaclass 很難理解。 今天我嘗試用實(shí)例代碼的方式,讓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的數(shù)據(jù)類型是類對象,甚至函數(shù)本身也是對象。 Python object 是所有類型的基類,各種數(shù)據(jù)類型, 函數(shù), class 都是object 的派生類,因此,從object的概念上推理,存在某些 class ,其可以生成其它c(diǎn)lass, 這種 class 就稱為meta class., 也稱元類.
本文將討論meta class的定義,以及使用方式。 內(nèi)容共包含3個主題:
- 用 type 定義類
- 如何編寫 Metaclass
- Metaclass 的實(shí)際應(yīng)用
Type 來定義類
1個 class 也是1個object, 其包含若干屬性,以及一些方法。 type () 通常用來顯示 變量與函數(shù)的類型,但也可以用type 來創(chuàng)建 class. 下面我們來演示這一過程。
首先,先用標(biāo)準(zhǔn)的方式,class關(guān)鍵字來創(chuàng)建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來創(chuàng)建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:
蛋炒飯
要創(chuàng)建一個class對象,type()
函數(shù)依次傳入3個參數(shù):
- 第1個參數(shù)是string類型,class的名稱;
- 第2個參數(shù)是1個tuple , (object, ) , 指定繼承的父類是 object,注意支持多重繼承,如果只有一個父類,后面是加個 , 號;
- 第3個參數(shù)是 dictionary 類型, 指定 class的屬性與方法名稱,這里我們把函數(shù)init綁定到方法名
__init__
上
通過type()
函數(shù)創(chuàng)建的類和直接寫class是完全一樣的,因?yàn)镻ython解釋器遇到class定義時,僅僅是掃描一下class定義的語法,然后調(diào)用type()
函數(shù)創(chuàng)建出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. 因此,如前一節(jié)的示例 ,metaclass 也可以用來創(chuàng)建類。
用metaclass后, 關(guān)于類的編程過程: 先定義metaclass,就可以創(chuàng)建類,最后創(chuàng)建實(shí)例。
所以,metaclass允許你創(chuàng)建類或者修改類。換句話說,你可以把類看成是metaclass創(chuàng)建出來的“實(shí)例”。
metaclass的定義過程,主要是實(shí)現(xiàn) __new__
方法,有4個傳入?yún)?shù), 與 type創(chuàng)建類的參數(shù)相似
- metaclass 自身
- 類名
- 父類( tuple 類型)
- 類的屬性與方法字典
metaclass還可以實(shí)現(xiàn)1個 __call__
方法,在該類被調(diào)用時執(zhí)行此方法。
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的實(shí)例對象 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類的實(shí)例 化過程,example可以添加自己的方法,可以修改從父類繼承的屬性。
metaclass應(yīng)用
實(shí)際開發(fā)中遇到的metaclass是django中定義model, form時,可以定義metaclass的屬性,其實(shí)就是django的ORM使用了 metaclass的編程方式,由于其實(shí)現(xiàn)較復(fù)雜,就不深入討論。
這里我們來看1個更簡單,而且非常實(shí)用的metaclass的例子: 用metaclass實(shí)現(xiàn)單例模式。
單例模式提供了這樣一個機(jī)制,即確保類有且只有一個特定類型的對象,并提供全局 訪問點(diǎn)。因此,單例模式通常用于下列情形,例如日志記錄或數(shù)據(jù)庫操作、打印機(jī)后臺處 理程序,以及其他程序—該程序運(yùn)行過程中只能生成一個實(shí)例,以避免對同一資源產(chǎn)生 相互沖突的請求。
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 雖然分別實(shí)例化,但內(nèi)存中的地址都指向同1個SingletonClass對象,這樣就實(shí)現(xiàn)了單例化。
而且metaclass實(shí)現(xiàn)單例模式,比 object方式實(shí)現(xiàn)的單例化有明顯的優(yōu)勢,任何類都可以通過繼承SingletonMeta實(shí)現(xiàn)單例模式, 是不是很酷.
原文鏈接:https://blog.csdn.net/captain5339/article/details/128016007
相關(guān)推薦
- 2022-04-25 SpringBoot集成redis錯誤問題及解決方法_Redis
- 2022-03-14 servlet已經(jīng)配置url映射,提示Servlet should have a mapping a
- 2022-12-13 深入了解Rust的生命周期_Rust語言
- 2022-03-25 Postman如何導(dǎo)出接口的幾種方法(postman怎么把接口導(dǎo)出來)
- 2023-02-06 Python利用Pytorch實(shí)現(xiàn)繪制ROC與PR曲線圖_python
- 2022-07-24 Golang實(shí)現(xiàn)可重入鎖的示例代碼_Golang
- 2022-12-10 C++的std::vector<bool>轉(zhuǎn)儲文件問題_C 語言
- 2023-03-03 詳解Flask框架中Flask-Login模塊的使用_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支