python元类深入理解
1.python 中的類
在python中,類也是一個(gè)對(duì)象,只不過這個(gè)對(duì)象擁有生成實(shí)例的能力,我們一般使用class XXX來定義一個(gè)類,在python解釋器執(zhí)行到這個(gè)地方的時(shí)候會(huì)自動(dòng)創(chuàng)建出這個(gè)對(duì)象,python也為我們提供了手動(dòng)創(chuàng)建類的方法,type()。type()這個(gè)方法對(duì)我們來說并不陌生,我們所熟知的用法是:class = type(instance),當(dāng)傳入一個(gè)參數(shù)時(shí),type()返回這個(gè)參數(shù)的類。而今天我們要用到的是type的另一個(gè)功能。type("classname",(object,),{"name":"jiao"})。當(dāng)給type傳入三個(gè)參數(shù)時(shí),就是一個(gè)手動(dòng)創(chuàng)建類的方式。
class A():def __init__(self,name):self.name = nameprint("創(chuàng)建了一個(gè)實(shí)例")a = type("a",(A,),{"name":"jiao"}) print(a) #<class '__main__.a'> print(a.name) #jiao print(a("jiang")) #創(chuàng)建了一個(gè)實(shí)例 #<__main__.a object at 0x00000280A973AA58>
?
type接收三個(gè)參數(shù)分別是:
classname: 要?jiǎng)?chuàng)建的class 的名稱
object:要?jiǎng)?chuàng)建類的父類所組成的元組
sttr_dict: 要?jiǎng)?chuàng)建類的屬性
type返回一個(gè)class,我們接收并賦值到一個(gè)變量上,現(xiàn)在這個(gè)變量就指向我們所創(chuàng)建的類,我們可以通過這個(gè)變量來使用類。
?
2.python 中的type
在python 中,幾乎所有的東西都是對(duì)象,這包括整數(shù)、字符串、函數(shù)以及類。它們?nèi)慷际菍?duì)象,而且它們都是從一個(gè)類創(chuàng)建而來——type
3.__metaclass__屬性
python在創(chuàng)建類時(shí),會(huì)按照如下的流程進(jìn)行:
?
Foo中有__metaclass__這個(gè)屬性嗎?如果是,Python會(huì)在內(nèi)存中通過__metaclass__創(chuàng)建一個(gè)名字為Foo的類對(duì)象(我說的是類對(duì)象,請(qǐng)緊跟我的思路)。如果Python沒有找到__metaclass__,它會(huì)繼續(xù)在Bar(父類)中尋找__metaclass__屬性,并嘗試做和前面同樣的操作。如果Python在任何父類中都找不到__metaclass__,它就會(huì)在模塊層次中去尋找__metaclass__,并嘗試做同樣的操作。如果還是找不到__metaclass__,Python就會(huì)用內(nèi)置的type來創(chuàng)建這個(gè)類對(duì)象。
那么在__metaclass__中放置什么樣的代碼可以創(chuàng)建類呢?type,或者任何使用到type或者子類化type的東東都可以。
?
4.自定義元類
class UpperAttrMetaClass(type):def __new__(cls,class_name,class_parents,class_attr, *args, **kwargs):print("__new__")class_attr['name'] = "jiao"return type.__new__(cls,class_name,class_parents,class_attr)def __init__(self,*args,**kwargs):print("__init__")super().__init__(*args, **kwargs)self.__cache = {}def __call__(self, *args, **kwargs):print("__call__")if args in self.__cache:return self.__cache[args]else:obj = super().__call__(*args)self.__cache[args] = objreturn objclass A(metaclass=UpperAttrMetaClass):def __init__(self,name):self.name = nameprint("a.__init__")
?
?
5.類的創(chuàng)建流程
1.元類的__new__(),返回創(chuàng)建好的類。當(dāng)我們想要改變創(chuàng)建方式的時(shí)候就要重寫這個(gè)方法。
2.元類的__init__(),初始化一些類的屬性
?
6.實(shí)例創(chuàng)建流程
1.元類的__call__(),創(chuàng)建一個(gè)實(shí)例時(shí),首先調(diào)用這個(gè)方法,返回創(chuàng)建好的實(shí)例,所以我們可以通過改寫這個(gè)方法來改變實(shí)例創(chuàng)建過程,比如實(shí)現(xiàn)單例模式
2.類的__init__(),初始化實(shí)例屬性
?
7.元類的應(yīng)用
1.單例模式
class Singleton(type):def __init__(cls,*args,**kwargs):cls.__instance = Nonesuper().__init__(*args,**kwargs)def __call__(cls, *args, **kwargs):if cls.__instance is None:cls.__instance = super().__call__(*args,**kwargs)return cls.__instanceelse:return cls.__instanceclass Spam(metaclass=Singleton):def __init__(self):print("Creating Spam")
?
2.緩存模式
import weakrefclass Cached(type):def __init__(cls,*args,**kwargs):super().__init__(*args,**kwargs)cls.__cache = weakref.WeakValueDictionary()def __call__(cls, *args, **kwargs):if args in cls.__cache:return cls.__cache[args]else:obj = super().__call__(*args)cls.__cache[args] = objreturn objclass Spams(metaclass=Cached):def __init__(self,name):print("Creating Spam({!r})".format(name))self.name = name
?
3.獲取屬性的定義順序
?
能過獲取到屬性的定義順序,我們就可以通過簡單的方法實(shí)現(xiàn)屬性到數(shù)據(jù)的映射,可以更加簡單的將類中的屬性數(shù)據(jù)化。
from collections import OrderedDictclass Typed:_excepted_type = type(None)def __init__(self,name=None):self._name = namedef __set__(self, instance, value):if not isinstance(value,self._excepted_type):raise TypeError("Excepted"+str(self._excepted_type))instance.__dict__[self._name] = valueclass Integer(Typed):_excepted_type = intclass Float(Typed):_excepted_type = floatclass String(Typed):_excepted_type = strclass OrderedMeta(type):def __new__(cls, clsname,bases,clsdict):d = dict(clsdict)order = []for name,value in clsdict.items():if isinstance(value,Typed):value._name = nameorder.append(name)d['_order'] = orderreturn type.__new__(cls,clsname,bases,d)@classmethoddef __prepare__(metacls, name, bases):return OrderedDict()#注:__prepare__該方法會(huì)在類定義一開始的時(shí)候調(diào)用,調(diào)用時(shí)以類名和基類名稱作為參數(shù),它必須返回一個(gè)映射對(duì)象,供處理類定義體時(shí)調(diào)用#eg. class Structure(metaclass=OrderedMeta):def as_csv(self):return ','.join(str(getattr(self,name)) for name in self._order)class Stock(metaclass=OrderedMeta):name = String()shares = Integer()price = Float()def __init__(self,name,shares,price):self.name = nameself.shares = sharesself.price = prices = Stock("haha",23,23.3) print(s.name) s = Stock(34,23,34) # print(s.as_csv())
?
?
8.小結(jié)
元類主要就是在類和實(shí)例創(chuàng)建的時(shí)候發(fā)揮作用,來實(shí)現(xiàn)一些功能。
轉(zhuǎn)載于:https://www.cnblogs.com/jiaojianglong/p/11260944.html
總結(jié)
以上是生活随笔為你收集整理的python元类深入理解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: centeos7安装mariadb
- 下一篇: 腾讯文档使用记录