为了增加程序的友好性,一般在程序报错的时候不会将错误直接返回用户,而是封装好一个提示页面给用户
最简单的结构 try: # 代码块 逻辑 pass except Exception as e: # e是Exception的对象,对象中封装了错误信息 # 上述代码块出错,执行当前块的内容 pass 断言 assert 条件 # 不满足条件直接报错,想使用程序必须报错,强制用户服从,不服从就报错 a = 2 assert a == 1 # try语句格式 try: # 执行业务代码 # a = [1,2,3] # a[4] pass except IndexError as e: print('我们知道报错的错误类型: IndexError',e) print("捕捉报错的错误类型, 可以进行精准的错误处理") print("比如这里, 可能是超出了列表的索引, 就可以提示用户重新输入或者处理列表") except ValueError as e: print('我们知道报错的错误类型: ValueError',e) except Exception as e: print('并不知道报错的类型: Exception',e) else: # try 代码块没报错才会执行这里的业务逻辑 print('try中的代码没出错执行这里') finally: # 可有可无, 无论 try 代码块是否报错都会执行这里 print('最后一定会执行这里') try: # 有时候程序没出错, 但是我们捕获到了用户的一些异常操作 # 自定义报错信息 raise Exception('心情不好,主动触发异常') except Exception as e: print(e)
# 需求: 打开文件并输出内容
# 示例Python学习群:683380553,有大牛答疑,有资源共享!是一个非常不错的交流基地!欢迎喜欢Python的小伙伴!
try: with open('a.txt', "r", encoding="utf8") as f: print(f.read()) except FileNotFoundError as e: print("文件不存在, 将自动创建空白文件并输入: hello world") with open('a.txt', "w", encoding="utf8") as f: f.writelines("hello world")
常用异常
AttributeError 试图访问一个对象没有的属性, 比如foo.x,但是foo没有属性x IOError 输入/输出异常;常见为无法打开文件 ImportError 无法引入模块或包;常见为路径问 题或名称错误 IndentationError 语法错误(的子类) ;代码 没有正确对齐 IndexError 下标索引超出序列边界,比如当x只 有三个元素,却试图访问x[5] KeyError 试图访问字典里不存在的键 KeyboardInterrupt Ctrl+C被按下 NameError 使用一个还未被赋予对象的变量 SyntaxError Python代码非法,代码不能编译 (个人认为这是语法错误, 写错了) TypeError 传入对象类型与要求的不符合 UnboundLocalError 试图访问一个还未被设置 的局部变量,基本上是由于另有一个同名的全局 变量, 导致你以为你正在访问它 ValueError 传入一个调用者不期望的值,即使 值的类型是正确的
反射
什么是反射: 通过字符串映射object对象的方法或属性
- hasattr(obj, name_str): 判断objec是否有name_str这个方法或者属性
- getattr(obj, name_str): 获取object对象中与name_str同名的方法或者函数
- setattr(obj, name_str, value): 为object对象设置一个以name_str为名的value方法或者属性
- delattr(obj, name_str): 删除object对象中的name_str方法或者属性
方法的简介绍
class F006: static_foo = '公有静态字段' __static_foo = '私有静态字段' def __init__(self,name,age): self.name = name self.age = age def show(self): print(self.name) def __show(self): print(self.name) obj = F006('nathaniel',20) # 检查是否含有某成员 ret = hasattr(obj,'static_foo') print(ret) ret = hasattr(obj,'__static_foo') print(ret) ret = hasattr(obj,'__init__') print(ret) ret = hasattr(obj,'show') print(ret) ret = hasattr(obj,'__show') print(ret) # 从对象中获取成员 ret = getattr(obj,'static_foo') print(ret) # ret = getattr(obj,'__static_foo') # print(ret) ret = getattr(obj,'__init__') print(ret) ret = getattr(obj,'show') print(ret) # ret = getattr(obj,'__show') # print(ret) # 设置对象中的成员 setattr(obj,'show',lambda x:print(x)) obj.show('233') setattr(obj,'static_foo',999) print(obj.static_foo) setattr(obj,'new_num',888) print(obj.new_num) # 删除对象中的成员 delattr(obj,'name') print(obj.name) # >> 报错 AttributeError: 'F006' object has no attribute 'name'
python的反射,它的核心本质其实就是利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,是一种基于字符串的事件驱动!!!
举个栗子 >> 一个web页面,需要根据用户输入的URL不同,调用不同的函数,实现不同的操作,也就是一个简单的路由,这在web框架里是核心部件之一
你可能会这样写
# web框架实例之普通青年版 class Web0: def __init__(self,name): self.name = name def home_page(self): print('%s进入了首页'% self.name) def login_page(self): print('%s进入了登录页'% self.name) def logout_page(self): print('%s进入了退出页'% self.name) def news_page(self): print('%s进入了新闻页'% self.name) obj = Web0('Nathaniel') inp = '' while inp != 'q' and inp != 'Q': inp = input('请输入需要查看的url>>>') if inp == 'home_page': obj.home_page() elif inp == 'login_page': obj.login_page() elif inp == 'logout_page': obj.logout_page() elif inp == 'news_page': obj.news_page() else: if inp != 'q' and inp != 'Q': print('404')
有毛病嘛?没毛病.然而,我们考虑一个问题,如果有成百上千个URL呢(这很正常)?难道我们手动去写成百上千条if语句?显然不现实,呐,反射就来了>>我们对上述代码进行如下优化
# web框架实例之装逼青年版 class Web1: def __init__(self,name): self.name = name def home_page(self): print('%s进入了首页'% self.name) def login_page(self): print('%s进入了登录页'% self.name) def logout_page(self): print('%s进入了退出页'% self.name) def news_page(self): print('%s进入了新闻页'% self.name) obj = Web1('Nathaniel') inp = '' while inp != 'q' and inp != 'Q': inp = input('请输入需要查看的url>>>') if hasattr(obj,inp): getattr(obj,inp)() else: if inp != 'q' and inp != 'Q': print('404')
单例模式
单例模式,是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中应用该模式的类一个类只有一个实例,即一个类只有一个对象实例
举个栗子,某服务器程序的配置信息存放在一个文件当中,客户端通过一个AppConfig的类来读取配置文件的信息.如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,严重浪费内存资源,尤其是在配置文件内容很多的情况下.事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象
使用模块实现单例模式
python模块天然就是单例模式,当模块第一次被导入时会生成一个.pyc文件,第二次导入该模块就会直接执行.pyc文件而不会再次执行模块里的代码,因此我们可以把需要的函数和数据都定义在一个模块当中,这样就可以保证每次使用的都是同一个对象了
# 使用模块实现单例模式 class Foo7: def __init__(self): pass def foo0(self): pass obj = Foo7() # 将上面的代码保存在文件 xxx.py 中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象 from xxx.py import obj print(id( obj))
使用装饰器实现单例模式
# 使用装饰器实现单例模式 def make_singleton(cls): _instance = {} def _singleton(*args, **kwargs): if cls not in _instance: _instance[cls] = cls(*args, **kwargs) return _instance[cls] return _singleton @make_singleton class Foo8: pass obj0 = Foo8() obj1 = Foo8() obj2 = Foo8() obj3 = Foo8() print(obj0) print(obj1) print(obj2) print(obj3) 我们发现,无论用Foo8创建多少实例对象,他们所使用的都是同一个内存地址 使用类实现单例模式 # 使用类实现单例模式 class Singleton(object): def __init__(self): pass @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): cls._instance = Singleton(*args, **kwargs) return cls._instance obj0 = Singleton.instance() obj1 = Singleton.instance() obj2 = Singleton.instance() obj3 = Singleton.instance() print(obj0) print(obj1) print(obj2) print(obj3)
这种方式实现的单例模式,使用时会有限制,以后实例化必须通过 obj = Singleton.instance() , 如果用 obj=Singleton() ,这种方式得到的不是单例
使用__new__方法实现(推荐使用,方便)
我们知道,当我们实例化一个对象时,是先执行了类的__new__方法(我们没写时,默认调用object.__new__),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式
# 使用__new__方法实现(推荐使用,方便) class Singleton(object): def __init__(self): pass def __new__(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): if not hasattr(Singleton, "_instance"): Singleton._instance = object.__new__(cls) return Singleton._instance obj0 = Singleton() obj1 = Singleton() obj2 = Singleton() obj3 = Singleton() print(obj0) print(obj1) print(obj2) print(obj3)
简单粗暴的说,就是一个类无论你实例化多少次,它的对象始终都是一个内存地址