阿里山QQ

导航

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、如下代码:

inpu = raw_input()
data = int(inpu)

如果输入的不是数字,那么就会报错
View Code

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

如下:

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'
请输入数字
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:\python\python.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:\python\python.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:\python\python.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:\python\python.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:\python\python.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:\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']
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:\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'}
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:\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


因为:#因为是类寻找的话,会在自己的成员中找,而对象寻找的话,会现在自己的内存中找,如果没有找到,会到创建对象的类中找(通过类对象指针)
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:\python\python.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:\python\python.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\r\n\r\n")
        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

posted on 2016-02-23 19:42  阿里山QQ  阅读(356)  评论(0编辑  收藏  举报