反射及元類

2022-04-10 17:02:23 字數 3537 閱讀 4050

什麼是反射, 其實是反省,自省的意思

反射指的是乙個物件應該具備,可以檢測,修改,增加自身屬性的能力

反射就是通過字串操作屬性

涉及的四個函式,這四個函式就是普通的內建函式 沒有雙下劃線,與print等等沒有區別

class

person:

def__init__

(self,name, age, gender):

self.name =name

self.age =age

self.gender =gender

p = person('

cly', 17, '

female')

print(hasattr(p, '

salary

')) #

判斷物件中是否存在某個屬性

print(getattr(p, '

ages

', none)) #

從物件中取出屬性,第三個值位預設值 當屬性不存在是返回預設值

#為物件新增屬性

setattr(p, '

salary

', 1000000000)

#刪除物件屬性

delattr(p, '

salary

')

使用場景:

反射其實就是對屬性的增刪改查,但是如果直接使用內建的dict來操作,語法繁瑣,不好理解

另外乙個最主要的問題是,如果物件不是我自己寫的是另一方提供的,我就必須判斷這個物件是否滿足的要求,也就是是否我需要的屬性和方法

所有的類都是物件

所有的類都是元類產生的

object是根類,是所有類的父類

預設情況下所有類都是元類

學習元類的目的:

高度自定義乙個類,例如控制類的名字必須以大駝峰的方式來書寫

類也是物件,也有自己的類

我們的需求是建立類物件並做一些限制

我們可以找到類物件的類(元類)進行覆蓋其中init方法就能實現需求

當然我們不能改變源**,所以應該繼承type來編寫自己的類,同時覆蓋init來完成需求

#

繼承type元類

#定義了乙個類

class

a(type):

def__init__

(self,class_name,bases,dict):

super().

__init__

(class_name,bases,dict)

self.name =class_name

ifnot

self.name.istitle():

raise

exception

#為asd類指定了元類為a

class asd(metaclass=a):

pass

元類中call方法

當你呼叫類物件時會自動珍惜元類中的__call__方法 ,並將這個類本身作為第乙個引數傳入,以及後面的一堆引數

覆蓋元類中的call之後,這個類就無法產生物件,必須呼叫super().

__call__來完成物件的建立

並返回其返回值

使用場景

當你想控制物件的建立過程時,就覆蓋call方法

當你想控制類的建立過程時,就覆蓋init方法

案例:實現將物件的所有屬性名稱轉為大寫

class

mytype(type):

def__call__(self, *args, **kwargs):

l =for i in

args:

return super().__call__(*l, **kwargs)

class person(metaclass=mytype):

def__init__

(self, name, gender):

self.name =name

self.gender =gender

p = person('

cly','

man'

)print(p.__dict__)

注意:一旦覆蓋了call必須呼叫元類的call方法來產生物件並返回這個物件

當你要建立物件時,會首先執行元類中的__new__方法,拿到乙個空物件,然後會自動呼叫

__init__來對這個類進行初始化操作

注意:如果你覆蓋了該方法則必須保證,new方法必須有返回值且必須是對應的類物件

class

meta(type):

def__new__(cls, *args, **kwargs):

print(cls) #

元類自己

print(args) #

建立類需要的幾個引數 類名,基類,命名空間

print(kwargs) #

空的 print("

new run")

#return super().__new__(cls,*args,**kwargs)

obj = type.__new__(cls,*args,**kwargs)

return

obj

def__init__

(self,a,b,c):

super().

__init__

(a,b,c)

print("

init run")

class a(metaclass=meta):

pass

print(a)

在實現控制類的建立過程來看,new方法與init方法相比,還是init方法比較簡單些

單例:指的是乙個類產生乙個物件

為什麼要用單例?

單例是為了節省資源,當乙個類的所有物件屬性全部相同時,則沒有必要建立多個物件

元類實現:

class

mytype(type):

def__call__(self, *args, **kwargs):

if hasattr(self, '

obj'): #

判斷物件是否已存在物件

return getattr(self,'

obj'

) obj = super().__call__(*args, **kwargs) #

沒有物件就建立乙個

self.obj = obj #

存入類中

return

objclass person(metaclass=mytype):

def__init__

(self,name,age):

self.name =name

self.age =age

p = person('

cly', 18)

p1 = person('

asd','

asd')#

只會存在乙個物件

print(p1.__dict__)

友元類 及用法

什麼是友元類 當乙個類b成為了另外乙個類a的 朋友 時,那麼類a的私有和保護的資料成員就可以被類b訪問。我們就把類b叫做類a的友元。友元類能做什麼 友元類可以通過自己的方法來訪問把它當做朋友的那個類的所有成員。但是我們應該注意的是,我們把類b設定成了類a的友元類,但是這並不會是類a成為類b的友元。說...

友元函式及友元類詳解

在 c 中,乙個類中可以有 public protected private 三種屬性的成員,通過物件可以訪問 public 成員,只有本類中的函式可以訪問本類的 private 成員。現在,我們來介紹一種例外情況 友元 friend 借助友元 friend 可以使得其他類中的成員函式以及全域性範圍...

C 通過反射呼叫類及方法

反射有個典型的應用,就是選單的動態載入,原理就是通過反射呼叫某個窗體 類 下面演示python基礎教程 一下通過反射呼叫類及方法 1 新建乙個類,命名為 reflectionhelper,如下 region 建立物件例項 建立物件例項 物件型別 程式集名稱 命名空間 類名 public static...