本文實(shí)例講述了Python 使用元類type創(chuàng)建類對(duì)象。分享給大家供大家參考,具體如下:
type("123") 可以查看變量的類型;同時(shí) type("類名",(父類),{類屬性:值,類屬性2:值}) 可以創(chuàng)建一個(gè)類。
在Python中不建議一個(gè)函數(shù)具有不同的功能(重載);type()具有不同的功能是為了兼容之前的版本。
類可以創(chuàng)建實(shí)例對(duì)象,類對(duì)象是由元類創(chuàng)建的。 (元類創(chuàng)建類,類創(chuàng)建實(shí)例對(duì)象)
type就是元類(type本質(zhì)上就是一個(gè)類)
demo.py(用元類type創(chuàng)建類):
# 通過class關(guān)鍵字創(chuàng)建類class MyClass1(object): name = "張三" # 類屬性 (所有實(shí)例對(duì)象共用) age = 23# 通過type創(chuàng)建類。 type()返回的是創(chuàng)建的類對(duì)象的引用。Test2 = type("MyClass2",(object,),{"name":"張三","age":23}) # Test2是MyClass2類的引用,一般變量名和類名保持一致。print(Test2()) # <__main__.MyClass2 object at 0x7fa05a4ca9e8>demo.py(用type創(chuàng)建帶有方法的類):
# 實(shí)例方法def print_b(self): print(self.num)# 靜態(tài)方法@staticmethoddef print_static(): print("----haha-----")# 類方法@classmethoddef print_class(cls): print(cls.num)# 用type創(chuàng)建類B = type("B", (object,), {"num":100, "print_b": print_b, "print_static": print_static, "print_class": print_class})b = B()b.print_b() # 100b.print_static() # ----haha-----b.print_class() # 100元類的應(yīng)用
在定義一個(gè)類的時(shí)候可以為其指定__metaclass__屬性(指定創(chuàng)建該類的元類),默認(rèn)使用type元類創(chuàng)建類對(duì)象。
通過指定自定義的元類,可以對(duì)類的創(chuàng)建進(jìn)行攔截??梢詫?duì)類名、繼承的父類、屬性(方法)做一些預(yù)處理。
例如:將類名大寫,默認(rèn)繼承object類,添加、修改屬性(方法)名(私有屬性的偽私有化就是通過修改屬性名實(shí)現(xiàn)的)。
裝飾器是對(duì)函數(shù)進(jìn)行功能擴(kuò)展(不用修改原代碼),而元類可以對(duì)類進(jìn)行功能擴(kuò)展(添加額外的屬性/方法)。
demo.py(用函數(shù)指定__metaclass__屬性):
#-*- coding:utf-8 -*-def upper_attr(class_name, class_parents, class_attr): # class_name 會(huì)保存類的名字 Foo # class_parents 會(huì)保存類的父類 object # class_attr 會(huì)以字典的方式保存所有的類屬性/方法 # 遍歷屬性字典,把不是__開頭的屬性名字變?yōu)榇髮? new_attr = {} for name, value in class_attr.items(): if not name.startswith("__"): new_attr[name.upper()] = value # 調(diào)用type來創(chuàng)建一個(gè)類 return type(class_name, class_parents, new_attr)class Foo(object, metaclass=upper_attr): # python3的方式 # python2.x的方式。 # __metaclass__ = upper_attr # 設(shè)置Foo類的元類為upper_attr bar = 'bip'print(hasattr(Foo, 'bar'))print(hasattr(Foo, 'BAR'))f = Foo()print(f.BAR)demo.py(用類指定__metaclass__屬性):
class UpperAttrMetaClass(type): # __new__ 是在__init__之前被調(diào)用的特殊方法 # __new__是用來創(chuàng)建對(duì)象并返回之的方法 # 而__init__只是用來將傳入的參數(shù)初始化給對(duì)象 # 你很少用到__new__,除非你希望能夠控制對(duì)象的創(chuàng)建 # 這里,創(chuàng)建的對(duì)象是類,我們希望能夠自定義它,所以我們這里改寫__new__ # 如果你希望的話,你也可以在__init__中做些事情 # 還有一些高級(jí)的用法會(huì)涉及到改寫__call__特殊方法,但是我們這里不用 def __new__(cls, class_name, class_parents, class_attr): # 遍歷屬性字典,把不是__開頭的屬性名字變?yōu)榇髮? new_attr = {} for name, value in class_attr.items(): if not name.startswith("__"): new_attr[name.upper()] = value # 方法1:通過'type'來做類對(duì)象的創(chuàng)建 return type(class_name, class_parents, new_attr) # 方法2:復(fù)用type.__new__方法 # 這就是基本的OOP編程,沒什么魔法 # return type.__new__(cls, class_name, class_parents, new_attr)# python3的用法class Foo(object, metaclass=UpperAttrMetaClass): bar = 'bip'# python2的用法# class Foo(object):# __metaclass__ = UpperAttrMetaClass# bar = 'bip'print(hasattr(Foo, 'bar'))# 輸出: Falseprint(hasattr(Foo, 'BAR'))# 輸出:Truef = Foo()print(f.BAR)# 輸出:'bip'
新聞熱點(diǎn)
疑難解答
網(wǎng)友關(guān)注