案例一:你我合作协同开发,你调用我写的方法。
- 我定义了一个函数
class EmailValidError(Exception): title = "邮箱格式错误" class ContentRequiredError(Exception): title = "文本不能为空错误" def send_email(email,content): if not re.match("\w+@live.com",email): raise EmailValidError() if len(content) == 0 : raise ContentRequiredError() # 发送邮件代码... # ...
你调用我写的函数
def execute(): # 其他代码 # ... try: send_email(...) except EmailValidError as e: pass except ContentRequiredError as e: pass except Exception as e: print("发送失败") execute() # 提示:如果想要写的简单一点,其实只写一个Exception捕获错误就可以了。
案例二:在框架内部已经定义好,遇到什么样的错误都会触发不同的异常。
import requests from requests import exceptions while True: url = input("请输入要下载网页地址:") try: res = requests.get(url=url) print(res) except exceptions.MissingSchema as e: print("URL架构不存在") except exceptions.InvalidSchema as e: print("URL架构错误") except exceptions.InvalidURL as e: print("URL地址格式错误") except exceptions.ConnectionError as e: print("网络连接错误") except Exception as e: print("代码出现错误", e) # 提示:如果想要写的简单一点,其实只写一个Exception捕获错误就可以了。
案例三:按照规定去触发指定的异常,每种异常都具备被特殊的含义。
3.4 特殊的finally
try: # 逻辑代码 except Exception as e: # try中的代码如果有异常,则此代码块中的代码会执行。 finally: # try中的代码无论是否报错,finally中的代码都会执行,一般用于释放资源。 print("end")
当在函数或方法中定义异常处理的代码时,要特别注意finally和return。
def func(): try: return 123 except Exception as e: pass finally: print(666) func()
在try或except中即使定义了return,也会执行最后的finally块中的代码。
练习题
- 补充代码实现捕获程序中的错误。
# 迭代器 class IterRange(object): def __init__(self, num): self.num = num self.counter = -1 def __iter__(self): return self def __next__(self): self.counter += 1 if self.counter == self.num: raise StopIteration() return self.counter obj = IterRange(20) while True: try: ele = next(obj) except StopIteration as e: print("数据获取完毕") break print(ele)
补充代码实现捕获程序中的错误。
class IterRange(object): def __init__(self, num): self.num = num self.counter = -1 def __iter__(self): return self def __next__(self): self.counter += 1 if self.counter == self.num: raise StopIteration() return self.counter class Xrange(object): def __init__(self, max_num): self.max_num = max_num def __iter__(self): return IterRange(self.max_num) data_object = Xrange(100) obj_iter = data_object.__iter__() while True: try: ele = next(obj_iter) except StopIteration as e: print("数据获取完毕") break print(ele)
补充代码实现捕获程序中的错误。
def func(): yield 1 yield 2 yield 3 gen = func() while True: try: ele = next(gen) except StopIteration as e: print("数据获取完毕") break print(ele)
补充代码实现捕获程序中的错误。(注意:本案例用于练习,在真是开发中对于这种情况建议还是自己做判断处理,不要用异常)
num = int("lbw") try: num = int("lbw") except ValueError as e: print("转换失败")
补充代码实现捕获程序中的错误。(注意:本案例用于练习,在真是开发中对于这种情况建议还是自己做判断处理,不要用异常)
data = [11,22,33,44,55] data[1000] try: data = [11,22,33,44,55] data[1000] except IndexError as e: print("转换失败")
补充代码实现捕获程序中的错误。(注意:本案例用于练习,在真是开发中对于这种情况建议还是自己做判断处理,不要用异常)
data = {"k1":123,"k2":456} data["xxxx"] try: data = {"k1":123,"k2":456} data["xxxx"] except KyeError as e: print("转换失败")
分析代码,写结果
class MyDict(dict): def __getitem__(self, item): try: return super().__getitem__(item) # KeyError except KeyError as e: return None info = MyDict() info['name'] = "lbw" info['wx'] = "lbw666" print(info['wx']) # info['wx'] -> __getitem__ print(info['email']) # info['email'] -> __getitem__
看代码写结果
def run(handler): try: num = handler() print(num) return "成功" except Exception as e: return "错误" finally: print("END") print("结束") res = run(lambda: 123) print(res) >>> 123 >>> END >>> 成功 def func(): print(666) return "成功" def run(handler): try: num = handler() print(num) return func() except Exception as e: return "错误" finally: print("END") print("结束") res = run(lambda: 123) print(res)
>>> 123 >>> 666 >>> END >>> 成功
4.反射
反射,提供了一种更加灵活的方式让你可以实现去 对象 中操作成员(以字符串的形式去 对象
中进行成员的操作)。
class Person(object): def __init__(self,name,wx): self.name = name self.wx = wx def show(self): message = "姓名{},微信:{}".format(self.name,self.wx) user_object = Person("lbw","lbw666") # 对象.成员 的格式去获取数据 user_object.name user_object.wx user_object.show() # 对象.成员 的格式无设置数据 user_object.name = "lbw"
user = Person("lbw","lbw666") # getattr 获取成员 getattr(user,"name") # user.name getattr(user,"wx") # user.wx method = getattr(user,"show") # user.show method() # 或 getattr(user,"show")() # setattr 设置成员 setattr(user, "name", "lbw") # user.name = "lbw"
Python中提供了4个内置函数来支持反射:
- getattr,去对象中获取成员
v1 = getattr(对象,"成员名称") v2 = getattr(对象,"成员名称", 不存在时的默认值)
setattr,去对象中设置成员
setattr(对象,"成员名称",值)
hasattr,对象中是否包含成员
v1 = hasattr(对象,"成员名称") # True/False
delattr,删除对象中的成员
delattr(对象,"成员名称")
以后如果再遇到 对象.成员 这种编写方式时,均可以基于反射来实现。
案例:
class Account(object): def login(self): pass def register(self): pass def index(self): pass def run(self): name = input("请输入要执行的方法名称:") # index register login xx run .. account_object = Account() method = getattr(account_object, name,None) # index = getattr(account_object,"index") if not method: print("输入错误") return method()
4.1 一些皆对象
在Python中有这么句话:一切皆对象
。 每个对象的内部都有自己维护的成员。
- 对象是对象
class Person(object): def __init__(self,name,wx): self.name = name self.wx = wx def show(self): message = "姓名{},微信:{}".format(self.name,self.wx) user_object = Person("lbw","lbw666") user_object.name
类是对象
class Person(object): title = "lbw" Person.title # Person类也是一个对象(平时不这么称呼)
模块是对象
import re re.match # re模块也是一个对象(平时不这么称呼)。
由于反射支持以字符串的形式去对象中操作成员【等价于 对象.成员 】,所以,基于反射也可以对类、模块中的成员进行操作。
简单粗暴:只要看到 xx.oo 都可以用反射实现。
class Person(object): title = "lbw" v1 = Person.title print(v1) v2 = getattr(Person,"title") print(v2) import re v1 = re.match("\w+","dfjksdufjksd") print(v1) func = getattr(re,"match") v2 = func("\w+","dfjksdufjksd") print(v2)
4.2 import_module + 反射
在Python中如果想要导入一个模块,可以通过import语法导入;企业也可以通过字符串的形式导入。
示例一:
# 导入模块 import random v1 = random.randint(1,100) # 导入模块 from importlib import import_module m = import_module("random") v1 = m.randint(1,100)
示例二:
# 导入模块exceptions from requests import exceptions as m # 导入模块exceptions from importlib import import_module m = import_module("requests.exceptions")
示例三:
# 导入模块exceptions,获取exceptions中的InvalidURL类。 from requests.exceptions import InvalidURL # 错误方式 from importlib import import_module m = import_module("requests.exceptions.InvalidURL") # 报错,import_module只能导入到模块级别。 # 导入模块 from importlib import import_module m = import_module("requests.exceptions") # 去模块中获取类 cls = m.InvalidURL
在很多项目的源码中都会有 import_module
和 getattr
配合实现根据字符串的形式导入模块并获取成员,例如:
from importlib import import_module path = "openpyxl.utils.exceptions.InvalidFileException" module_path,class_name = path.rsplit(".",maxsplit=1) # "openpyxl.utils.exceptions" "InvalidFileException" module_object = import_module(module_path) cls = getattr(module_object,class_name) print(cls)
我们在开发中也可以基于这个来进行开发,提高代码的可扩展性,例如:请在项目中实现一个发送 短信、微信 的功能。
参考示例代码中的:auto_message 项目。
总结
- 了解 mro和c3算法
- python2和python3在面向对象中的区别。
- 内置函数
staticmethod,classmethod,property,callable,type,isinstance,issubclass,super getattr,setattr,hasattr,delattr
- 异常处理
- 根据字符串的形式导入模块
import_module
- 根据字符串的形式操作成员
反射-getattr,setattr,hasattr,delattr