python—類對象和實例對象的區別


      最近在對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)

 

        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM