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)

 

        

posted @ 2016-04-21 19:50  loleina  阅读(28900)  评论(2编辑  收藏  举报