zoukankan      html  css  js  c++  java
  • 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)

            

  • 相关阅读:
    FirewallD 详解
    EventBus源码解析
    详谈 Jquery Ajax 异步处理Json数据.
    jQuery Ajax异步处理Json数据详解
    7款jQuery图片轮播滑动插件
    分享15款为jQuery Mobile定制的插件
    在springmvc中解决FastJson循环引用的问题
    SpringMVC与fastjson整合并同时解决中文乱码问题
    SpringMVC处理ajax请求
    spring mvc 返回json的配置
  • 原文地址:https://www.cnblogs.com/loleina/p/5409084.html
Copyright © 2011-2022 走看看