最近在對RF的通訊層的模塊進行封裝,需要將之前放在類似main里面的一個方法,如下所示:這段代碼是開發提供,用於接口測試,模擬底層通訊,具體的通訊是在dll內,python這邊只是做了個封裝讓RF進行調用。這段通訊層的代碼實質上做了五件事:
第一:加載dll;
第二:初始化dll內的通訊參數;
第三:與服務器進行連接,創建session
第四:把數據senbuffer通過sessionManger發送給服務器
第五:取得的數據返回recibuffer
def testlogin(ip,port,buf): dllName = "SessionConnector.dll" dllABSPath = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + dllName dll = cdll.LoadLibrary(dllABSPath) dll.Init.restype = c_bool; ret = dll.Init(); dll.CreateSession.argtypes=[c_char_p,c_char_p] dll.CreateSession.restype = c_int; session_id = dll.CreateSession(ip,port); time.sleep(2); dll.SendSessionMsg.argtypes=[c_int,c_char_p,c_uint] dll.CreateSession.restype = c_bool; send_msg = buf ret = dll.SendSessionMsg(session_id, send_msg, len(send_msg) + 1); dll.RecvSessionMsg.argtypes=[c_int,c_char_p,c_uint,c_int] dll.RecvSessionMsg.restype = c_bool; recv_buf = create_string_buffer(1024); ret = dll.RecvSessionMsg(session_id, recv_buf, 1024, 3000); return recv_buf.value
很明顯存在很多的問題。最明顯的就是這個模塊中,第一和第二,第三的前3個步驟,不是每個接口都必須做的事情,所有接口在測試之前干完這些事就可以了。所有這塊代碼必須得弄成一個類模塊,再打成一個包,然后做為關鍵字提供給RF工具在寫case的時候使用,於是就開始重點的關注了下python的類和對象,粗看的時候改寫代碼是這樣的:
class Main_class_dll(): def __init__(self): dllName = "SessionConnector.dll" dllABSPath = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + dllName self.dll = cdll.LoadLibrary(dllABSPath) self.session_id='' def int_create_(self): self.dll.Init.restype = c_bool sign = self.dll.Init() def Create_Session(self,ip,port): self.dll.CreateSession.argtypes=[c_char_p,c_char_p] #輸入參數的格式 self.dll.CreateSession.restype = c_int; #輸出參數的格式 self.session_id = self.dll.CreateSession(ip,port); def send_recv(self,buf): time.sleep(2) self.dll.SendSessionMsg.restype = c_bool; self.dll.SendSessionMsg.argtypes=[c_int,c_char_p,c_uint] ret = self.dll.SendSessionMsg(self.session_id, buf, len(buf) + 1); self.dll.RecvSessionMsg.argtypes=[c_int,c_char_p,c_uint,c_int] self.dll.RecvSessionMsg.restype = c_bool; recv_buf = create_string_buffer(1024); ret = self.dll.RecvSessionMsg(self.session_id, recv_buf, 1024, 3000); self.dll.DestroySession.restype = c_bool; ret = self.dll.DestroySession(self.session_id); return recv_buf.value
然后在RF里調用,老是報錯,調試后是發現初始化都有問題,dll也都沒加載起來。后面仔細想想,確實覺得這樣寫是有問題的,__init__方法,表示創建的實例本身時調用的函數進行初始化用的,但是在RF內,始終就沒有去創建一個類的實例,直接導入后,使用里面的函數做關鍵字就可以了,那就是能提供類對象,直接操作類的函數。那類對象和實例對象有什么區別呢?
類對象就是可以用類名字直接使用表示的對象,它支持兩種操作,直接屬性使用和實例化。對於類屬性的使用,直接使用類名.屬性即可。對於類方法的使用,需要實例化一個對象后,將對象名賦值給self使用,如下所示:
class test: data = 1 def __init__(self): self.property=0 def test2(self): print 'hello' if __name__=='__main__': t = test() print test.data print t.data print test.test2 print t.test2() print test.test2(t)
運行結果如下:
1
1
<unbound method test.test2>
hello
hello
那實例對象和類對象分別修改數據成員變量,會是怎么樣的呢?
class test: data = 1 def __init__(self): self.property=0 def test2(self): return 'hello' if __name__=='__main__': test1= test() test2=test() print 'test.data = ',test.data print 'id of test.data', id(test.data) print '*'*10 print 'test1.data = ',test1.data print 'id of test1.data', id(test1.data) print '*' * 10 print 'test2.data = ',test2.data print 'id of test2.data', id(test2.data) print '*' * 10 test1.data = 2 print 'test1.data = ', test1.data print 'id of test1.data', id(test1.data) print 'test.data = ', test.data print 'id of test.data', id(test.data) print '*' * 10 print 'test2.data = ', test2.data print 'id of test2.data', id(test2.data) print '*' * 10 test1.__class__.data= 2 print 'test1.data = ', test1.data print 'id of test1.data', id(test1.data) print '*' * 10 print 'test2.data = ', test2.data print 'id of test2.data', id(test2.data) print '*' * 10 print 'test.data = ', test.data print 'id of test.data', id(test.data) print '*' * 10
運行結果如下:
test.data = 1 id of test.data 37285680 ********** test1.data = 1 id of test1.data 37285680 ********** test2.data = 1 id of test2.data 37285680 ********** test1.data = 2 id of test1.data 37285668 test.data = 1 id of test.data 37285680 ********** test2.data = 1 id of test2.data 37285680 ********** test1.data = 2 id of test1.data 37285668 ********** test2.data = 2 id of test2.data 37285668 ********** test.data = 2 id of test.data 37285668 **********
從這個例子得出一個結論:
總結 : 第一:作為test的類對象的變量 (data),每次創建一個新的實例對象,類對象變量就多一個引用指向它,通過實例對象來修改類對象的變量的取值,實際上是讓實例對象 的data指向了另外一塊內存變量。實例對象是類對象的一個拷貝。 第二:可以通過實例對象.__class_.data 來獲取類對象的data值,改變類對象的變量的值后,相應實例的值也會發生變化。 類對象的變量在實例中實際上是只讀的,任何實例都無法修改類對象變量的值(test1.data=2 實際上是讓實例的變量指向了另一塊內存,當再生成一個新的對象時, 值仍然還是1),通過實例對象.__class_.data可以修改類對象的屬性值
然后又想到一個問題,類成員的變量,實例對象生成的時候就有么?實例成員變量,類對象直接就有么?這就需要用到vars()來測試一下:dir(object)和vars(object)是用來查看模塊的attribute和properties的;其中通過help()得到官方的解釋如下:
dir使用: dir([object]) -> list of strings
for a module object: the module's attributes.
for a class object: its attributes, and recursively the attributes of its bases.
for any other object: its attributes, its class's attributes, and recursively the attributes of its class's base classes.
vars使用:vars([object]) -> dictionary
Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.
class test3: __value1=0 value2=0 def __init__(self): self.__value3=0 def testit(self): pass if __name__=='__main__': test=test3() print 'vars(test)=',vars(test) print 'vars(test3)=',vars(test3) print 'dir(test)=', dir(test) print 'dir(test3)=', dir(test3)
運行結果:
vars(test)= {'_test3__value3': 0} vars(test3)= {'__module__': '__main__', 'testit': <function testit at 0x027831B0>, '_test3__value1': 0, 'value2': 0, '__doc__': None, '__init__': <function __init__ at 0x027831F0>} dir(test)= ['__doc__', '__init__', '__module__', '_test3__value1', '_test3__value3', 'testit', 'value2'] dir(test3)= ['__doc__', '__init__', '__module__', '_test3__value1', 'testit', 'value2']
dir:如果是一個模塊對象,就是一個模塊的屬性;如果是一個類對象,就是類及其父類的屬性;如果是其他對象,就是它本身的屬性和它的類對象以及其父類的對象。只顯示其屬性字段,不顯示其值。
vars:vars(object)等價於 object.__dict__,顯示當前命名空間內的屬性和值。
私有成員分:類對象的變量私有和實例對象的變量私有,對於類對象的私有成員,在實例對象生成初期,實例對象的命名空間內是不存在類對象的任何變量(不管私有或公有),實例對象是無法直接修改的,可以通過實例對象.類名.類對象的私有成員來進行訪問和修改,之后命名空間內就有了該數據的引用。
明白了類對象和實例對象的不同之后,修改腳本如下所示,測試終於能跑通了~~~
class Main_class_dll(): dllName = "SessionConnector.dll" # 僅僅是定義了一個string 字符串而已 dllABSPath = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + dllName dll = cdll.LoadLibrary(dllABSPath) session_id='' def __init__(self): pass def int_create_(self): self.dll.Init.restype = c_bool sign = self.dll.Init() def Do_work_connector(self,ip,port): self.dll.CreateSession.argtypes=[c_char_p,c_char_p] #輸入參數的格式 self.dll.CreateSession.restype = c_int; #輸出參數的格式 self.session_id = self.dll.CreateSession(ip,port); def Do_work_send_recv(self,buf): time.sleep(2) self.dll.SendSessionMsg.restype = c_bool; self.dll.SendSessionMsg.argtypes=[c_int,c_char_p,c_uint] ret = self.dll.SendSessionMsg(self.session_id, buf, len(buf) + 1); self.dll.RecvSessionMsg.argtypes=[c_int,c_char_p,c_uint,c_int] self.dll.RecvSessionMsg.restype = c_bool; recv_buf = create_string_buffer(1024); ret = self.dll.RecvSessionMsg(self.session_id, recv_buf, 1024, 3000); self.dll.DestroySession.restype = c_bool; ret = self.dll.DestroySession(self.session_id); return recv_buf.value def Close_Session(self): self.dll.MainSessionClosed.argtypes = [c_int] self.dll.MainSessionClosed.restype = None self.dll.MainSessionClosed(self.session_id)