1. 程式人生 > >Python開發基礎----反射、面向對象進階

Python開發基礎----反射、面向對象進階

elf bob 是否 pro sat 自己的 代碼 改變 數據類型

isinstance(obj,cls)和issubclass(sub,super)

isinstance(obj,cls)檢查是否obj是否是類 cls 的對象,如果是返回True

1 class Foo(object):
2     pass
3 obj = Foo()
4 print(isinstance(obj, Foo))

issubclass(sub, super)檢查sub類是否是 super 類的派生類,如果是返回True

1 class Foo(object):
2     pass 
3 class Bar(Foo):
4     pass
5 issubclass(Bar, Foo)

反射

反射主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。

python面向對象中的反射:通過字符串的形式操作對象相關的屬性。而python中的一切事物都是對象,即都可以使用反射。

示例代碼:

1 class Teacher:
2     school=‘jialidun‘
3     def __init__(self,name,age):
4         self.name=name
5         self.age=age
6     def teach(self):
7         print(‘%s teach‘ %self.name)

通過字符串的方式判斷是否存在一個屬性:

1 t=Teacher(‘bob‘,18)
2 print(hasattr(Teacher,‘name‘))  #False
3 print(hasattr(Teacher,‘school‘))    #True
4 print(hasattr(Teacher,‘teach‘))     #True
5 print(hasattr(t,‘name‘))  #True
6 print(hasattr(t,‘school‘))    #True
7 print(hasattr(t,‘teach‘))     #True

通過字符串的方式獲取一個屬性:

1 print(getattr(Teacher,‘school‘))    #獲取到則返回屬性的值
2 print(getattr(Teacher,‘sdfad‘,None))    #獲取不到返回None,如果不指定None那麽拋出異常錯誤

通過字符串的方式設定一個屬性:

1 setattr(Teacher,‘sex‘,‘male‘)    #設定Teacher類的屬性sex=‘male‘
2 setattr(t,‘sex‘,‘female‘)    #設定對象t對象的屬性sex=‘female‘
3 print(Teacher.__dict__)
4 print(t.__dict__)

通過字符串的方式刪除一個屬性:

1 delattr(Teacher,‘sex‘)
2 delattr(t,‘sex‘)

反射應用場景:用戶交互

 1 class Cmd:
 2     def __init__(self,name):
 3         self.name=name
 4     def run(self):
 5         while True:
 6             cmd=input(‘>>>‘).strip()
 7             if not cmd:continue
 8             if hasattr(self,cmd):    #判斷這個類包含不包含輸入的屬性
 9                 func=getattr(self,cmd)    #如果包含,獲取該屬性
10                 func()    #執行該屬性(輸入name會拋錯提示字符串不能被調用,因為name是一個數據屬性,而非函數屬性)
11             else:
12                 print(‘not valid func‘)
13     def ls(self):
14         print(‘ls function‘)
15     def pwd(self):
16         print(‘pwd function‘)
17     def cat(self):
18         print(‘cat function‘)
19 c=Cmd(‘bob‘)
20 c.run()

反射的好處

實現可插拔機制:可以事先定義好接口,接口只有在被完成後才會真正執行,這實現了即插即用,這其實是一種‘後期綁定’,即可以事先把主要的邏輯寫好(只定義接口),然後後期再去實現接口的功能

動態導入模塊:基於反射當前模塊成員

__str__方法

改變對象的字符串顯示

 1 class Teacher:
 2     def __init__(self,name,age):
 3         self.name=name
 4         self.age=age
 5 t=Teacher(‘bob‘,18)
 6 print(t)
 7 輸出結果
 8 <__main__.Teacher object at 0x0000020FC4DA9278>
 9 
10 #########分割線君###########
11 
12 class Teacher:
13     def __init__(self,name,age):
14         self.name=name
15         self.age=age
16     def __str__(self):
17         return ‘<name:%s age:%s>‘ % (self.name, self.age)
18 t=Teacher(‘bob‘,18)
19 print(t)    #t.__str__()
20 輸出結果:類中的__str__函數的執行結果
21 <name:bob age:18>

__del__方法

在程序執行完了之後會自動執行的內容

 1 class Foo:
 2     def __init__(self,x):
 3         self.x=x
 4     def __del__(self):
 5         print(‘執行__del__‘)
 6         ‘‘‘一般用來做一些關於對象執行完了之後剩下的垃圾的清理操作‘‘‘
 7 f=Foo(10)
 8 print(‘執行完了‘)
 9 
