一、内置函数isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)检查obj是否是cls的对象当程序依赖用户输入,即对用户输入的内容进行分门别类的操作时就用isinstance
>>> n1=10>>> n2=9>>> print isinstance(n1,int)True>>> print isinstance(n1,str)False>>>
判断n1是否是int类创建,是返回True,否返回Falseisinstance第2个参数可以是第1个参数的类,也可以是第1个参数的基类
>>> class A:... pass... >>> class B(A):... pass... >>> b=B()>>> print isinstance(b,B)True>>> print isinstance(b,A)True>>>
注意:obj是对象,cls代表类判断obj对象是否是clas类的实例isinstance第2个参数可以是第1个参数的类,也可以是第1个参数的基类issubclass(sub,super)功能:判断某个类是否是另外一个类的派生类,或者说某个类是否是某个类的基类检查sub类是否是super
>>> class A:... pass... >>> class B(A):... pass... >>>>>> print issubclass(B,A)True>>> print issubclass(B,int)False>>>
判断B是否是A的派生类,换句话说判断A是否是B的基类
二、异常处理
我们访问网站或者直接运行代码时,有时候会报错,这里报错的实质就是程序没有对异常做特殊处理,所以出现错误页面或者显示异常错误代码,下面来学习如何处理异常:
示例代码:
input = ()data = (input)print data
运行代码:
D:\Python27\python.exe C:/Users/ryan/PycharmProjects/day08/index.py请输入数字:123123Process finished with exit code 0
输入 是数字,所以直接打印出输入 123但是如果输入的字母或者特殊符号呢?
发现报错了,在有用户输入的情况下我们是无法直接控制用户输入内容是否是按照我们要求输入,所以这里我们引入了异常处理语句:
try:
正式代码块:
except Exception,e:
"异常提示语句"
该语句的含义是:
如果try模块内代码执行出现异常(错误)则运行except Exception,e:代码块,输出"异常提示语句"
在语句"except Exception,e:"中,e是一个对象(或者说实例),Exception是一个类,e对象是类Exception创建的。如果上面正式代码块运行错误话,实例e封装了try模块下代码运行的所有错误,即包含了所有正式代码运行所产生的错误提示
#!/usr/bin/env python# -*- coding:utf-8 -*-__author__ = 'ryan'try: input = raw_input("请输入数字:") data = int(input) print dataexcept Exception,e: print e
运行代码:
D:\Python27\python.exe C:/Users/ryan/PycharmProjects/day08/index.py请输入数字:abcdefinvalid literal for int() with base 10: 'abcdef'Process finished with exit code 0
从内容可以发现错误提示为:输入的文字不是×××数字,为了避免输出不是整型数字而爆出上述提示页面,所有对提示信息做如下修改:
#!/usr/bin/env python# -*- coding:utf-8 -*-__author__ = 'ryan'try: input = raw_input("请输入数字:") data = int(input) print dataexcept Exception,e: print "你输入的不是数字" #这里可以定义日志record=e,然后将record写入到日志文件
再运行该代码:
D:\Python27\python.exe C:/Users/ryan/PycharmProjects/day08/index.py请输入数字:bd你输入的不是数字Process finished with exit code 0
通过上述代码演示,我们可以通过“except Exception,e:”中的Exception来捕获常见的所有错误信息,但是无法把错误信息进行进一步 区分,即:错误类型无法获取。为了进一步获取异常类型,看下面代码:
#!/usr/bin/env python# -*- coding:utf-8 -*-try: dic={'k1':'v1'} dic['kkk']except IndexError,e: print 'error:',eexcept KeyError,e: print eexcept Exception,e: print e
运行代码输出如下结果:
上述代码的执行过程是:程序从上到下执行,当执行完try模块下代码后,如果有异常,则会跟IndexError,e:进行匹配,如果是IndexEror错误,则执行 print 'error:',e否则,继续往下匹配KeyError,e:,如果匹配成功,则执行"print e:,如果所有错误类型都 匹配,那么就直接抛出异常代码。由于except Exception,e:可以获取所有错误,而except IndexError,e: 和except KeyError,e:都可以获取异常,那么在写程序的时候如果我们要求对某一种异常做特殊处理,则可以通过except XXX将详细的异常先捕获,然后再通过定义的语句进行处理,所以我们常常将except IndexError,e: 和except KeyError,e:写在前面,在最后写上except Exception,e:来捕获万能的异常,即:
#!/usr/bin/env python# -*- coding:utf-8 -*-__author__ = 'ryan'try: dic={'k1':'v1'} dic['kkk']except IndexError,e: print 'error:',eexcept KeyError,e: print eexcept Exception,e: print e
其他异常(错误)提示代码块结构:
try: #逻辑代码块 passexcept IndexError,e: passexcept KeyError,e: passexcept Exception,e: passelse: #逻辑代码块未出现异常就执行else块下语句 passfinally: #不管try模块下的逻辑代码块执行是否异常,只要执行完就会执行finally模块下的代码 pass进一步研究except Exception,e:中的e,
上面已经说了e是从Exception类实例化之后得到对象,类似于:
class A: obj=A()print obj
该代码输出结果为:“<__main__.A instance at 0x0088DE90>”,而代码:
try: int('adfageawehg')except Exception,e: print e
输出结果:
从这里发现"print e" 输出的是一段字符串,再看一段代码:
class A: def __str__(self): return 'python test'obj=A()print obj
运行代码输出结果:
输出结果是一个字符串,所以从上可以总结打出,print 后面如果跟的是一个对象时,都是调用该对象实例化时所用的类里的__str__方法。
三、自定义异常处理
异常处理提示我们可以自己定义,来看如下代码:
class AlexError(Exception): def __init__(self,msg=None): self.message=msg def __str__(self): if self.message: return self.message else: return 'alex error'try: raise AlexError('错误提示语句')except Exception,e: print e
输出结果:
上述定义了一个新类AlexError,然后继承了它的基类Exception,并且在AlexError类的构造方法中定义 了一个变量msg=None和一个方法__str__,然后在__str__方法中对输入的参数进行判断,如果message存在,则返回传入的参数值,否则就返回“alex error",而语句模块
try:
raise AexError('错误提示语句')
except Exception,e:
通过类名.('参数')调用类中定义 方法,所以输出调用时传入 参数值。
四、更多其他异常
ArithmeticErrorAssertionErrorAttributeErrorBaseExceptionBufferErrorBytesWarningDeprecationWarningEnvironmentErrorEOFErrorExceptionFloatingPointErrorFutureWarningGeneratorExitImportErrorImportWarningIndentationErrorIndexErrorIOErrorKeyboardInterruptKeyErrorLookupErrorMemoryErrorNameErrorNotImplementedErrorOSErrorOverflowErrorPendingDeprecationWarningReferenceErrorRuntimeErrorRuntimeWarningStandardErrorStopIterationSyntaxErrorSyntaxWarningSystemErrorSystemExitTabErrorTypeErrorUnboundLocalErrorUnicodeDecodeErrorUnicodeEncodeErrorUnicodeErrorUnicodeTranslateErrorUnicodeWarningUserWarningValueErrorWarningZeroDivisionError五、反射
python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,该四个函数分别用于对对象内部执行:
例如:home.py代码:
home.py内容如下:
#!/usr/bin/env python# -*- coding:utf-8 -*-__author__ = 'ryan'def index(): return 'result home.index'def dev(): return 'result home.dev'def user(): return 'result home.user'def passwd(): return 'result home.passwd'
hasattr:检查是否含有某成员
import home#print dir(home)#print hasattr(home,'dev')#通过函数hasattr到内存中找到home模块,判断home模块下是否存在dev函数,有返回True,否则返回false
getattr:获取成员
#print dir(home)#print getattr(home,'dev')#到内存中的home模块中去获取函数dev(其实时获取dev函数在内存中的地址)
setatt:设置成员
#print setattr(home,'alex','gentle man')#通过setattr对内存中的home模块添加一个字符串alex#print dir(home)
delattr删除成员
#delattr(home,'dev')#通过delattr删除内存中home模块中的dev函数#print dir(home)
所以反射就是通过以上的四个方法操作某个容器中的元素,或者说操作一段内存地址中的各个元素
示例代码(通过反射实现简单 web框架):webdemo.py代码
#!/usr/bin/env python#coding:utf-8from wsgiref.simple_server import make_serverdef RunServer(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) url = environ['PATH_INFO'] temp = url.split('/')[1] import home #去home模块中检查,是否含有指定的函数 is_exist = hasattr(home, temp) #如果存在指定的函数 if is_exist: #获取函数 func = getattr(home, temp) #执行函数并获取返回值 ret = func() #将函数返回值响应响应给请求者,即浏览器 return ret else: #如果不存在函数则返回给浏览器'404 not found' return '404 not found'if __name__ == '__main__': httpd = make_server('', 8001, RunServer) print "Serving HTTP on port 8001..." httpd.serve_forever()
六、反射操作类和对象中的成员(这里仅仅用hasattr()举例其他三个类似)
有如下代码:
class Foo: static_name='nba' def __init__(self): self.name='alex' def show(self): pass @staticmethod def static_show(self): pass @classmethod def class_show(cls): pass
查看类成员
print Foo.__dict__
输出结果:
D:\Python27\python.exe C:/Users/ryan/PycharmProjects/day08/index.py{'static_show':, '__module__': '__main__', 'show': , 'static_name': 'nba', 'class_show': , '__doc__': None, '__init__': }Process finished with exit code 0
对类成员操作
print hasattr(Foo,'__init__')print "##########分隔符①################"print hasattr(Foo,'static_name')print "##########分隔符②################"print hasattr(Foo,'show')print "##########分隔符③################"print hasattr(Foo,'static_show')print "##########分隔符④################"print hasattr(Foo,'class_show')
输出结果:
D:\Python27\python.exe C:/Users/ryan/PycharmProjects/day08/index.pyTrue##########分隔符①################True##########分隔符②################True##########分隔符③################True##########分隔符④################TrueProcess finished with exit code 0
查看对象成员
print obj.__dict__
输出结果:
D:\Python27\python.exe C:/Users/ryan/PycharmProjects/day08/index.py{'name': 'alex'}Process finished with exit code 0
从这里可以发现对象中成员只有name,即self.name='alex'是存储在对象obj中
对对象进行操作
print hasattr(obj,'__init__')print "##########分隔符①################"print hasattr(obj,'static_name')print "##########分隔符②################"print hasattr(obj,'show')print "##########分隔符③################"print hasattr(obj,'static_show')print "##########分隔符④################"print hasattr(obj,'class_show')print "##########分隔符⑤################"print hasattr(obj,'name')
输出结果:
True##########分隔符①################True##########分隔符②################True##########分隔符③################True##########分隔符④################True##########分隔符⑤################TrueProcess finished with exit code 0
对象obj中只有name='alex',但是通过hasattr检查发现,其他的方法也是存在,这是为什么?
解答:普通方法是存储在类里,对象中只存储普通字段,即self.name='alex',当hasattr检查name时返回True这个是意料之中,但是其他几个方法(普通方法、类方法、静态方法)也返回True,这里就要说道对象 特殊性,类去找成员时候只会在自己内存地址中去找,而对象找查找成员的时候先在自己的内存地址中查找,当自己内存地址中不存在要查找的成员的时候,对象会通过类对象指针到创建自己的类的地址中继续查找,所以这里就出现了在对象中查找几种方法返回True的结果
七、反射操作多层嵌套成员
假如home.py代码如下
class Foo: static_name='nba' def __init__(self): self.name='alex' def show(self): pass @staticmethod def static_show(self): pass @classmethod def class_show(cls): pass
index.py文件如下:
import homecls = getattr(home,"Foo")print cls
运行index.py,输出结果:
D:\Python27\python.exe C:/Users/ryan/PycharmProjects/day08/index.pyhome.FooProcess finished with exit code 0
发现输出的是home.Foo,即找到 home.py中 Foo类,如果我们进一步找Foo类中的成员,则可以这样操作:
import homecls = getattr(home,"Foo")print clss_name = getattr(cls,'static_name')print s_namec_show = getattr(cls,'show')print c_shows_show=getattr(cls,'static_show')print s_showcla_show = getattr(cls,'class_show')print cla_show
输出结果:
D:\Python27\python.exe C:/Users/ryan/PycharmProjects/day08/index.pyhome.Foonba>Process finished with exit code 0
如果用类Foo实例化一个对象obj,则在内存里再开辟块空间,此时对象与home没有所属关系,所以可以通过实例化对象来访问home.py中类Foo中 成员,代码如下:
import homecls = getattr(home,'Foo')print clsobj=cls()#实例化一个对象objname = getattr(obj,'name')print name
运行代码输出结果:
D:\Python27\python.exe C:/Users/ryan/PycharmProjects/day08/qiantao.pyhome.FooalexProcess finished with exit code 0多层嵌套 实质就是运用getattr等内置函数对获取 结果再一次运行getattr进行查找,从文件中获取类,然后从类中获取类成员;也可以将类实例化为对象,然后通过对象获取类中成员,逐层获取。
八、动态模块导入
一般情况下要导入某个模块直接用import 模块名(假如模块存在,这里用import home为例子),
如果controller = raw_input('url:')#比如输入的是home,
那么import controller就等价于import home;
即import controller == import "home",这里import "home"与import home显然不相等。
所以这里我们将import进行改造一下:
import ====>__import__()
所以就有了:
moude = __import__("home")
代码解释过程是:如果遇到import home,则将home.py中的内容加载到内存,生成一个内存地址段,加入名字叫home,但是如果遇到 module =__import__("home"),时,将home(home.py文件)导入到内存然后将home内容占据内存 地址段名字命名为module,类似于import home as module,另外一个功能是将原来未知的对象(Python中一切事物皆为对象)类型转换成了熟知的字符串(这里是"home"),
所以就有了如果要将用户动态输入的内容导入到内存那又该如何操作?
这里介绍__import__("内容")
示例代码:
home.py文件
#!/usr/bin/env python# -*- coding:utf-8 -*-__author__ = 'ryan'def index(): return 'result home.index'def dev(): return 'result home.dev'def user(): return 'result home.user'def passwd(): return 'result home.passwd'
index.py代码如下:
controller,action = raw_input('url:').split('/')module = __import__(controller)func = getattr(module,action)ret = func()#假设getattr获取的是函数print ret
运行index.py,输出结果:
D:\Python27\python.exe C:/Users/ryan/PycharmProjects/day08/qiantao.pyurl:home/indexresult home.indexProcess finished with exit code 0
home.py中有函数index,输出正确,至此解决了用户输入,将用户输入内容转换为字符串并导入内存,即模块的动态导入。同样输入home/dev,输出如下结果:
D:\Python27\python.exe C:/Users/ryan/PycharmProjects/day08/qiantao.pyurl:home/devresult home.devProcess finished with exit code 0
九、单例模式
单例,顾名思义单个实例。
学习单例之前,首先来回顾下面向对象的内容:
python的面向对象由两个非常重要的两个“东西”组成:类、实例
面向对象场景一:
如:创建三个游戏人物,分别是:
苍井井,女,18,初始战斗力1000
东尼木木,男,20,初始战斗力1800
波多多,女,19,初始战斗力2500
# ##################### 定义类 #####################class Person: def __init__(self, na, gen, age, fig): self.name = na self.gender = gen self.age = age self.fight =fig def grassland(self): """注释:草丛战斗,消耗200战斗力""" self.fight = self.fight - 200###################### 创建实例 #####################cang = Person('苍井井', '女', 18, 1000) # 创建苍井井角色dong = Person('东尼木木', '男', 20, 1800) # 创建东尼木木角色bo = Person('波多多', '女', 19, 2500) # 创建波多多角色
面向对象场景二:
如:创建对数据库操作的公共类
增
删
改
查
# #### 定义类 ####class DbHelper(object): def __init__(self): self.hostname = '1.1.1.1' self.port = 3306 self.password = 'pwd' self.username = 'root' def fetch(self): # 连接数据库 # 拼接sql语句 # 操作 pass def create(self): # 连接数据库 # 拼接sql语句 # 操作 pass def remove(self): # 连接数据库 # 拼接sql语句 # 操作 pass def modify(self): # 连接数据库 # 拼接sql语句 # 操作 pass # #### 操作类 ####db = DbHelper()db.create()
实例:结合场景二实现Web应用程序
#!/usr/bin/env python#coding:utf-8from wsgiref.simple_server import make_serverclass DbHelper(object): def __init__(self): self.hostname = '1.1.1.1' self.port = 3306 self.password = 'pwd' self.username = 'root' def fetch(self): # 连接数据库 # 拼接sql语句 # 操作 return 'fetch' def create(self): # 连接数据库 # 拼接sql语句 # 操作 return 'create' def remove(self): # 连接数据库 # 拼接sql语句 # 操作 return 'remove' def modify(self): # 连接数据库 # 拼接sql语句 # 操作 return 'modify'class Handler(object): def index(self): # 创建对象 db = DbHelper() db.fetch() return 'index' def news(self): return 'news' def RunServer(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) url = environ['PATH_INFO'] temp = url.split('/')[1] obj = Handler() is_exist = hasattr(obj, temp) if is_exist: func = getattr(obj, temp) 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()
对于上述实例,每个请求到来,都需要在内存里创建一个实例,再通过该实例执行指定的方法。
那么问题来了...如果并发量大的话,内存里就会存在非常多功能上一模一样的对象。存在这些对象肯定会消耗内存,对于这些功能相同的对象可以在内存中仅创建一个,需要时都去调用,也是极好的!!!
铛铛 铛铛 铛铛铛铛铛,单例模式出马,单例模式用来保证内存中仅存在一个实例!!!
通过面向对象的特性,构造出单例模式:
# ########### 单例类定义 ###########class Foo(object): __instance = None @staticmethod def singleton(): if Foo.__instance: return Foo.__instance else: Foo.__instance = Foo() return Foo.__instance # ########### 获取实例 ###########obj = Foo.singleton()
对于Python单例模式,创建对象时是不能再直接使用:obj = Foo(),但是可以调用特殊的方法:obj = Foo.singleton() 。
Web应用实例-单例模式
#!/usr/bin/env python#coding:utf-8from wsgiref.simple_server import make_server# ########### 单例类定义 ###########class DbHelper(object): __instance = None def __init__(self): self.hostname = '1.1.1.1' self.port = 3306 self.password = 'pwd' self.username = 'root' @staticmethod def singleton(): if DbHelper.__instance: return DbHelper.__instance else: DbHelper.__instance = DbHelper() return DbHelper.__instance def fetch(self): # 连接数据库 # 拼接sql语句 # 操作 pass def create(self): # 连接数据库 # 拼接sql语句 # 操作 pass def remove(self): # 连接数据库 # 拼接sql语句 # 操作 pass def modify(self): # 连接数据库 # 拼接sql语句 # 操作 pass class Handler(object): def index(self): obj = DbHelper.singleton() print id(single) obj.create() return 'index' def news(self): return 'news' def RunServer(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) url = environ['PATH_INFO'] temp = url.split('/')[1] obj = Handler() is_exist = hasattr(obj, temp) if is_exist: func = getattr(obj, temp) 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()
总结:单利模式存在的目的是保证当前内存中仅存在单个实例,避免内存浪费!!!