一 isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)檢查是否obj是否是類 cls 的對象 issubclass(sub, super)檢查sub類是否是 super 類的派生類 二、反射 2 python面向對象中的反射:通 ...
一 isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)檢查是否obj是否是類 cls 的對象
1 class Foo(object):
2 pass
3
4 obj = Foo()
5
6 isinstance(obj, Foo)
issubclass(sub, super)檢查sub類是否是 super 類的派生類
class Foo(object):
pass
class Bar(Foo):
pass
issubclass(Bar, Foo)
二、反射
2 python面向對象中的反射:通過字元串的形式操作對象相關的屬性。python中的一切事物都是對象(都可以使用反射)
四個可以實現自省的函數
def getattr(object , name, defalut=None) :
判斷object中有沒有一個name字元串對應的方法或屬性
def getattr(object, name, default=None): # known special case of getattr
"""
getattr(object, name[, default]) -> value
Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
When a default argument is given, it is returned when the attribute doesn't
exist; without it, an exception is raised in that case.
"""
pass
def setattr(x,y, v):
def setattr(x, y, v): # real signature unknown; restored from __doc__
"""
Sets the named attribute on the given object to the specified value.
setattr(x, 'y', v) is equivalent to ``x.y = v''
"""
pass
def delattr(x,y):
def delattr(x, y): # real signature unknown; restored from __doc__
"""
Deletes the named attribute from the given object.
delattr(x, 'y') is equivalent to ``del x.y''
"""
pass
實踐案例
class BlackMedium:
feature='Ugly'
def __init__(self,name,addr):
self.name=name
self.addr=addr
def sell_house(self):
print('%s 黑中介賣房子啦,傻逼才買呢,但是誰能證明自己不傻逼' %self.name)
def rent_house(self):
print('%s 黑中介租房子啦,傻逼才租呢' %self.name)
b1=BlackMedium('萬成置地','回龍觀天露園')
#檢測是否含有某屬性
print(hasattr(b1,'name'))
print(hasattr(b1,'sell_house'))
#獲取屬性
n=getattr(b1,'name')
print(n)
func=getattr(b1,'rent_house')
func()
# getattr(b1,'aaaaaaaa') #報錯
print(getattr(b1,'aaaaaaaa','不存在啊'))
#設置屬性
setattr(b1,'sb',True)
setattr(b1,'show_name',lambda self:self.name+'sb')#給Blackhouser添加SB屬性
print(b1.__dict__)
print(b1.show_name(b1))
#刪除屬性
delattr(b1,'addr')
delattr(b1,'show_name')
delattr(b1,'show_name111')#不存在,則報錯
print(b1.__dict__)
類也是對象
class Foo(object):
staticField = "old boy"
def __init__(self):
self.name = 'wupeiqi'
def func(self):
return 'func'
@staticmethod
def bar():
return 'bar'
print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import sys
def s1():
print 's1'
def s2():
print 's2'
this_module = sys.modules[__name__]
hasattr(this_module, 's1')
getattr(this_module, 's2')
#!/usr/bin/env python
# -*- coding:utf-8 -*-
def test():
print('from the test')
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 """ 5 程式目錄: 6 module_test.py 7 index.py 8 9 當前文件: 10 index.py 11 """ 12 13 import module_test as obj 14 15 #obj.test() 16 17 print(hasattr(obj,'test')) 18 19 getattr(obj,'test')()View Code
3 為什麼用反射之反射的好處
好處一:實現可插拔機制
總之反射的好處是,可以事先定義好介面,介面只有在被完成後才會真正執行,這實現了即插即用,這其實是一種‘後期綁定’,什麼意思?即你可以事先把主要的邏輯寫好(只定義介面),然後後期再去實現介面的功能
class FtpClient:
'ftp客戶端,但是還麽有實現具體的功能'
def __init__(self,addr):
print('正在連接伺服器[%s]' %addr)
self.addr=addr
#from module import FtpClient
f1=FtpClient('192.168.1.1')
if hasattr(f1,'get'):
func_get=getattr(f1,'get')
func_get()
else:
print('---->不存在此方法')
print('處理其他的邏輯')
動態導入模塊
三 __setattr__,__delattr__,__getattr__
class Foo:
x=1
def __init__(self,y):
self.y=y
def __getattr__(self, item):
print('----> from getattr:你找的屬性不存在')
def __setattr__(self, key, value):
print('----> from setattr')
# self.key=value #這就無限遞歸了,你好好想想
# self.__dict__[key]=value #應該使用它
def __delattr__(self, item):
print('----> from delattr')
# del self.item #無限遞歸了
self.__dict__.pop(item)
#__setattr__添加/修改屬性會觸發它的執行
f1=Foo(10)
print(f1.__dict__) # 因為你重寫了__setattr__,凡是賦值操作都會觸發它的運行,你啥都沒寫,就是根本沒賦值,除非你直接操作屬性字典,否則永遠無法賦值
f1.z=3
print(f1.__dict__)
#__delattr__刪除屬性的時候會觸發
f1.__dict__['a']=3#我們可以直接修改屬性字典,來完成添加/修改屬性的操作
del f1.a
print(f1.__dict__)
#__getattr__只有在使用點調用屬性且屬性不存在的時候才會觸發
f1.xxxxxx
四 二次加工標準類型(包裝)
包裝:python為大家提供了標準數據類型,以及豐富的內置方法,其實在很多場景下我們都需要基於標準數據類型來定製我們自己的數據類型,新增/改寫方法,這就用到了我們剛學的繼承/派生知識(其他的標準類型均可以通過下麵的方式進行二次加工)
授權:授權是包裝的一個特性, 包裝一個類型通常是對已存在的類型的一些定製,這種做法可以新建,修改或刪除原有產品的功能。其它的則保持原樣。授權的過程,即是所有更新的功能都是由新類的某部分來處理,但已存在的功能就授權給對象的預設屬性。
實現授權的關鍵點就是覆蓋__getattr__方法
import time
class FileHandle:
def __init__(self,filename,mode='r',encoding='utf-8'):
self.file=open(filename,mode,encoding=encoding)
def write(self,line):
t=time.strftime('%Y-%m-%d %T')
self.file.write('%s %s' %(t,line))
def __getattr__(self, item):
return getattr(self.file,item)
f1=FileHandle('b.txt','w+')
f1.write('你好啊')
f1.seek(0)
print(f1.read())
f1.close()
描述符註意事項:
一 描述符本身應該定義成新式類,被代理的類也應該是新式類
二 必須把描述符定義成這個類的類屬性,不能為定義到構造函數中
三 要嚴格遵循該優先順序,優先順序由高到底分別是
1.類屬性
2.數據描述符
3.實例屬性
4.非數據描述符
5.找不到的屬性觸發__getattr__()
其中
數據描述符、數據描述符:至少實現了__get__()和__set__()
非數據描述符、沒有實現__set__()