python高級(jí)之元類(lèi)的用法總結(jié)
一、Type創(chuàng)建類(lèi)
class A(object):
def __init__(self, name):
self.name = name
def __new__(cls, *args, **kwargs):
data = object.__new__(cls)
return data
根據(jù)類(lèi)創(chuàng)建對(duì)象
obj=A(‘kobe’)
1、執(zhí)行類(lèi)的new方法,創(chuàng)建對(duì)象(空對(duì)象),【構(gòu)造方法】 {}
2、執(zhí)行類(lèi)的init方法,初始化對(duì)象 ,【初始化方法】 {‘name’:‘kobe’}
對(duì)象是基于類(lèi)創(chuàng)建出來(lái)的;問(wèn)題:類(lèi)是由誰(shuí)創(chuàng)建的?
類(lèi)默認(rèn)是由type創(chuàng)建的
1、傳統(tǒng)方式創(chuàng)建類(lèi)
class A(object):
v1 = 123
def func(self):
return 666
print(A) #<class '__main__.A'>
2、非傳統(tǒng)方式
類(lèi)名
繼承類(lèi)
成員
A1 = type('A', (object,), {"v1": 123, "func": lambda self: 666})
print(A1) #<class '__main__.A'>
# 根據(jù)類(lèi)創(chuàng)建對(duì)象
obj1 = A1() #<__main__.A object at 0x0000017049D035E0>
print(obj1)
# 調(diào)用對(duì)象中的func方法
print(obj1.func()) #666
類(lèi)默認(rèn)由type創(chuàng)建,怎么讓一個(gè)類(lèi)的創(chuàng)建改為其他的東西呢? 元類(lèi)。
二、元類(lèi)
元類(lèi):指定類(lèi)由誰(shuí)來(lái)創(chuàng)建
1、Foo類(lèi)由MyType創(chuàng)建,代碼如下
class MyType(type):
pass
# Foo類(lèi)由MyType創(chuàng)建
class Foo(object, metaclass=MyType):
pass
2、假設(shè)Foo是一個(gè)對(duì)象,它是由MyType類(lèi)創(chuàng)建。
class MyType(type):
def __init__(self, *args, **kwargs):
print('init')
super().__init__(*args, **kwargs)
def __new__(cls, *args, **kwargs):
# 創(chuàng)建類(lèi)
print('new')
new_cls = super().__new__(cls, *args, **kwargs)
print(new_cls)
return new_cls
# 假設(shè)Foo是一個(gè)對(duì)象,由MyType類(lèi)創(chuàng)建。
class Foo(object, metaclass=MyType):
pass
執(zhí)行結(jié)果
new
<class '__main__.Foo'>
init
3、類(lèi)加括號(hào)得到的是對(duì)象,執(zhí)行的是__init__()和__new__()方法,對(duì)象加括號(hào)執(zhí)行__call__()方法
class F1(object):
def __init__(self):
print('init')
# def __new__(cls, *args, **kwargs):
# print('new')
def __call__(self, *args, **kwargs):
print(111)
# 類(lèi)加括號(hào)得到的是對(duì)象,執(zhí)行的是__init__和__new__方法
obj = F1()
# 對(duì)象加括號(hào)執(zhí)行call方法
obj()
執(zhí)行結(jié)果
init
111
4、假設(shè)Foo是一個(gè)對(duì)象,由MyType創(chuàng)建。
Foo類(lèi)其實(shí)是MyType的一個(gè)對(duì)象。
Foo() 加括號(hào)執(zhí)行的是——》MyType類(lèi)中的__call__()方法
__call__()方法實(shí)現(xiàn)的功能是:
1、調(diào)用自己那個(gè)類(lèi)的__new__方法創(chuàng)建對(duì)象
empty_object=self.__new__(self)
2、調(diào)用你自己那個(gè)類(lèi)__init__方法去初始化對(duì)象
self.__init__(empty_object,*args,**kwargs)3、將創(chuàng)建的對(duì)象返回:return empty_object
class MyType(type):
def __init__(self, *args, **kwargs):
print('init')
super().__init__(*args, **kwargs)
def __new__(cls, *args, **kwargs):
# 創(chuàng)建類(lèi)
print('new')
new_cls = super().__new__(cls, *args, **kwargs)
print(new_cls)
return new_cls
def __call__(self, *args, **kwargs):
# 1、調(diào)用自己哪個(gè)類(lèi)的__new__方法創(chuàng)建對(duì)象
empty_object=self.__new__(self)
#2、調(diào)用你自己那個(gè)類(lèi) __init__方法去初始化
self.__init__(empty_object,*args,**kwargs)
return empty_object
# 假設(shè)Foo是一個(gè)對(duì)象,由MyType創(chuàng)建。
# Foo類(lèi)其實(shí)是MyType的一個(gè)對(duì)象。
# Foo() ——》MyType對(duì)象()
class Foo(object, metaclass=MyType):
def __init__(self,name):
self.name=name
v1=Foo('666')
print(v1)
print(v1.name)三、總結(jié)
1、當(dāng)我們不寫(xiě)MyType類(lèi)時(shí),Type中已經(jīng)幫我們定義好了__init____new____call__ 方法了
當(dāng)我定義了MyType類(lèi)時(shí),__init____new____call__ 方法是我們自己定義的
2、這就是為什么實(shí)例化對(duì)象的時(shí)候,先去創(chuàng)建對(duì)象再去初始化對(duì)象,Type類(lèi)中已經(jīng)實(shí)現(xiàn)了先 __new__()再__init__()

