一、 元類(***)難點
定義類,控制物件產生
定義元類,控制類產生(看原始碼時用)
一切源自于一句話:python中一切皆為物件
1、元類介紹
物件是呼叫類得到
元類是呼叫元類得到
查看類(就是型別):type(obj)===>OldboyTeacher
查看元類(就是型別):type(OldboyTeacher)==>type
# 元類=》OldboyTeacher類=》obj class OldboyTeacher(object): school = 'oldboy' def __init__(self, name, age): self.name = name self.age = age def say(self): print('%s says welcome to the oldboy to learn Python' % self.name) obj = OldboyTeacher('egon', 18) # 呼叫OldboyTeacher類=》物件obj # 呼叫元類=》OldboyTeacher類 # print(type(obj)) print(type(OldboyTeacher)) # 結論:默認的元類是type,默認情況下我們用class關鍵字定義的類都是由type產生的
2、class關鍵字底層的做了哪些事造出來類?
一定是呼叫了type得到回傳值,把回傳值賦值給class關鍵字
# 1、先拿到一個類名 class_name = "OldboyTeacher" # 2、然后拿到類的父類 class_bases = (object,) # 3、再運行類體代碼,將產生的名字放到名稱空間中 class_dic = {} class_body = """ school = 'oldboy' def __init__(self, name, age): self.name = name self.age = age def say(self): print('%s says welcome to the oldboy to learn Python' % self.name) """ exec(class_body,{},class_dic) # print(class_dic) # 4、呼叫元類(傳入類的三大要素:類名、基類、類的名稱空間)得到一個元類的物件,然后將元類的物件賦值給變數名OldboyTeacher,oldboyTeacher就是我們用class自定義的那個類 OldboyTeacher = type(class_name,class_bases,class_dic)
3、自定義元類
只有繼承了type類的類才是自定義的元類
type是內置的元類,type內部一定有個__init__用法
class Mymeta(type): # 只有繼承了type類的類才是自定義的元類 pass class OldboyTeacher(object, metaclass=Mymeta): school = 'oldboy' def __init__(self, name, age): self.name = name self.age = age def say(self): print('%s says welcome to the oldboy to learn Python' % self.name) # 1、先拿到一個類名:"OldboyTeacher" # 2、然后拿到類的父類:(object,) # 3、再運行類體代碼,將產生的名字放到名稱空間中{...} # 4、呼叫元類(傳入類的三大要素:類名、基類、類的名稱空間)得到一個元類的物件,然后將元類的對象賦值給變數名OldboyTeacher,oldboyTeacher就是我們用class自定義的那個類 OldboyTeacher = Mymeta("OldboyTeacher",(object,),{...})
4、自定義元類來控制OldboyTeacher類的產生
import re class Mymeta(type): # 只有繼承了type類的類才是自定義的元類 def __init__(self, class_name, class_bases, class_dic): # print(self) # 類<class '__main__.OldboyTeacher'> # print(class_name) # print(class_bases) # print(class_dic) if not re.match("[A-Z]", class_name): raise BaseException("類名必須用駝峰體") if len(class_bases) == 0: raise BaseException("至少繼承一個父類") # print("檔案注釋:",class_dic.get('__doc__')) doc=class_dic.get('__doc__') if not (doc and len(doc.strip()) > 0): raise BaseException("必須要有檔案注釋,并且注釋內容不為空") # OldboyTeacher = Mymeta("OldboyTeacher",(object,),{...}) class OldboyTeacher(object,metaclass=Mymeta): """ adsaf """ school = 'oldboy' def __init__(self, name, age): self.name = name self.age = age def say(self): print('%s says welcome to the oldboy to learn Python' % self.name)
5、自定義元類來控制OldboyTeacher類的呼叫
自定義元類的目的是:定義規范
這里涉及到如何隱藏屬性問題:其實就是利用字典的k:v(此例子中有)
import re class Mymeta(type): # 只有繼承了type類的類才是自定義的元類 def __init__(self, class_name, class_bases, class_dic): # print(self) # 類<class '__main__.OldboyTeacher'> # print(class_name) # print(class_bases) # print(class_dic) if not re.match("[A-Z]", class_name): raise BaseException("類名必須用駝峰體") if len(class_bases) == 0: raise BaseException("至少繼承一個父類") # print("檔案注釋:",class_dic.get('__doc__')) doc = class_dic.get('__doc__') if not (doc and len(doc.strip()) > 0): raise BaseException("必須要有檔案注釋,并且注釋內容不為空") # res = OldboyTeacher('egon',18) def __call__(self, *args, **kwargs): # 1、先創建一個老師的空物件 tea_obj = object.__new__(self) # 2、呼叫老師類內的__init__函式,然后將老師的空物件連同括號內的引數的引數一同傳給__init__ self.__init__(tea_obj, *args, **kwargs) tea_obj.__dict__ = {"_%s__%s" %(self.__name__,k): v for k, v in tea_obj.__dict__.items()} # 3、將初始化好的老師物件賦值給變數名res return tea_obj # OldboyTeacher = Mymeta("OldboyTeacher",(object,),{...}) class OldboyTeacher(object, metaclass=Mymeta): """ adsaf """ school = 'oldboy' # tea_obj,'egon',18 def __init__(self, name, age): self.name = name # tea_obj.name='egon' self.age = age # tea_obj.age=18 def say(self): print('%s says welcome to the oldboy to learn Python' % self.name) res = OldboyTeacher('egon', 18) print(res.__dict__) # print(res.name) # print(res.age) # print(res.say) # 呼叫OldboyTeacher類做的事情: # 1、先創建一個老師的空物件 # 2、呼叫老師類內的__init__方法,然后將老師的空物件連同括號內的引數的引數一同傳給__init__ # 3、將初始化好的老師物件賦值給變數名res
6、僅供理解的例子
class Foo: def __call__(self, *args, **kwargs): print('================>') print(self) print(args) print(kwargs) obj1 = Foo() obj1(1,2,3,a=1,b=2) # 呼叫物件其實就是在呼叫物件類中定義的系結方法__call__ # # obj2 = int(10) # obj2() # obj3 = list([1, 2, 3]) # obj3()
二、 單例模式
字面意思:保證一個類僅有一個實體,并只提供一個訪問它的全域訪問點
目的:節省記憶體空間
設計模式的一種
#優點: 1、由于單例模式要求在全域內只有一個實體,因而可以節省比較多的記憶體空間; 2、全域只有一個接入點,可以更好地進行資料同步控制,避免多重占用; 3、單例可長駐記憶體,減少系統開銷, #缺點: 1、單例模式的擴展是比較困難的; 2、賦于了單例以太多的職責,某種程度上違反單一職責原則(六大原則后面會講到); 3、單例模式是并發協作軟體模塊中需要最先完成的,因而其不利于測驗; 4、單例模式在某種情況下會導致“資源瓶頸”, #應用舉例: 1、生成全域惟一的序列號; 2、訪問全域復用的惟一資源,如磁盤、總線等; 3、單個物件占用的資源過多,如資料庫等; 4、系統全域統一管理,如Windows下的Task Manager; 5、網站計數器,
更多模式:https://www.cnblogs.com/liuqingzheng/p/10038958.html
三種方式實作單例模式
IP='192.1.1.1' PORT=3306settings
1、實作方式1:classmethod
import settings class MySQL: __instance = None def __init__(self, ip, port): self.ip = ip self.port = port @classmethod def singleton(cls): if cls.__instance: return cls.__instance cls.__instance = cls(settings.IP, settings.PORT) return cls.__instance # obj1=MySQL("1.1.1.1",3306) # obj2=MySQL("1.1.1.2",3306) # print(obj1) # print(obj2) obj3 = MySQL.singleton() print(obj3) obj4 = MySQL.singleton() print(obj4)
2、實作方式2:元類
import settings class Mymeta(type): __instance = None def __init__(self,class_name,class_bases,class_dic): self.__instance=object.__new__(self) # Mysql類的物件 self.__init__(self.__instance,settings.IP,settings.PORT) def __call__(self, *args, **kwargs): if args or kwargs: obj = object.__new__(self) self.__init__(obj, *args, **kwargs) return obj else: return self.__instance # MySQL=Mymeta(...) class MySQL(metaclass=Mymeta): def __init__(self, ip, port): self.ip = ip self.port = port # obj1 = MySQL("1.1.1.1", 3306) # obj2 = MySQL("1.1.1.2", 3306) # print(obj1) # print(obj2) obj3 = MySQL() obj4 = MySQL() print(obj3 is obj4)
3、實作方式3:裝飾器
import settings def outter(func): # func = MySQl類的記憶體地址 _instance = func(settings.IP,settings.PORT) def wrapper(*args,**kwargs): if args or kwargs: res=func(*args,**kwargs) return res else: return _instance return wrapper @outter # MySQL=outter(MySQl類的記憶體地址) # MySQL=》wrapper class MySQL: def __init__(self, ip, port): self.ip = ip self.port = port # obj1 = MySQL("1.1.1.1", 3306) # obj2 = MySQL("1.1.1.2", 3306) # print(obj1) # print(obj2) obj3 = MySQL() obj4 = MySQL() print(obj3 is obj4)
三、屬性查找
按照之前的查找順序
在有元類的情況下的屬性查找順序:一直找到父類找到object后再找元類

class Mymeta(type): n=444 # def __call__(self, *args, **kwargs): #self=<class '__main__.OldboyTeacher'> # obj=self.__new__(self) # print(self.__new__ is object.__new__) #True class Bar(object): # n=333 # def __new__(cls, *args, **kwargs): # print('Bar.__new__') pass class Foo(Bar): # n=222 # def __new__(cls, *args, **kwargs): # print('Foo.__new__') pass class OldboyTeacher(Foo,metaclass=Mymeta): # n=111 school='oldboy' def __init__(self,name,age): # self.n=0 self.name=name self.age=age def say(self): print('%s says welcome to the oldboy to learn Python' %self.name) # def __new__(cls, *args, **kwargs): # print('OldboyTeacher.__new__') # obj=OldboyTeacher('egon',18) # print(obj.n) print(OldboyTeacher.n)
---34---
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/47305.html
標籤:Python
上一篇:Python容器型別公共方法匯總
下一篇:109有序鏈表轉化為二叉搜索樹
