1. 程式人生 > >反射、自定義內置方法來定制類的功能、元類

反射、自定義內置方法來定制類的功能、元類

tle col turn cal meta 自定義 error 使用方法 天使

一、反射

  1. 定義:通過字符串來操作類或者對象屬性

  2. 方法:hasattr、getattr、setattr、delattr

  3. 使用方法:

技術分享圖片
 1 class People:
 2     def __init__(self,name):
 3         self.name=name
 4     def put(self):
 5         print(%s is putting%self.name)
 6     def get(self):
 7         print(%s get sth%self.name)
 8     def run(self):
9 while True: 10 choice=input(>>).strip() 11 method=getattr(obj,choice,None) 12 13 # # 判斷對象obj裏邊有沒有choice這個屬性 14 # print(hasattr(obj,choice)) 15 16 # # obj.choice=z 17 # setattr(obj,choice,name) 18 19 #
# delete boj.msg 20 # delattr(obj,msg) 21 if method is None: 22 print(command is not exists) 23 else: 24 # getattr 是取得字符串並將該字符串轉成可執行的函數 25 method() 26 27 obj=People(大王) 28 obj.run()
hasattr、setattr、getattr、delattr

  4.反射的好處:可以事先定義好接口,接口只有在被完成後才會真正執行,這實現了即插即用,這其實是一種‘後期綁定’,什麽意思?即你可以事先把主要的邏輯寫好(只定義接口),然後後期再去實現接口的功能

二、自定義內置方法來實現定制類的功能

  1. __str__

  

class People:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    
    # 在打印對象時會自動觸發這個功能
    # 此時應該收集跟這個對象有關的信息,輸出到屏幕上
    def __str__(self):
        return <%s : %s>%(self.name,self.age)

p=People(小天使,17)
print(p)

  2.__del__析構方法

class People:
    def __init__(self,name):
        self.name=name
        self.f=open(a.txt,rt,encoding=utf8)

    # 會在對象刪除之前自動觸發
    def __del__(self):
        # print(‘>>>>>>>‘)

        # 做回收系統資源相關的事情
        self.f.close()
p=People(魔鬼)
print()

三、元類

  1.定義

  在python中一切都是對象,所以用class 關鍵字定義的類本身也是一個對象,負責產生該對象的類稱之為元類,即產生類的類即稱為元類。

  2.為何用元類

  元類是負責產生類的,所以學習元類或者自定義元類的目的是為了控制類的產生過程,還可以控制對象的產生過程。

知識準備:

  內置函數exec的用法:將函數體代碼執行一遍

# 將函數體代碼執行一遍,放至局部{}中
msg=‘‘‘
x=1
def func():
    pass
‘‘‘
class_dic={}
exec(msg,{},class_dic)
print(class_dic)

    __call__的用法

    如果想要讓實例化出來的對象變成可以調用的對象,則需要在該對象的類中定義一個__call__的方法,該對象會在調用時自動觸發

class Foo:
    def __call__(self, *args, **kwargs):
        print(self)
        print(args)
        print(kwargs)

obj=Foo()
obj()
obj(1,2,3,x=1,y=2)

  執行結果入下圖

技術分享圖片

  3. 創建類的方法有兩種

如果說類也是對象的話,那麽用class關鍵字去創建類的過程也是一個實例化的過程

該實例化的目的是為了得到一個類,調用的是元類

3.1 方式一:用默認的元類type

class People:
    def __init__(self,name):
        self.name=name

    def eat(self):
        print(%s is eating...%self.name)

print(type(People))

3.1.1 創建類的三個要素 (類名,基類們,類的名稱空間)

class_name=People‘     #類名
class_bases=(object,)   #基類
class_dic={}            #類的名稱空間
class_body=‘‘‘          #類體代碼
class People:
    def __init__(self,name):
        self.name=name

    def eat(self):
        print(‘%s is eating...‘%self.name)

print(type(People))
‘‘‘
exec(class_body,{},class_dic)

3.2 用的自定義的元類

class Mymeta(type):  # Mymeta=type(...)
    def __init__(self,class_name,class_bases,class_dic):
        super(Mymeta, self).__init__(class_name,class_bases,class_dic)
class People(object,metaclass=Mymeta): # People=Mymeta(類名,基類們,類的名稱空間)
    def __init__(self,name):
        self.name=name
    def eat(self):
        print(%s is eating...%self.name)
p=People(小三炮)
p.eat()

原理:

  3.2.1 得到一個字符串的類名 class_name = ‘People‘

  3.2.2 得到一個類的基類們 class_bases = (object,)

  3.3.3 執行類體代碼,得到一個類的名稱空間 class_dic = {...}

  3.3.4 調用 People = type(class_name,class_bases,class_dic)

3.3 應用

  自定義元類控制類的產生過程,類的產生過程其實就是元類的調用過程

class Mymeta(type):
    def __init__(self,class_name,class_bases,class_dic):
        super(Mymeta, self).__init__(class_name,class_bases,class_dic)
        print(class_dic) # {‘__module__‘: ‘__main__‘, ‘__qualname__‘: ‘People‘, ‘__doc__‘: ‘ ‘,
                        #  ‘__init__‘: <function People.__init__ at 0x000001FCE6048AE8>}
        print(class_name)  # People
        print(class_bases)  # (<class ‘object‘>,)
        if class_dic.get(__doc__) is None and len(class_dic.get(__doc__))==0:
            raise TypeError(Document must exists and must not be None)
        if not class_name.istitle():
            raise NameError(First letter must be capital)
class People(object,metaclass=Mymeta):  # if class_name‘initials is not capital,it 
                                                  # will report an error
    ‘‘‘ hey guys ‘‘‘  
    def __init__(self,name):
        self.name=name
p=People(明日之星)
技術分享圖片
 1 class Mymeta(type):
 2 
 3 
 4     def __call__(self, *args, **kwargs):
 5 
 6         # 先造出一個類的空對象
 7         obj=self.__new__(self)
 8 
 9         # 為該空對象初始化獨有屬性
10         self.__init__(obj,*args,**kwargs)
11 
12         # 返回一個初始化好的對象
13         return obj
14 
15 
16 class People(object,metaclass=Mymeta):
17     def __init__(self,name):
18         print(self)
19         self.name=name
20 
21     def eat(self):
22         print(%s is eating%self.name)
23     def __new__(cls, *args, **kwargs): #(涉及查找順序)
24         print(cls)   # <class ‘__main__.People‘>
25         # cls.__new__(cls) # 錯誤
26         obj=super(People,cls).__new__(cls)
27         return obj
28 obj=People(大寶,)
自定義元類來控制類的調用的過程,即類的實例化過程

反射、自定義內置方法來定制類的功能、元類