3、代碼從上到下執(zhí)行,當(dāng)執(zhí)行到class Foo(object, metaclass=MyType)時(shí)
先創(chuàng)建這個(gè)類(lèi),去MyType中的__new__()創(chuàng)建方法
__init__()實(shí)例化方法,類(lèi)在內(nèi)存中創(chuàng)建好了,
但是MyType中的__call__()方法是不執(zhí)行的,因?yàn)轭?lèi)后面沒(méi)有加括號(hào)
如果類(lèi)后面加了括號(hào)Foo(),會(huì)執(zhí)行MyType的__call__()方法

4、如果自己定義的類(lèi)中實(shí)現(xiàn)了__call__方法,此時(shí)是不會(huì)執(zhí)行的,因?yàn)镕oo是MyType創(chuàng)建出來(lái)的

5、如果要執(zhí)行Foo類(lèi)的__call__方法,需要實(shí)例化Foo類(lèi)的對(duì)象v1,
然后v1加括號(hào)

附:元類(lèi)的最佳實(shí)踐和注意事項(xiàng)
最佳實(shí)踐
僅在必要時(shí)使用元類(lèi)。元類(lèi)是高級(jí)編程工具,通常不需要在日常編程中使用。
考慮繼承自type以定義元類(lèi),因?yàn)閠ype是Python中的內(nèi)置元類(lèi)。
在元類(lèi)的__new__方法中,要返回一個(gè)類(lèi)對(duì)象,通常是使用super().__new__來(lái)創(chuàng)建它。
注意事項(xiàng)
元類(lèi)可以控制類(lèi)的創(chuàng)建和初始化,但要小心不要過(guò)度使用,以免使代碼變得復(fù)雜和難以理解。
在元類(lèi)中的操作可能會(huì)影響所有使用該元類(lèi)創(chuàng)建的類(lèi),因此要小心不要引入意外的副作用。
元類(lèi)的概念可能對(duì)初學(xué)者來(lái)說(shuō)有點(diǎn)復(fù)雜,建議在熟悉Python的基礎(chǔ)之后再深入學(xué)習(xí)元類(lèi)。
總結(jié)
到此這篇關(guān)于python高級(jí)之元類(lèi)用法總結(jié)的文章就介紹到這了,更多相關(guān)python高級(jí)之元類(lèi)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入理解Python單元測(cè)試unittest的使用示例
本篇文章主要介紹了深入理解Python單元測(cè)試unittest的使用示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11
Python獲取excel的數(shù)據(jù)并繪制箱型圖和直方圖的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于Python獲取excel的數(shù)據(jù)并繪制箱型圖和直方圖的相關(guān)資料,好的圖表能幫助我們深化數(shù)據(jù)的記憶點(diǎn),文中通過(guò)圖文以及代碼示例將實(shí)現(xiàn)的方法介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12
python3實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲(chóng)之BeautifulSoup使用詳解
這篇文章主要介紹了python3實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲(chóng)之BeautifulSoup使用詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
Python Opencv提取圖片中某種顏色組成的圖形的方法
這篇文章主要介紹了Python Opencv提取圖片中某種顏色組成的圖形的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
詳解Python3.6安裝psutil模塊和功能簡(jiǎn)介
這篇文章主要介紹了詳解Python3.6安裝psutil模塊和功能簡(jiǎn)介,詳細(xì)的介紹了安裝psutil模塊和該模塊的使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05
Python?Requests使用Cookie的幾種方式詳解
這篇文章主要給大家介紹了關(guān)于Python?Requests使用Cookie的幾種方式,Python中的requests庫(kù)可以使用cookie來(lái)維持會(huì)話(huà)狀態(tài),實(shí)現(xiàn)登錄等操作,需要的朋友可以參考下2023-07-07
python進(jìn)行數(shù)據(jù)預(yù)處理的4個(gè)重要步驟
在數(shù)據(jù)科學(xué)項(xiàng)目中,數(shù)據(jù)預(yù)處理是最重要的事情之一,本文詳細(xì)給大家介紹python進(jìn)行數(shù)據(jù)預(yù)處理的4個(gè)重要步驟:拆分訓(xùn)練集和測(cè)試集,處理缺失值,處理分類(lèi)特征和進(jìn)行標(biāo)準(zhǔn)化處理,需要的朋友可以參考下2023-06-06
Python count函數(shù)使用方法實(shí)例解析
這篇文章主要介紹了Python count函數(shù)使用方法實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03

