python 之 面向對象(元類、__call__、單例模式)

7.13 元類

元類:類的類就是元類,我們用class定義的類來產生我們自己的對象的,內置元類type是用來專門產生class定義的類

code="""
global x     
x=0
y=2
"""                           #字符串內聲明的名稱是全局,其他為局部名稱
global_dic={'x':100000}
local_dic={}                   # 運行字符串內代碼
exec(code,global_dic,local_dic) # 把全局名稱空間的名稱放入global_dic,把局部的放入local_dic
print(global_dic)              #{'x': 0}
print(local_dic)               #{'y': 2}

7.131 用內置的元類type,來實例化得到我們的類

class_name='Chinese'
class_bases=(object,)   #基類
class_body="""
country="China"
def __init__(self,name,age,sex):
    self.name=name
    self.age=age
    self.sex=sex
def speak(self):
    print('%s speak Chinese' %self.name)
 """
class_dic={}
exec(class_body,{},class_dic)
​
# 類的三大要素
print(class_name,class_bases,class_dic) # Chinese (<class 'object'>,) {'country':'China', '__init__': <function __init__ at ...>, 'speak': <function speak at....>}
​
Chinese=type(class_name,class_bases,class_dic)  #實例化一個類
print(Chinese)                               #<class '__main__.Chinese'>
​
p=Chinese('egon',18,'male')  #實例化對象p
print(p.name,p.age,p.sex)    # egon 18 male  #說明和class定義的類功能相同

7.132 __call__方法

在調用對象時自動觸發__call__的執行

class Foo:
     def __init__(self):
         passdef __call__(self, *args, **kwargs):# 調用對象,則會自動觸發對象下的綁定方法__call__的執行,
         print('__call__',*args, **kwargs)# 然後將對象本身當作第一個參數傳給self,將調用對象時括號內的值傳給*args與**kwargs
obj=Foo()
obj(1,2,3,a=1,b=2,c=3) #對象調用

7.133 自定義元類來控制類的創建行為

class Mymeta(type):   
     def __init__(self,class_name,class_bases,class_dic): #self=Foo
         print(class_name)
         print(class_bases)
         print(class_dic)
         if not class_name.istitle():                       #控制類名首字母必須大寫
             raise TypeError('類名的首字母必須大寫傻叉')
​
         if not class_dic.get('__doc__'):                   # 控制文檔註釋必須存在
             raise TypeError('類中必須寫好文檔註釋,大傻叉')
​
         super(Mymeta,self).__init__(class_name,class_bases,class_dic)  #重用父類功能
#Foo=Mymeta('Foo',(object,),class_dic)
class Foo(object,metaclass=Mymeta): # metaclass=Mymeta創建自定義元類
     """
     文檔註釋
     """

7.134 自定義元類來控制類的調用

控制類Foo的調用過程,即控制實例化Foo的過程

class Mymeta(type):   
     def __init__(self,class_name,class_bases,class_dic): #self=Foo
         print(class_name)
         print(class_bases)
         print(class_dic)
        
     def __call__(self, *args, **kwargs): #self=Foo,args=(1111,) kwargs={}
         #1 造一個空對象obj
         obj=object.__new__(self)
​
         #2、調用Foo.__init__,將obj連同調用Foo括號內的參數一同傳給__init__
         self.__init__(obj,*args,**kwargs)
         return obj
#Foo=Mymeta('Foo',(object,),class_dic)
class Foo(object,metaclass=Mymeta): 
     x=1
     def __init__(self,y):
         self.y=y
​
     def f1(self):
         print('from f1')
obj=Foo(1111)           #Foo.__call__()
print(obj)              #<__main__.Foo object at 0x000002019EE1BB70>
print(obj.y)            # 1111
print(obj.f1)           #<bound method Foo.f1 of <__main__.Foo object at 0x000002019EE1BB70>>
print(obj.x)            # 1

7.14 單例模式

對於對象通過相同的配置文件進行實例化,可以使幾個對象使用同一個內存地址,節省內存

import settings
class MySQL:
    __instance=None
    def __init__(self,ip,port):
        self.ip=ip
        self.port=port
​
    @classmethod
    def singleton(cls):
        if not cls.__instance:
            obj=cls(settings.IP, settings.PORT)
            cls.__instance=obj
        return cls.__instance
​
obj1=MySQL('1.1.1.2',3306)
obj2=MySQL('1.1.1.3',3307)
obj3=MySQL('1.1.1.4',3308)
​
obj4=MySQL.singleton()          # obj4=MySQL(settings.IP,settings.PORT)
obj5=MySQL.singleton()
obj6=MySQL.singleton()
print(obj4.ip,obj4.port)        # 1.1.1.1 3306
print(obj4 is obj5 is obj6)     # True
点赞

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *