• python异常处理、反射、socket


    一、isinstance 判断对象是否为类的实例

    n1 = 10
    print isinstance(n1,int)
    class A:
       pass
    class B(A):
       pass
    
    b= B()
    print isinstance(b,B)
    print isinstance(b,A)
    
    ===================
    D:pythonpython.exe D:/python_scripts/11S_08day/index.py
    True
    True
    True

    注意:1、isinstance用于判断对象是否为类的实例

           2、类为创建对象的类或创建对象的类的基类

     issubclass 判断B是否为A的派生类
    
    print issubclass(B,A)
    print issubclass(B,int)
    
    ==================
    True
    False
    

    二、异常处理应用场景

    异常处理:

    1、当网页URL没有被处理的时候返回大黄页(错误);

    2、如下代码:

    inpu = raw_input()
    data = int(inpu)
    
    如果输入的不是数字,那么就会报错
    View Code

    那么实际应用中需要考虑到这些可能出现的异常:

    如下:

    try:
        #正常逻辑代码
        inpu = raw_input()
        data = int(inpu)
    except Exception,e:
        #逻辑代码块出现错误
        print e
        print "请输入数字"
        #可以将错误信息写入日志,e
    ########结果如下############
    D:pythonpython.exe D:/python_scripts/11S_08day/index.py
    ddd
    invalid literal for int() with base 10: 'ddd'
    请输入数字
    View Code

    但是上述代码没有将错误分门别类:

    try:
        li = [11,22,33]
        li[100]
    
    except IndexError,e:
        print 'error',e
    except TypeError,e:
        print e
    #以后再使用时,先写详细的错误,最后写一个except Exception,e:
    View Code

    三、异常处理之自定义异常

    一般异常处理代码块包含如下代码块:

    try:
        #逻辑代码,链接数据库,执行sql
        pass
    except IndexError,e:
        pass
    except Exception,e:
        pass
    else:
        #逻辑块中未出现异常时执行
        pass
    finally:
        #断开链接,释放资源
        #永远执行,逻辑代码执行完成之后
        pass
    View Code

    那么,异常处理中e是什么?

    try:
        int('abcde')
    except Exception,e:
        #e是对象,是由Exception类创建的
        print e
    
    #######################
    class A:
        pass
    obj = A()
    print obj    #返回对象的内存地址
    #######################
    #调用__str__方法
    class A:
        def __str__(self):
            return 'sb'
    obj = A()
    print obj
    
    #######结果#############
    D:pythonpython.exe D:/python_scripts/11S_08day/index.py
    invalid literal for int() with base 10: 'abcde'
    <__main__.A instance at 0x000000000259A748>
    sb
    View Code

    事实上,e返回的是Exception中的__str__方法,这样的话我们就可以写自己的异常了。

    那么如何自定义异常:

    class CharlesError(Exception):   #自定义类继承Exception类
        def __str__(self):
            return 'Charles Error'
    try:
        raise CharlesError()    #触发异常
    except Exception,e:
        print e
    #########结果#############
    D:pythonpython.exe D:/python_scripts/11S_08day/index.py
    Charles Error
    View Code

    上述自定义异常是写死了的,如何灵活返回?

    class CharlesError(Exception):   #自定义类继承Exception类
        def __init__(self,msg=None):
            self.massage = msg
        def __str__(self):
            if self.massage:
                return self.massage
            else:
                return 'Charles Error'
    
    try:
        obj = CharlesError('123')
        raise obj    #触发异常
    except Exception,e:
        print e
    #########结果#############
    D:pythonpython.exe D:/python_scripts/11S_08day/index.py
    123
    View Code

    四、自定义异常之断言

    assert 条件    #如果条件满足,不报错,条件不满足,就报错
    
    1、在程序测试的时候使用;
    2、满足条件,可以使用程序,不满足,就不可以使用;
    3、一般不要使用;
    View Code

    总结异常处理:

    try:
        #主代码块
        pass
    except KeyError,e:
        #异常时,执行该块
        pass
    else:
        #主代码执行完,执行该块
        pass
    finally:
        #无论异常与否,最终执行该块
        pass
    
    
    要求:
        1、熟悉四个代码块的执行流程;
        2、e是调用了Exception类中的__str__方法;
        3、raise触发异常,在做大项目的时候,代码分层之后会用到;
    View Code

    五、反射和普通方式对比(模拟web框架)

    先看一个例子,如下:

    存在两个url文件home.py和account.py
    #home.py
    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    
    def dev():
        return 'result,home.dev'
    
    def index():
        return 'result,home.index'
    
    #account.py
    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    
    def login():
        return 'account.login'
    
    def logout():
        return 'account.logout'
    
    index.py文件(如下)调用上述两个文件:
    import home,account
    print 'Charles...'
    url = raw_input('url:')
    if url == 'home/dev':
        ret = home.dev()
        print ret
    elif url == 'home/index':
        ret = home.index()
        print ret
    elif url == 'account/login':
        ret = account.login()
        print ret
    else:
        print 404
    ################结果为#############
    D:pythonpython.exe D:/python_scripts/11S_08day/index.py
    Charles...
    url:ddd
    404
    View Code

    但是一个网站存在有大量的url文件,如果全部使用if...else访问处理的话,那么就是很不明智的;

    那么如何处理呢???

    事实上,web程序存在框架可以处理,常见的有mvc和mtv两张框架,如下图:

    在python中,如何处理的呢?

    controller,action = raw_input('url:').split('/')
    #如何去找url,使用简单反射代理处理
    import home
    #action = 字符串
    #去某个模块中招函数,字符串为函数名,如果有,则获取函数
    func = getattr(home,action)
    ret = func()
    print ret
    
    #########结果为#############
    D:pythonpython.exe D:/python_scripts/11S_08day/index.py
    url:home/dev
    result,home.dev
    View Code

    六、反射操作中的成员

     反射的执行,有两种方式:

    a、
    import home
    home.dev()
    s = "dev" ###
    home.dev  ###这两种方式不同
    
    b、
    import home
    func = getattr(home,"dev")
    func()
    View Code

    getattr,setattr,delattr,hasattr的使用(操作内存中某个容器的元素)

    import home
    print dir(home)   #查看模块中存在哪些成员
    
    print hasattr(home,'abcd')   #判断函数abcd是否是模块home的成员
    
    print getattr(home,"dev")
    
    setattr(home,'Charles',lambda x:x+1)    #相当于在home模块中添加了一个Charles函数
    
    
    delattr(home,"dev")    #删除dev成员函数(在内存中删除,而不改变文件内容)
    print dir(home)
    
    ##########结果为#############
    D:pythonpython.exe D:/python_scripts/11S_08day/index.py
    ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'dev', 'index']
    False
    <function dev at 0x0000000001E02518>
    ['Charles', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'index']
    View Code

    七、反射操作类和对象中的成员

    class Foo:
        static_name = 'NB'
        def __init__(self):
            self.name = 'Charles'
        def show(self):
            pass
    
        @staticmethod
        def static_show():
            pass
        @classmethod
        def class_show(cls):
            pass
    
    obj = Foo()
    print Foo.__dict__
    print Foo.__dict__.keys()   #类中的成员
    
    print obj.__dict__
    ############结果为############
    D:pythonpython.exe D:/python_scripts/11S_08day/index.py
    {'static_show': <staticmethod object at 0x000000000249E318>, '__module__': '__main__', 'show': <function show at 0x000000000254C7B8>, 'static_name': 'NB', 'class_show': <classmethod object at 0x000000000249E858>, '__doc__': None, '__init__': <function __init__ at 0x000000000254C748>}
    ['static_show', '__module__', 'show', 'static_name', 'class_show', '__doc__', '__init__']
    {'name': 'Charles'}
    View Code

    接下来使用getattr和setattr操作对象

    class Foo:
        static_name = 'NB'
        def __init__(self):
            self.name = 'Charles'
        def show(self):
            pass
    
        @staticmethod
        def static_show():
            pass
        @classmethod
        def class_show(cls):
            pass
    
    obj = Foo()
    print Foo.__dict__
    print Foo.__dict__.keys()
    
    print obj.__dict__
    
    print hasattr(obj,'name')
    print hasattr(obj,'show')
    
    
    ##########结果##############
    D:pythonpython.exe D:/python_scripts/11S_08day/index.py
    {'static_show': <staticmethod object at 0x000000000258E318>, '__module__': '__main__', 'show': <function show at 0x000000000263C7B8>, 'static_name': 'NB', 'class_show': <classmethod object at 0x000000000258E858>, '__doc__': None, '__init__': <function __init__ at 0x000000000263C748>}
    ['static_show', '__module__', 'show', 'static_name', 'class_show', '__doc__', '__init__']
    {'name': 'Charles'}
    True    ????为什么
    True
    
    
    因为:#因为是类寻找的话,会在自己的成员中找,而对象寻找的话,会现在自己的内存中找,如果没有找到,会到创建对象的类中找(通过类对象指针)
    View Code

    反射当前模块中的成员

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    import sys
    
    
    def s1():
        print 's1'
    
    
    def s2():
        print 's2'
    
    
    this_module = sys.modules[__name__]
    print this_module
    
    print hasattr(this_module, 's1')
    ret =getattr(this_module, 's2')
    ret()
    View Code

    八、反射操作中的多层嵌套成员

    模块home.py存在如下内容:

    class Foo:
        static_name = "NB"
        def __init__(self):
            self.name = "Charles"
        def show(self):
            pass
    View Code

    模块index.py调用home模块

    import home
    cls = getattr(home,"Foo")
    print cls
    
    s_name = getattr(cls,'static_name')
    print s_name
    
    obj = cls()
    
    name = getattr(obj,'name')
    print name
    
    ##########结果为###############
    D:pythonpython.exe D:/python_scripts/11S_08day/index.py
    home.Foo
    NB
    Charles
    View Code

    总结:反射可以操作各种对象,如模块、类、实例化对象、函数、字段、方法等等。

    九、动态模块导入

    前面的**attr操作,可以根据用户输入不同的url,自动查找指定模块中url函数,那么如果存在大量的URL模块,我们在使用之前是不是都得import一下呢?

    事实上,模块也可以通过字符串的方式由用户导入,具体方法如下:

    import home
    module = __import__("home")  #类似于import home as module
    controller,action = raw_input("URL:").split('/')
    module1 = __import__(controller)
    
    func = getattr(module,action)
    ret = func()
    print ret
    View Code

    可以利用动态导入模块的方法完善web框架

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    from wsgiref.simple_server import make_server
    
    def RunServer(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html')])
        url = environ['PATH_INFO']
        module_name  = url.split('/')[1]
        function_name =url.split('/')[2]
        module = __import__(module_name)
        is_exist = hasattr(module,function_name)
        if is_exist:
            func = getattr(module,function_name)
            ret = func()
            return ret
        else:
            return '404 not found'
    
    if __name__ == '__main__':
        httpd = make_server('', 8001, RunServer)
        print "Serving HTTP on port 8001..."
        httpd.serve_forever()
    View Code

    十、设计模式之单例模式

    单例模式,顾名思义就是单个实例

    单例模式--->内存中之存在一个实例,如果想要使用类中的功能,只使用这一个实例(内存中的)

    看下面的例子:

    模块userinfo.py内容如下:
    
    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    
    class SqlHelper:
        def __init__(self):
            self.hostname = '0.0.0.0'
            self.port = 3306
            self.user = 'root'
            self.pwd = '123'
    
        def fetch(self):
            pass
    
        def remove(self):
            pass
    
    
    def get_user():
        obj = SqlHelper()
        obj.fetch()
        print id(obj)    #对次调用会创建多个实例,刷新会显示不同的id值
        return '1'
    
    def del_user():
        obj = SqlHelper()     #此方法和上一个方法中创建的两个实例,在使用完之后,会被python的垃圾回收机制销毁,也就是在调用的时候回分别创建,但是这是没有必要的,那么如何让相同的实例只创建一份呢?如何实现
        obj.remove()
        return '2'
    View Code

    效果如下:

    下面使用单利模式,使得每次调用时只调用之前实例化的相同的实例

    例子如下:

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    class SqlHelper:
        __static_instance = None
        def __init__(self):
            self.hostname = '0.0.0.0'
            self.port = 3306
            self.user = 'root'
            self.pwd = '123'
    
        @classmethod
        def instance(cls):
            if cls.__static_instance:
                return cls.__static_instance
            else:
                cls.__static_instance = SqlHelper()
                return cls.__static_instance
    
        def fetch(self):
            pass
    
        def remove(self):
            pass
    
    
    def get_user():
        obj = SqlHelper.instance()    #创建实例都用类方法
        obj.fetch()
        print id(obj)
        return '1'
    
    def del_user():
        obj = SqlHelper.instance()
        obj.remove()
        return '2'
    
    
    print id(SqlHelper.instance())
    print id(SqlHelper.instance())
    print id(SqlHelper.instance())
    print id(SqlHelper.instance())
    
    
    ###这样做在大数据量的时候,所有的数据库,连接都只连接在一个实例,有可能会出现问题,建议在数据量少的时候使用
    View Code

    效果如下:

    如果不使用web框架,多个实例化结果如下:

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    class SqlHelper:
        __static_instance = None
        def __init__(self):
            self.hostname = '0.0.0.0'
            self.port = 3306
            self.user = 'root'
            self.pwd = '123'
    
        @classmethod
        def instance(cls):
            if cls.__static_instance:
                return cls.__static_instance
            else:
                cls.__static_instance = SqlHelper()
                return cls.__static_instance
    obj1=SqlHelper.instance()
    print id(obj1)
    obj2=SqlHelper.instance()
    print id(obj2)
    View Code

    结果如下:

    D:pythonpython.exe D:/python_scripts/11S_08day/单例模式.py
    39048904
    39048904
    View Code

    12、socket原理和web框架的实现

    使用浏览器模拟客户端,server端代码如下:

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    
    import socket
    
    def main():
        #创建socket对象
        sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        #监听端口
        sock.bind(('localhost',8080))
        #开始监听
        sock.listen(5)    #最大连接数
    
        while True:
            #阻塞,等
            #直到有请求连接
            connection,address = sock.accept()
            #connection,代表客户端socket对象
            #address,客户端IP地址
            buf = connection.recv(1024)
            connection.send("HTTP/1.1 200 OK
    
    ")
            connection.send("Hello,World!")
            connection.close()
    
    if __name__ == '__main__':
        main()
    View Code

    简单例子:

    server端:

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    
    import socket
    
    obj_server = socket.socket()
    obj_server.bind(('localhost',8314))
    obj_server.listen(5)
    
    while True:
        print 'writing....'
        conn,addr = obj_server.accept()
        print obj_server.getsockname()  #返回服务器的ip和端口
        #最多接受size
        client_data = conn.recv(1024)
        print client_data
        conn.send('不要回答,不要回答,不要回答')    #发送到缓冲区
        #conn.sendall('abc')   #写到缓冲区之后立即发送
        conn.close()    #关闭连接,但是不关闭socket服务
    View Code

    client端:

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    import socket
    
    obj = socket.socket()
    obj.connect(('localhost',8314))
    print obj.getpeername() #返回服务器的ip和端口
    obj.send('请占领地球')
    server_data = obj.recv(1024)
    print server_data
    obj.close()    #关闭socket服务
    View Code

    如何根据用户输入的信息的关键字,返回特定的应答,模拟10086如下:

    server端:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    
    import socket
    
    ip_port = ('127.0.0.1',8888)
    sk = socket.socket()
    sk.bind(ip_port)
    sk.listen(5)
    
    while True:
        conn,address =  sk.accept()
        conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
        Flag = True
        while Flag:
            data = conn.recv(1024)
            if data == 'exit':
                Flag = False
            elif data == '0':
                conn.sendall('通过可能会被录音.balabala一大推')
            else:
                conn.sendall('请重新输入.')
        conn.close()
    View Code

    client端:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import socket
    ip_port = ('127.0.0.1',8888)
    sk = socket.socket()
    sk.connect(ip_port)
    sk.settimeout(5)
    
    while True:
        data = sk.recv(1024)
        print 'receive:',data
        inp = raw_input('please input:')
        sk.sendall(inp)
        if inp == 'exit':
            break
    
    sk.close()
    View Code

    13、socket详细方法

    obj_server.setblocking(False):默认在遇到accept或recv的时候回阻塞,但是如果是obj_server.setblocking(False)那么就不阻塞,但是server端accept如果没有接受到数据的话就会报错,实际在使用的时候,应用于epoll模型中,结合select使用;

     大神alex的FTP开发博文      大神gethub上的相关代码

    14、socket使用多线程实现

     server端:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import SocketServer
    import os
    class MyServer(SocketServer.BaseRequestHandler):
    
        def handle(self):    #必须为handle
            print "--got connection from---",self.client_address
            while True:
                data = self.request.recv(1024)
                print "Recv from[%s] cmd %s" %(self.client_address,data)
    
                cmd_res = os.popen(data).read()
                print 'cmd_res:',len(cmd_res)
                self.request.send( str(len(cmd_res)))
                self.request.sendall(cmd_res)
    if __name__ == '__main__':
        server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)    #将Myclass类实例化,真正实现多线程
        server.serve_forever()    #相当于一个while循环,是select while循
    View Code

    client端:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import socket
    ip_port = ('127.0.0.1',8009)
    sk = socket.socket()
    sk.connect(ip_port)
    sk.settimeout(5)
    
    while True:
        #data = sk.recv(1024)    #接受消息
        #print 'receive:',data
        inp = raw_input('please input:')
        sk.sendall(inp)
        res_size = sk.recv(1024)
        print "going to recv data size:",res_size,type(res_size)
        total_size = int(res_size)
        receive_size = 0
        while True:
            data = sk.recv(1024)
            receive_size +=len(data)
            print '-----data-----'
            if total_size == receive_size:
                print data
                print '---not data---'
                break
                #sk.sendall(inp)
                #if inp == 'exit':
                #    break
    
    sk.close()
    View Code

     socket传输大数据和解决socket粘包参考如下:

    http://www.cnblogs.com/alex3714/articles/5830365.html

  • 相关阅读:
    Caused by: java.io.IOException: 你的主机中的软件中止了一个已建立的连接。
    jauery加入项目中,但是在页面中显示没有找到这个文件--springMVC框架
    SpringMVC中Controller和RestController
    firefox与chrome中对select下拉框中的option支持问题
    Spring与jsp表达式的产生的问题
    javaScript基础练习题-下拉框制作(神奇的代码)
    javaScript基础练习题-下拉框制作(JQuery)
    云,git,blog,感想
    javaScript基础练习题-下拉框制作(CSS)
    javaScript基础练习题-下拉框制作
  • 原文地址:https://www.cnblogs.com/cqq-20151202/p/5171498.html
Copyright © 2020-2023  润新知