10 輸出結果:先執行最後的print,沒有代碼了執行__del__函數
11 執行完了
12 執行__del__

刪除對象後立即執行的內容

 1 class Foo:
 2     def __init__(self,x):
 3         self.x=x
 4     def __del__(self):
 5         print(‘執行__del__‘)
 6         ‘‘‘做一些關於對象的清理操作‘‘‘
 7 f=Foo(10)
 8 del f     #刪除的時候也會執行del內容
 9 print(‘執行完了‘)
10 
11 輸出結果:刪除了f對象後執行了__del__後才執行最後的print
12 執行__del__
13 執行完了

item系列

以中括號的方式進行處理類似於:

1 l=[‘a‘,‘b‘,‘c‘]
2 dic={‘a‘:1}
3 print(l[1])
4 print(dic[‘a‘])

__getitem__、__setitem__、__delitem__

 1 class Teacher:
 2     def __init__(self,name,age,sex):
 3         self.name=name
 4         self.age=age
 5         self.sex=sex
 6     def __getitem__(self, item):    #查詢
 7         # return getattr(self,item)
 8         return self.__dict__[item]
 9     def __setitem__(self, key, value):    #設置
10         # setattr(self,key,value)
11         self.__dict__[key]=value
12     def __delitem__(self, key):    #刪除
13         # delattr(self,key)
14         self.__dict__.pop(key)
15 f=Teacher(‘bob‘,18,‘male‘)
16 print(f.name) #f[‘name‘]
17 print(f[‘name‘])    #查詢
18 f[‘name‘]=‘bob_nb‘    #設置
19 print(f.__dict__)
20 del f[‘name‘]    #刪除
21 print(f.__dict__)

__len__方法

給對象提供len()統計方法

1 class Teacher:
2     def __init__(self,name,age,sex):
3         self.name=name
4         self.age=age
5         self.sex=sex
6     def __len__(self):    #長度設置為10
7         return 10
8 f=Teacher(‘bob‘,18,‘male‘)
9 print(len(f))    #輸出10

其他方法(補充)

__setattr__,__delattr__,__getattr__方法

 1 class Foo:
 2     x=1
 3     def __init__(self,y):
 4         self.y=y
 5     def __getattr__(self, item):
 6         print(‘----> from getattr:你找的屬性不存在‘)
 7     def __setattr__(self, key, value):  #限制賦值,無法對屬性直接賦值,必須要對__dict__進行操作賦值
 8         print(‘----> from setattr‘)
 9         # self.key=value #這就無限遞歸了,任何賦值操作都會調用__setattr__的運行,所以....
10         # self.__dict__[key]=value #應該使用這種方式,操作字典可以賦值成功
11     def __delattr__(self, item):
12         print(‘----> from delattr‘)
13         # del self.item #無限遞歸了,同__setattr__方法的無限遞歸
14         self.__dict__.pop(item)
15 #__setattr__添加/修改屬性會觸發它的執行
16 f1=Foo(10)
17 f1.__setattr__(‘a‘,1)   #不是直接操作字典,無法賦值
18 print(f1.__dict__) # 因為重寫了__setattr__,凡是賦值操作都會觸發它的運行,什麽都不寫,就是根本沒賦值,除非直接操作屬性字典,否則永遠無法賦值
19 f1.z=3
20 print(f1.__dict__)
21 #__delattr__刪除屬性的時候會觸發
22 f1.__dict__[‘a‘]=3#我們可以直接修改屬性字典,來完成添加/修改屬性的操作
23 del f1.a    #刪除的時候如果上面函數是del self.item,會無限遞歸
24 print(f1.__dict__)
25 
26 #__getattr__只有在使用點調用屬性且屬性不存在的時候才會觸發
27 f1.xxxxxx

包裝(對標準數據類型進行方法修改)

通過繼承和派生的方式,進行修改源生數據類型的方法

 1 class List(list): #繼承list所有的屬性,也可以派生出自己新的,比如append和mid
 2     def append(self, p_object):
 3         ‘派生自己的append:加上類型檢查‘
 4         if not isinstance(p_object,int):
 5             raise TypeError(‘must be int‘)
 6         super().append(p_object)
 7     @property
 8     def mid(self):
 9         ‘新增自己的屬性‘
10         index=len(self)//2
11         return self[index]

Python開發基礎----反射、面向對象進階