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:\python\python.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、如下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
inpu = raw_input() data = int(inpu) 如果输入的不是数字,那么就会报错
那么实际应用中需要考虑到这些可能出现的异常:
如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
try: #正常逻辑代码 inpu = raw_input() data = int(inpu) except Exception,e: #逻辑代码块出现错误 print e print "请输入数字" #可以将错误信息写入日志,e ########结果如下############ D:\python\python.exe D:/python_scripts/11S_08day/index.py ddd invalid literal for int() with base 10: 'ddd' 请输入数字
但是上述代码没有将错误分门别类:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
try: li = [11,22,33] li[100] except IndexError,e: print 'error',e except TypeError,e: print e #以后再使用时,先写详细的错误,最后写一个except Exception,e:
三、异常处理之自定义异常
一般异常处理代码块包含如下代码块:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
try: #逻辑代码,链接数据库,执行sql pass except IndexError,e: pass except Exception,e: pass else: #逻辑块中未出现异常时执行 pass finally: #断开链接,释放资源 #永远执行,逻辑代码执行完成之后 pass
那么,异常处理中e是什么?
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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:\python\python.exe D:/python_scripts/11S_08day/index.py invalid literal for int() with base 10: 'abcde' <__main__.A instance at 0x000000000259A748> sb
事实上,e返回的是Exception中的__str__方法,这样的话我们就可以写自己的异常了。
那么如何自定义异常:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class CharlesError(Exception): #自定义类继承Exception类 def __str__(self): return 'Charles Error' try: raise CharlesError() #触发异常 except Exception,e: print e #########结果############# D:\python\python.exe D:/python_scripts/11S_08day/index.py Charles Error
上述自定义异常是写死了的,如何灵活返回?
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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:\python\python.exe D:/python_scripts/11S_08day/index.py 123
四、自定义异常之断言
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
assert 条件 #如果条件满足,不报错,条件不满足,就报错 1、在程序测试的时候使用; 2、满足条件,可以使用程序,不满足,就不可以使用; 3、一般不要使用;
总结异常处理:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
try: #主代码块 pass except KeyError,e: #异常时,执行该块 pass else: #主代码执行完,执行该块 pass finally: #无论异常与否,最终执行该块 pass 要求: 1、熟悉四个代码块的执行流程; 2、e是调用了Exception类中的__str__方法; 3、raise触发异常,在做大项目的时候,代码分层之后会用到;
五、反射和普通方式对比(模拟web框架)
先看一个例子,如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
存在两个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:\python\python.exe D:/python_scripts/11S_08day/index.py Charles... url:ddd 404
但是一个网站存在有大量的url文件,如果全部使用if...else访问处理的话,那么就是很不明智的;
那么如何处理呢???
事实上,web程序存在框架可以处理,常见的有mvc和mtv两张框架,如下图:
在python中,如何处理的呢?
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
controller,action = raw_input('url:').split('/') #如何去找url,使用简单反射代理处理 import home #action = 字符串 #去某个模块中招函数,字符串为函数名,如果有,则获取函数 func = getattr(home,action) ret = func() print ret #########结果为############# D:\python\python.exe D:/python_scripts/11S_08day/index.py url:home/dev result,home.dev
六、反射操作中的成员
反射的执行,有两种方式:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
a、 import home home.dev() s = "dev" ### home.dev ###这两种方式不同 b、 import home func = getattr(home,"dev") func()
getattr,setattr,delattr,hasattr的使用(操作内存中某个容器的元素)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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:\python\python.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']
七、反射操作类和对象中的成员
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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:\python\python.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'}
接下来使用getattr和setattr操作对象
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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:\python\python.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 因为:#因为是类寻找的话,会在自己的成员中找,而对象寻找的话,会现在自己的内存中找,如果没有找到,会到创建对象的类中找(通过类对象指针)
反射当前模块中的成员
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/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()
八、反射操作中的多层嵌套成员
模块home.py存在如下内容:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Foo: static_name = "NB" def __init__(self): self.name = "Charles" def show(self): pass
模块index.py调用home模块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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:\python\python.exe D:/python_scripts/11S_08day/index.py home.Foo NB Charles
总结:反射可以操作各种对象,如模块、类、实例化对象、函数、字段、方法等等。
九、动态模块导入
前面的**attr操作,可以根据用户输入不同的url,自动查找指定模块中url函数,那么如果存在大量的URL模块,我们在使用之前是不是都得import一下呢?
事实上,模块也可以通过字符串的方式由用户导入,具体方法如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
可以利用动态导入模块的方法完善web框架
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/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()
十、设计模式之单例模式
单例模式,顾名思义就是单个实例
单例模式--->内存中之存在一个实例,如果想要使用类中的功能,只使用这一个实例(内存中的)
看下面的例子:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
模块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'
效果如下:
下面使用单利模式,使得每次调用时只调用之前实例化的相同的实例
例子如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/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()) ###这样做在大数据量的时候,所有的数据库,连接都只连接在一个实例,有可能会出现问题,建议在数据量少的时候使用
效果如下:
如果不使用web框架,多个实例化结果如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/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)
结果如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
D:\python\python.exe D:/python_scripts/11S_08day/单例模式.py 39048904 39048904
12、socket原理和web框架的实现
使用浏览器模拟客户端,server端代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/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\r\n\r\n") connection.send("Hello,World!") connection.close() if __name__ == '__main__': main()
简单例子:
server端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/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服务
client端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/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服务
如何根据用户输入的信息的关键字,返回特定的应答,模拟10086如下:
server端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/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()
client端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/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()
13、socket详细方法
obj_server.setblocking(False):默认在遇到accept或recv的时候回阻塞,但是如果是obj_server.setblocking(False)那么就不阻塞,但是server端accept如果没有接受到数据的话就会报错,实际在使用的时候,应用于epoll模型中,结合select使用;
14、socket使用多线程实现
server端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/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循
client端:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/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()
socket传输大数据和解决socket粘包参考如下: