目錄
- 面向物件之元類
- 一、什么是元類
- 二、元類推導流程
- 三、創建類的方式
- 方式一:
- 方式二:
- 四、元類定制類的產生行為
- 五、元類定制物件的產生行為
- 六、元類之雙下new
面向物件之元類
一、什么是元類
- Python中一切皆為物件,物件是有類實體化生成;
- 類也是物件(類物件),生成類物件的類可稱之為元類;
- 所以,元類就是來創建類物件的,可稱之為類工廠;
- type是python內建元類,type是最上層的元類,也可稱為一切類物件的元類
二、元類推導流程
"""推導步驟1:如何查看資料的資料型別"""
# s1 = 'hello world' # str()
# l1 = [11, 22, 33, 44] # list()
# d1 = {'name': 'jason', 'pwd': 123} # dict()
# t1 = (11, 22, 33, 44) # tuple()
# print(type(s1)) # <class 'str'>
# print(type(l1)) # <class 'list'>
# print(type(d1)) # <class 'dict'>
# print(type(t1)) # <class 'tuple'>
"""推導步驟2:其實type方法是用來查看產生物件的類名"""
# class Student:
# pass
# obj = Student()
# print(type(obj)) # <class '__main__.Student'>
"""推導步驟3:python中一切皆物件 我們好奇type查看類名顯示的是什么"""
class Student:
pass
obj = Student()
print(type(obj)) # <class '__main__.Student'>
print(type(Student)) # <class 'type'>
class A:pass
class B:pass
print(type(A), type(B))
"""
結論:我們定義的類其實都是由type類產生的>>>:元類(產生類的類)
"""
三、創建類的方式
方式一:
創建方法:
? 直接使用class關鍵字創建
class Foo:
school_name = 'kangkang
def func1(self):
pass
print(Teacher)
print(Teacher.__dict__)
方式二:
創建方法:
? 使用元類type
? type(類名, 類的父類, 類的名稱空間)
cls = type('Student', (object,), {'name':'jason'})
print(cls)
print(cls.__dict__)
"""
1.手動寫鍵值對
針對系結方法不好定義
2.內置方法exec
能夠運行字串型別的代碼并產生名稱空間
"""
四、元類定制類的產生行為
? 通過上述推導,我們得出了我們所創建的類,其實就是type幫我們所生成的,那么我們是否可以通過繼承type(元類)的方式,來研究type底層代碼原理,來改修,新增條件,來定制類的生成
例如:
? 生成類時,類名的首字母必須大寫,否則報錯
推導流程:
"""
推導
1、物件是由類名加括號產生的 __init__
2、類是由元類加括號產生的 __init__
3、查看type底層原始碼,找到__init__
__init__(cls, what, bases=None, dict=None)
cls:元類本身
what:需要產生的類名
bases:產生類的父類
dict:類體名稱空間
4、通過上述我們就可以發現what可以控制類名的產生
"""
# 1、首先生成一個類,繼承元類(type)
class MyMetaClass(type):
pass
# 2、在類中,創建def __init__(self, what, bases=None, dict=None):
# 3、對限制what產生類名的條件
class MyMetaClass(type):
def __init__(self, what, bases=None, dict=None):
# 設定條件,未滿足時,主動拋出例外并提示
if not what.istitle():
raise TypeError('類的首字母要大寫')
# 條件滿足后呼叫父類進行產生
super().__init__(what, bases, dict)
# 4、指定類的元類:利用關鍵字metaclass指定類的元類
class myclass(metaclass=MyMetaClass):
desc = '元類其實很有趣 就是有點繞'
class Student(metaclass=MyMetaClass):
info = '我是學生 我很聽話'
print(Student)
print(Student.__dict__)
# 5、這個時候我們在生成MyMetaClass的子類時,就必須要遵循它的條件,否則將會報錯
五、元類定制物件的產生行為
要求:
? 生成的物件必須使用關鍵字進行傳參,否則將無法生成物件
推導流程:
'''
推導:
1、我們在上述學習了類的魔法方法,發現:
2、物件加括號會執行產生該物件類里的__call__
3、類加括號會執行產生該類的類里的__call__
4、觀察__call__(self, *args, **kwargs):
self: 呼叫者本身
*args:接收位置實參
**kwargs:接收關鍵字實參
5、得出結論,我們需要對args進行約束就可達到條件
'''
class MyMetaClass(type):
def __call__(self, *args, **kwargs):
# 1.產生一個空物件(骨架)
# 2.呼叫__init__給物件添加獨有的資料(血肉)
# 3.回傳創建好的物件
# print(args) # ('jason', 18, 'male')
# print(kwargs) # {}
# 設定條件
if args:
# 當條件未滿足時,主動拋出例外,并提升
raise TypeError("需要進行關鍵字傳參")
# 條件滿足后執行,使用super,重新呼叫父類
return super().__call__(*args, **kwargs)
class Student(metaclass=MyMetaClass):
def __init__(self, name, age, gender):
# print('__init__')
self.name = name
self.age = age
self.gender = gender
# obj = Student('jason', 18, 'male')
obj = Student(name='jason',age= 18,gender= 'male')
print(obj.__dict__)
六、元類之雙下new
? 當我們在使用類產生物件時,類體代碼種名字產生的順序是:
? __ call __ >>>: __ new __ >>>:__ init __
? 雙下call將類名傳給雙下new,然后new將物件的名字傳給雙下init而后產生類名
? 得出結論:物件是由new進行產生的
class MyMetaClass(type):
def __call__(self, *args, **kwargs):
# 1.產生一個空物件(骨架)
obj = self.__new__(self)
# 2.呼叫__init__給物件添加獨有的資料(血肉)
self.__init__(obj,*args, **kwargs)
# 3.回傳創建好的物件
return obj
class Student(metaclass=MyMetaClass):
def __init__(self, name):
self.name = name
obj = Student('jason')
print(obj.name)
"""
__new__可以產生空物件
"""
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/529876.html
標籤:其他
下一篇:Python中切片操作的詳細用法
