元類
Python元類
一.引言:
python語言是一門物件導向的語言,在python中一切皆物件
二 類的兩種建立方式:
一個類的三大組層部分:
1.類名
2.父類
3.三類體程式碼
1.類的建立可以用type方法
#tyoe('類名',(父類,),{名稱空間})
classname = 'yct'
def __init__(self,name,age):
self.name = name
self.age = age
def say():
pass
Person = type('Person',(object,),{classname:'yct','__init':__init__,'say':say})
print(Person.__dict__)
2.類的建立可以用class關鍵字
class Person():
classname = 'yct'
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
pass
print(Person.__dict__)
三、高度化定製類的三種方法
1、new
在python建立類的過程中,會首先呼叫__new__方法返回一個obj物件:
class People():
def __new__(cls, *args, **kwargs):
print(cls)
print(args)
print(kwargs)
obj = object.__new__(cls) # 對於例項化一個類只接受物件的類
print(obj.__dict__) # 此時obj為空
return obj #返回obj物件給__init__方法使用
def __init__(self,name,age): # init為obj物件定製引數
self.name = name
self.age = age
people = People('egon',18)
正如程式碼所示:__new__創造出了物件,但是這個物件是空的,名稱空間的裝備需要通過__init__來完成。
例1:例項化物件的__new__方法
基於例項化物件的__new__方法會創造一個空物件,然後__init__方法進行武裝:
class People():
def __new__(cls, *args, **kwargs):
print(cls)
print(args)
print(kwargs)
obj = object.__new__(cls) # 對於例項化一個類只接受物件的類
print(obj.__dict__) # 此時obj為空
return obj #返回obj物件給__init__方法使用
def __init__(self,name,age): # init為obj物件定製引數
self.name = name
self.age = age
people = People('egon',18)
例2:基於建立類的元類__new__方法:
基於建立類的元類__new__方法,自動傳入類,同時會自動傳入類名,類體,和類的父類方法:
在這裡插入程式碼片class Mymeta(type):
def __new__(cls, classname, father,cls_dict):
print(cls_dict)
if '__doc__'not in cls_dict:
print('類必須要有註釋!')
return
# print(kwargs)
obj =super().__new__(cls,classname,father,cls_dict) # 在 type內部被呼叫創造了obj的有__dict__的物件
# print(obj.__dict__)
print(obj.__dict__) #不為空
return obj
class People(metaclass=Mymeta):
'''天上有多少顆星星'''
school = 'stars'
def __init__(self,name,age):
self.name = name
self.age = age
def say(self):
pass
總結:在對例項化物件時和對類的建立時區別:
1.例項化物件時會返回一個空物件,再交由__init__方法武裝空字典
2.建立類方法時會自動傳入類,類名,父類,名稱空間,type類__init__方法會自動進行武裝
例項:註釋
"""利用元類:第一:類必須有文件註釋,不能為空 第二:在一個類內部定義的所有函式必須有文件註釋,不能為空"""
寫法一:
class MyMetaClass(type):
def __new__(cls, cls_name, cls_bases, cls_dict):
print(cls) #注意:<class '__main__.MyMetaClass'>
if '__doc__' not in cls_dict or len(cls_dict['__doc__'].strip()) == 0:
raise TypeError('類:%s 必須有文件註釋,並且註釋不能為空.' % cls_name)
for key, value in cls_dict.items():
if key.startswith('__'):
continue
if not callable(value):
continue
if not value.__doc__ or len(value.__doc__.strip()) == 0:
raise TypeError('函式:%s 必須有文件註釋,並且文件註釋不能為空.' % (key))
obj = super().__new__(cls,cls_name,cls_bases,cls_dict)
print(obj) #<class '__main__.Person'> 建立出來的就是Person類,是我們需要的.
print('--------名稱空間------')
print(obj.__dict__)
return obj
def __init__(self,cls_name, cls_bases, cls_dict):
print(self) #<class '__main__.Person'>
#接下來我們初始化這個物件
super().__init__(cls_name,cls_bases,cls_dict)
class Person(object,metaclass=MyMetaClass): #這一行: Person = MyMetaClass('Person',(object,),{...})
"""
元類.
"""
country = 'China'
def __init__(self,name,age):
self.name = name
self.age = age
def tell_info(self):
"""
繫結方法.
"""
print('%s 的年齡是:%s'%(self.name,self.age))
方法二:
class Mymeta(type):
def __new__(cls, classname, father,cls_dict):
print(cls_dict)
if '__doc__'not in cls_dict or cls_dict['__doc__'] is None:
raise TypeError('類的建立必需要有註釋')
for key,values in cls_dict.items():
if callable(values):
if values.__doc__ is None:
raise TypeError('方法下必要要有註釋')
obj =super().__new__(cls,classname,father,cls_dict)
# print(obj.__dict__)
print(obj.__dict__)
return obj
class People(metaclass=Mymeta):
'''類下注釋'''
school = 'stars'
def __init__(self,name,age):
self.name = name
self.age = age
def say(self):
pass
2.、init (__init__方法)
(暫時省略)
3、call (元類對類例項化行為的影響):
1.一個可呼叫物件加括號實際上是呼叫對物件下的__call__方法,反之一個可以呼叫的物件,他的類中必有__call__方法.
2.要想讓某個物件變成一個可呼叫的物件,需要在該物件的類中定義一個方法__call__方法。
例1.例項化物件
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def __call__(self, *args, **kwargs): # ==>給例項化物件使用
print('呼叫我')
student = Person('ww',199)
"""如果沒有__call__:TypeError: 'Student' object is not callable"""
print(callable(student))
print(student()) #一個可呼叫的物件加括號,就是觸發這個物件所在類中的__call__方法的執行
在此處,我們可以明白,如果類可以被呼叫,則元類中必然存在一個__call__方法!!!
class Mymeta(type):
pass
class People(metaclass=Mymeta):
def __init__(self,name,age):
self.name = self.name
self.age = self.age
def say(self):
pass
print(People.__dict__)
# 在Mymeta中必然有一個__call__方法,如果沒有定義則自動呼叫父類
例2:重寫Type類方法
class Mymeta(type):
def __call__(self, *args, **kwargs):
print(self)
print(args)
print(kwargs)
return 1
class People(metaclass=Mymeta):
def __init__(self,name,age):
self.name = self.name
self.age = self.age
def say(self):
pass
people = People('egon',18)
print(people)
此處我們可以發現call方法會將實參傳入,其返回值就是people的返回值,在此處people = 1
所以在此我們可以下一個結論,__call__是對類的例項化進行管控,對例項化物件字典的增刪改查就是在call內部進行的,最後返回了一個字典。此字典就是物件下的屬性
PYTHON中,call,init,__new__三者之間的關係
一個類在例項化的時候實際上是做了三件事情:
1.在呼叫產生類時會自動呼叫__call__類
2.在__call__呼叫中會呼叫類物件自己中的__new__方法
3.在__new__方法返回物件後自動呼叫__init__方法
4.將得到的obj結果返回給物件
相關文章
- 元類:Metaclass
- Python 元類Python
- Python元類與列舉類Python
- 23. 元類
- Python的元類Python
- 元類詳解
- Python如何自定義元類Python
- 由ORM談Python元類ORMPython
- 理解Python中的元類Python
- 類别範本與友元
- 友元類的使用方法
- OC底層原理之例項、類物件、元類物件物件
- 【Spark篇】---SparkStreaming中運算元中OutPutOperator類運算元Spark
- 2.1.5 Python元類深刻理解(metaclass)Python
- Python學習之路41-元類Python
- Spark----RDD運算元分類 DAGSpark
- python面試題~反射,元類,單例Python面試題反射單例
- Python 的元類設計起源自哪裡?Python
- 元學習:人類與大模型比較建模大模型
- Java單元測試常用工具類小結Java
- iOS開發·runtime原理與實踐: 基本知識篇(類,超類,元類,super_class,isa,物件,方法,SEL,IMP)iOS物件
- C++類將函式模板宣告為友元 例項C++函式
- 面試驅動技術之 - isa && 元類 && 函式呼叫面試函式
- 面試驅動技術之 – isa && 元類 && 函式呼叫面試函式
- 【ML系列】簡單的二元分類——Logistic迴歸
- Python進階丨如何建立你的第一個Python元類?Python
- 定義Point類,採用友元類的方式計算兩個點之間的水平和垂直距離
- Python 元類機制的工作流程及引數呼叫的不同Python
- ML.NET 示例:二元分類之垃圾簡訊檢測
- 如何用機器學習處理二元分類任務?機器學習
- 開闢“啟元like”新賽道,它正在SLG品類掀起全面革命
- JS正規表示式從入門到入土(2)—— 元字元和字元類JS字元
- 元宇宙收藏養成類遊戲設計說明(邏輯及步驟)元宇宙遊戲設計
- Pytorch實戰-logistic 迴歸二元分類程式碼詳細註釋PyTorch
- 利用App漏洞獲利2800多萬元,企業該如何避免類似事件?APP事件
- 【java】Maths類、Random類、System類、BigInteger類、BigDecimal類、Date類、SimpleDateFormat類JavarandomDecimalORM
- 阿里雲優惠3年279元/800元/797元/1650元/1615元阿里
- Python之難點元類|一句話給你安排的明明白白Python