天天看點

類特殊屬性方法--反射

概述

運作時,差別于編譯時,指的是程式被加載到記憶體中執行的時候

反射,reflection,指的是運作時擷取類型定義資訊

一個對象能夠在運作時,像照鏡子一樣,反射出其類型資訊

簡單說,在python中,能夠通過一個對象,找出其type、class、attribute或method的能力,稱為反射或者自省。

具有反射能力的函數有:type()、isinstance()、callable()、dir()、getattr()

反射相關的函數和方法

需求

有一個Point類,檢視它執行個體的屬性,并修改它。動态為執行個體增加屬性

getattr(object,name[,default])

通過name傳回object的name屬性,當name屬性不存在,将使用default傳回,如果沒有default,則抛出AttributeError
name必須是字元串類型
default是函數,因為getattr傳回的就是一個函數,是以當找不到name對應的函數後就調用default函數。           

setattr(object,name,value)

object存在name屬性時,則通過value覆寫之前name屬性
object不存在name屬性時,則新增屬性
name依然時字元串類型,value可以是一個數值,也可以是一個函數           

hasattr(object,name)

判斷對象是否有這個名字的屬性,name必須為字元串           

反射相關的魔術方法

getattr()、setattr()、delattr()這三個魔術方法,分别測試。

getattr()

class Base:
        n = 0

class Point(Base):
        z = 6

        def __init__(self,x,y):
                self.x = x
                self.y = y

        def show(self):
                print(self.x,self.y)

        def __getattr__(self,item):
                return "missing{}".format(item)

p1 = Point(4,5)
print(p1.x)
print(p1.z)
print(p1.n)
print(p1.t)           

一個類的屬性會按照繼承關系找,如果找不到,就會執行getattr()方法,如果沒有這個方法,就會抛出AttributeError異常表示找不到屬性

查找屬性順序為:

instance.dict --> instance.class.dict --> 繼承的祖先類(直到object)的dict --找不到--> 調用getattr()

setattr()

class Base:
        n = 0

class Point(Base):
        z = 6

        def __init__(self,x,y):
                self.x = x
                self.y = y

        def show(self):
                print(self.x,self.y)

        def __getattr__(self,item):
                return "missing{}".format(item)

        def __setattr__(self, key, value):
                print("setattr {}={}".format(key,value))
                #self.__dict__[key] = value #正常情況下設定屬性
                #return self #傳回執行個體本身

p1 = Point(4,5)
print(p1.__dict__)
print(p1.x)
print(p1.z)
print(p1.n)
print(p1.t)
p1.name = 50
p1.x = 50
print(p1.name)
print(p1.x)
p1.__dict__["x"] = 60
print(p1.__dict__)           
class Base:
        n = 0

class Point(Base):
        Z = 5

def __init__(self,x,y):
    self.x = x
    self.y = y

def __delattr__(self,item):
    print("Can not del{}".format(item))

p = Point(4,5)
del p.x
print(p.dict)
p.z = 15
print(p.dict)
del p.z
del p.z
print(Point.dict)
print(p.dict)
print(Point.Z)
del Point.Z
print(Point.dict)
print(Point.Z)