前段時(shí)間在B站上看到python類和元類的視頻講解徘禁,整理了視頻中的代碼诅诱,相信看完后對(duì)類有進(jìn)一步的了解。
1.py
cmd = """
x = 1
print("exec函數(shù)執(zhí)行了")
def func(self):
pass
"""
class_dict = {}
exec(cmd, {}, class_dict)
print(class_dict)
"""
執(zhí)行結(jié)果如下
exec函數(shù)執(zhí)行了
{'x': 1, 'func': <function func at 0x000002DAC0401E18>}
"""
2.py
class People:
country = "China"
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print("%s is eating" % self.name)
print(type(People)) # <class 'type'>
3創(chuàng)建類的三個(gè)要素.py
# 創(chuàng)建類有三個(gè)要素:類名 基類 類的名稱空間
# People = type(類名送朱,基類娘荡,類的名稱空間)
class_name = "People" # 類名
class_bases = (object,) # 基類
# 類的名稱空間
class_dic = {}
class_body = """
country = "China"
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print("%s is eating" % self.name)
"""
exec(class_body,
{},
class_dic, ) # 執(zhí)行exec后,class_dic里面就有類的變量和函數(shù)
# 類的3要素
print(class_name) # 類名 People
print(class_bases) # 基類(<class 'object'>,)
# {'country': 'China', '__init__': <function __init__ at 0x00000153DBC11E18>, 'eat': <function eat at 0x00000153DBF898C8>}
print(class_dic) # 類的名稱空間驶沼,執(zhí)行exec后炮沐,class_dic里面就有類的變量和函數(shù)
# 這樣創(chuàng)建類
People_class = type(class_name, class_bases, class_dic)
print(People_class) # <class '__main__.People'>
# 使用類
o_p = People_class("jjj", 12)
o_p.eat() # jjj is eating
4.自定義類.py
# 定義一個(gè)元類
class Mymeta(type):
# 只有繼承了type類才能稱之為一個(gè)元類,否則就是一個(gè)普通的自定義類
def __init__(self, class_name, class_bases, class_dic):
print("self", self) # 現(xiàn)在是People
print("class_name", class_name)
print("class_bases", class_bases)
print("class_dic", class_dic)
# 重用父類type的功能
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
class People(object, metaclass=Mymeta): # metaclass指定元類
# People=Mymeta(類名商乎,基類央拖,類的名稱空間
country = "China"
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print("%s is eating" % self.name)
# People的信息會(huì)被送到Meteta元類中去:類名 基類門 類的名稱空間
p = People("kk", 22)
p.eat()
"""
self <class '__main__.People'>
class_name People
class_bases (<class 'object'>,)
class_dic {'__module__': '__main__', '__qualname__': 'People', 'country': 'China', '__init__': <function People.__init__ at 0x000001E8C9529950>, 'eat': <function People.eat at 0x000001E8C9529840>}
kk is eating
"""
5.控制類的產(chǎn)生過程.py
# 我們可以控制類必選有文檔
class Mymeta(type):
# 只有繼承了type類才能稱之為一個(gè)元類,否則就是一個(gè)普通的自定義類
def __init__(self, class_name, class_bases, class_dic):
if class_dic.get("__doc__") is None or len(
class_dic.get("__doc__").strip()) == 0:
raise TypeError("類中必須要有文檔注釋鹉戚,并且文檔注釋不能為空")
if not class_name.istitle():
raise TypeError("類名首字母必須大寫")
# 重用父類type的功能
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
try:
class People(object, metaclass=Mymeta):
country = "China"
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print("%s is eating" % self.name)
except Exception as e:
print(e) # 類中必須要有文檔注釋鲜戒,并且文檔注釋不能為空
try:
class people(object, metaclass=Mymeta): # metaclass指定元類
"""
# 有注釋了,但類名是小寫
"""
country = "China"
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print("%s is eating" % self.name)
except Exception as e:
print(e) # 類名首字母必須大寫
6__call__方法.py
class Foo:
def __call__(self, *args, **kwargs):
print(args)
print(kwargs)
print("__call__實(shí)現(xiàn)了抹凳,實(shí)例化對(duì)象可以加括號(hào)調(diào)用了")
obj = Foo()
obj("xiaojun", age=18)
"""
('xiaojun',)
{'age': 18}
__call__實(shí)現(xiàn)了遏餐,實(shí)例化對(duì)象可以加括號(hào)調(diào)用了
"""
7__new__方法.py
# __new__方法
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def __new__(cls, name, age):
# 約束年齡
if 0 < age < 150:
# return object.__new__(cls)
return super(People, cls).__new__(cls)
else:
return None
b = People("x", 10)
print(b) # <__main__.People object at 0x000001732F7177B8>
p = People("x", 150)
print(p) # None
8利用new init控制類實(shí)例化產(chǎn)生.py
# 利用new init控制類實(shí)例化產(chǎn)生
class Mymeta(type):
def __call__(self, *args, **kwargs):
print(self) # <class '__main__.People'> ,self是People
print(args) # ('name1',)
print(kwargs) # {'age': 12}
# 1赢底,先造出一個(gè)People的空對(duì)象失都,申請內(nèi)存空間
# __new__方法接受的參數(shù)雖然也是和__init__一樣,但是__init__是在類實(shí)例創(chuàng)建之后調(diào)用幸冻,而__new__方式正是創(chuàng)建這個(gè)類實(shí)例之前調(diào)用
obj = self.__new__(self) # 雖然和下面同樣是People粹庞,但是People沒有,找到的__new__是父類的
# 2洽损,為該空對(duì)象初始化獨(dú)有的屬性
self.__init__(obj, *args, **kwargs)
# 3, 返回一個(gè)初始化好的對(duì)象
obj.name2 = "haha"
return obj
"""
類的調(diào)用庞溜,即類實(shí)例化就是元類的調(diào)用過程,可以通過元類Mymeta的__call__方法控制
1碑定,先造出一個(gè)People的空對(duì)象
2流码,為該空對(duì)象初始化獨(dú)有的屬性
3又官,返回一個(gè)初始化好的對(duì)象
"""
class People(object, metaclass=Mymeta):
country = "China"
def __init__(self, name1, age):
self.name1 = name1
self.age = age
def eat(self):
print("%s is eating" % self.name1)
p = People("name1", age=12)
p.eat() # name1 is eating
print(p.name2) # haha
9,使用元類修改屬性為隱藏屬性.py
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
def __call__(self, *args, **kwargs):
# 加上邏輯漫试,控制Foo的調(diào)用過程六敬,即Foo對(duì)象的產(chǎn)生過程
obj = self.__new__(self)
self.__init__(obj, *args, **kwargs)
# 修改屬性為隱藏屬性
obj.__dict__ = {
'_%s__%s' % (self.__name__, k): v
for k, v in obj.__dict__.items()
}
return obj
class Foo(object, metaclass=Mymeta):
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
obj = Foo("nick", 18, "male")
print(obj.__dict__)
# {'_Foo__name': 'nick', '_Foo__age': 18, '_Foo__sex': 'male'}