• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
喵了个喵0507
博客园             管理     
【python】第一模块 步骤三 第三课、面向对象的应用(异常处理、文件备份)

第三课、面向对象的应用(异常处理、文件备份)

一、课程介绍

  1.1 课程概要

  章节概要

  • 迭代器
  • 生成器
  • 实战:模拟range函数效果

 

二、装饰器的介绍与应用

  2.1 什么是装饰器

   装饰器

  • 用于拓展原来函数功能的一种函数
  • 返回函数的函数
  • 在不用更改原函数的代码前提下给函数增加新的功能

  如果没有装饰器

 1 def hello():
 2     """简单功能模拟"""
 3     print('hello world')
 4 
 5 
 6 def test():
 7     print('test..')
 8 
 9 
10 def hello_wrapper():
11     """新的函数,包裹原来的hello"""
12     print('开始执行hello')
13     hello()
14     print('结束执行')
15 
16 
17 def test_wrapper():
18     """新的函数,包裹原来的hello"""
19     print('开始执行hello')
20     test()
21     print('结束执行')
22 
23 
24 if __name__ == '__main__':
25     # hello()
26     hello_wrapper()

  实现装饰器

 1 def log(func):
 2     """记录函数执行的日志"""
 3     def wrapper():
 4         print('start...')
 5         func()
 6         print('end...')
 7     return wrapper
 8 
 9 
10 def log_in(func):
11     """记录函数执行的日志"""
12     def wrapper():
13         print('开始进入。。。')
14         func()
15         print('结束...')
16     return wrapper
17 
18 
19 @log
20 def hello():
21     # """简单功能模拟"""
22     print('hello world')
23 
24 
25 @log
26 @log_in
27 def test():
28     print('test..')
29 
30 
31 if __name__ == '__main__':
32     # hello()
33     test()

 

  2.2 带参数的装饰器

 1 def log(name=None):
 2     """记录函数执行的日志"""
 3 
 4     def decorator(func):
 5         def wrapper(*args, **kwargs):
 6             print('{0}.start...'.format(name))
 7             print(args)
 8             print(kwargs)
 9             rest = func(*args, **kwargs)
10             print('{0}.end...'.format(name))
11             return rest
12         return wrapper
13     return decorator
14 
15 
16 @log('hello')
17 def hello():
18     # """简单功能模拟"""
19     print('hello world')
20 
21 
22 @log('test')
23 def test():
24     print('test..')
25 
26 
27 @log('from add')
28 def add(a, b, *args, **kwargs):
29     return a+b
30 
31 
32 if __name__ == '__main__':
33     # hello()
34     # test()
35     rest = add(5, 6, k=5, v=6)
36     print(rest)

 

  2.3 带参数的装饰器之wraps

 1 from functools import wraps
 2 
 3 
 4 def log(name=None):
 5     """记录函数执行的日志"""
 6 
 7     def decorator(func):
 8         @wraps(funcs)
 9         def wrapper2(*args, **kwargs):
10             """装饰器内部的函数"""
11             print('{0}.start...'.format(name))
12             print('__warpper:{0}'.format(func.__name__))
13             print('__warpper:{0}'.format(func.__doc__))
14             rest = func(*args, **kwargs)
15             print('{0}.end...'.format(name))
16             return rest
17         # wrapper2.__doc__ = func.__doc__
18         # wrapper2.__name__ = func.__name__
19         return wrapper2
20     return decorator
21 
22 
23 @log('hello')
24 def hello():
25     """简单功能模拟"""
26     print('hello world')
27 
28 
29 if __name__ == '__main__':
30     print('doc:{0}'.format(hello.__doc__))
31     print('name:{0}'.format(hello.__name__))
32     hello()

 

 

 

  2.4 类的装饰器

 1 def f(self):
 2     print('{0}>我要吃东西'.format(self.name))
 3     print('0000000000')
 4 
 5 
 6 def eat(cls):
 7     """吃东西装饰器"""
 8     # cls.eat = lambda self: print('{0}>我要吃东西'.format(self.name))
 9     cls.eat = f
10     return cls
11 
12 
13 @eat
14 class Cat(object):
15     """猫类"""
16     def __init__(self, name):
17         self.name = name
18 
19 
20 if __name__ == '__main__':
21     cat = Cat('小黑')
22     cat.eat()

 

三、迭代器与生成器

  3.1 迭代器

  迭代器介绍

  • 迭代(iterate)意味着重复多次,就像循环那样(list,tuple)
  • 实现了方法__iter__的对象时可迭代的,而实现了方法__next__的对象是迭代器
  • 调用方法__next__时(或next()),迭代器返回其下一个值
  • 如果迭代器没有可供返回的值,触发Stoplteration异常

  从迭代器创建序列

  • 通过对可迭代对象调用内置函数iter,可获得一个迭代器
  • 举例

  迭代器效果演示

  • 生成12345的平方
  •  1 class PowNumber(object):
     2     """
     3     迭代器
     4     生成1,2,3,4,5,...数的平方
     5     """
     6     value = 0
     7 
     8     def __next__(self):
     9         self.value += 1
    10         if self.value > 10:
    11             raise StopIteration
    12         return self.value * self.value
    13 
    14     def __iter__(self):
    15         return self
    16 
    17 
    18 if __name__ == '__main__':
    19     pow = PowNumber()
    20     # print(pow.__next__())
    21     # print(pow.__next__())
    22     # print(pow.__next__())
    23     # print(pow.__next__())
    24     # print(pow.__next__())
    25     print(next(pow))
    26     print(next(pow))
    27     print(next(pow))
    28     print(next(pow))
    29     # 循环迭代器
    30     for i in pow:
    31         print(i)

     

  3.2 生成器

  生成器介绍

  • 生成器是一种普通函数语法定义的迭代器
  • 包含yield语句的函数都被称为生成器
  • 不使用return返回一个值,而是可以生成多个值,每次一个
  • 每次使用yield生成一个值后,函数都将冻结,即在此停止执行
  • 被重新唤醒后,函数将从停止的地方继续执行
  •  1 def pow():
     2     yield 1
     3     yield 2
     4     yield 3
     5     yield 4
     6 
     7 
     8 def pow_number():
     9     return (x * x for x in [1, 2, 3, 4, 5])
    10 
    11 
    12 def pow_number2():
    13     for x in [1, 2, 3, 4, 5]:
    14         yield x * x
    15 
    16 
    17 if __name__ == '__main__':
    18     # rest = pow()
    19     # print(next(rest))
    20     # print(next(rest))
    21     # print(next(rest))
    22     # print(next(rest))
    23     # print(next(rest))
    24     # for i in rest:
    25     #     print(i)
    26 
    27     rest = pow_number2()
    28     print(next(rest))
    29     print(next(rest))
    30     print(next(rest))
    31     print(next(rest)

 

  3.3 模拟range函数

 1 def use_range():
 2     """python内置的range函数"""
 3     for i in range(5, 10):
 4         print(i)
 5 
 6 
 7 class IterRange(object):
 8     """使用迭代器来模拟range函数"""
 9     def __init__(self, start, end):
10         self.start = start
11         self.end = end
12 
13     def __next__(self):
14         self.start += 1
15         if self.start >= self.end:
16             raise StopIteration
17         return self.start
18 
19     def __iter__(self):
20         return self
21 
22 
23 class GenRange(object):
24     def __init__(self, start, end):
25         self.start = start
26         self.end = end
27 
28     def get_num(self):
29         while True:
30             if self.start >= self.end - 1:
31                 break
32             self.start += 1
33             yield self.start
34 
35 
36 def get_num1(start, end):
37     start -= 1
38     while True:
39         if start >= end - 1:
40             break
41         start += 1
42         yield start
43 
44 
45 if __name__ == '__main__':
46     use_range()
47     print('----------')
48     iter = IterRange(5, 10)
49     # print(next(iter))
50     # print(next(iter))
51     # print(next(iter))
52     # print(next(iter))
53     # print(next(iter))
54     l = list(iter)
55     print(l)
56 
57     print('__________')
58     gen = GenRange(5, 10).get_num()
59     print(gen)
60     # print(next(gen))
61     # print(next(gen))
62     # print(next(gen))
63     # print(next(gen))
64     # print(next(gen))
65     print(list(gen))
66 
67     print('----------')
68     gen_f = get_num1(5, 10)
69     print(gen_f)
70     print(list(gen_f))

 

 

四、实战:文件备份

  1 import os
  2 import os.path
  3 
  4 
  5 class FileBackup(object):
  6     """
  7     文本文件备份
  8     """
  9 
 10     def __init__(self, src, dist):
 11         """
 12         构造方法
 13         :param src:目录 需要备份前的文件目录
 14         :param dist:目录 备份后的目录
 15         """
 16         self.src = src
 17         self.dist = dist
 18 
 19     def read_files(self):
 20         """
 21         读取src目录下的所有文件
 22         """
 23         ls = os.listdir(self.src)
 24         print(ls)
 25         for l in ls:
 26             # 循环处理每一个文件/文件夹
 27             self.backup_file(l)
 28 
 29     def backup_file(self, file_name):
 30         """
 31         处理备份
 32         :param file_name:
 33         :return:
 34         """
 35         # 1. 判断dist是否存在,如果不存在,要创建这个目录
 36         if not os.path.exists(self.dist):
 37             os.makedirs(self.dist)
 38             print('指定的目录不存在,创建完成')
 39 
 40         # 2. 判断文件是否为我们要备份的文件
 41 
 42         # 拼接文件的完整路径
 43         full_src_path = os.path.join(self.src, file_name)
 44         full_dist_path = os.path.join(self.dist, file_name)
 45 
 46         # 首先要判断是否为文件夹,然后借助于文件的后缀名进行判断
 47         if os.path.isfile(full_src_path) and os.path.splitext(full_src_path)[-1].lower() == '.txt':
 48             print(full_src_path)
 49             # 3. 读取文件内容
 50             with open(full_dist_path, 'w', encoding='utf-8')as f_dist:
 51                 print('>>开始备份【{0}】'.format(file_name))
 52 
 53                 with open(full_src_path, 'r', encoding='utf-8') as f_src:
 54                     while True:
 55                         rest = f_src.read(100)
 56                         if not rest:
 57                             break
 58                         # 4. 把读取到的内容写到新的文件中
 59                         f_dist.write(rest)
 60                     f_dist.flush()
 61                 print('>>>【{0}】备份完成'.format(file_name))
 62         else:
 63             print('文件类型不符合备份要求,跳过>>')
 64 
 65     def backup_file2(self, file_name):
 66         """
 67         处理备份
 68         :param file_name:
 69         :return:
 70         """
 71         # 1. 判断dist是否存在,如果不存在,要创建这个目录
 72         if not os.path.exists(self.dist):
 73             os.makedirs(self.dist)
 74             print('指定的目录不存在,创建完成')
 75 
 76         # 2. 判断文件是否为我们要备份的文件
 77 
 78         # 拼接文件的完整路径
 79         full_src_path = os.path.join(self.src, file_name)
 80         full_dist_path = os.path.join(self.dist, file_name)
 81 
 82         # 首先要判断是否为文件夹,然后借助于文件的后缀名进行判断
 83         if os.path.isfile(full_src_path) and os.path.splitext(full_src_path)[-1].lower() == '.txt':
 84             # 3. 读取文件内容
 85             with open(full_dist_path, 'w', encoding='utf-8')as f_dist, \
 86                     open(full_src_path, 'r', encoding='utf-8') as f_src:
 87                 print('>>开始备份【{0}】'.format(file_name))
 88                 while True:
 89                     rest = f_src.read(100)
 90                     if not rest:
 91                         break
 92                     # 4. 把读取到的内容写到新的文件中
 93                     f_dist.write(rest)
 94                 f_dist.flush()
 95                 print('>>>【{0}】备份完成'.format(file_name))
 96         else:
 97             print('文件类型不符合备份要求,跳过>>')
 98 
 99     def backup_file(self, file_name):
100         """
101         处理备份--代码优化
102         :param file_name:
103         :return:
104         """
105         # 1. 判断dist是否存在,如果不存在,要创建这个目录
106         if not os.path.exists(self.dist):
107             os.makedirs(self.dist)
108             print('指定的目录不存在,创建完成')
109 
110         # 2. 判断文件是否为我们要备份的文件
111 
112         # 拼接文件的完整路径
113         full_src_path = os.path.join(self.src, file_name)
114         full_dist_path = os.path.join(self.dist, file_name)
115 
116         # 首先要判断是否为文件夹,然后借助于文件的后缀名进行判断
117         if os.path.isfile(full_src_path) and os.path.splitext(full_src_path)[-1].lower() == '.txt':
118             print(full_src_path)
119             # 3. 读取文件内容
120             with open(full_dist_path, 'w', encoding='utf-8')as f_dist:
121                 print('>>开始备份【{0}】'.format(file_name))
122 
123                 with open(full_src_path, 'r', encoding='utf-8') as f_src:
124                     while True:
125                         rest = f_src.read(100)
126                         if not rest:
127                             break
128                         # 4. 把读取到的内容写到新的文件中
129                         f_dist.write(rest)
130                     f_dist.flush()
131                 print('>>>【{0}】备份完成'.format(file_name))
132         else:
133             print('文件类型不符合备份要求,跳过>>')
134 
135 
136 if __name__ == '__main__':
137     # # 要备份的文件目录地址
138     # src_path = 'C:\\Users\\19342\\Desktop\\me\\py_learn\\chapter05\\src'
139     # # 备份后的目录地址
140     # dist_path = 'C:\\Users\\19342\\Desktop\\me\\py_learn\\chapter05\\dist'
141 
142     # 当前代码的目录名称
143     # C:\\Users\\19342\\Desktop\\me\\py_learn\\chapter05\\        test_backup.py
144     base_path = os.path.dirname(os.path.abspath(__file__))
145     # 要备份的文件目录地址
146     src_path = os.path.join(base_path, 'src')
147     print(src_path)
148     # 备份后的目录地址
149     dist_path = os.path.join(base_path, 'dist')
150     print(dist_path)
151     bak = FileBackup(src_path, dist_path)
152     bak.read_files()

 

五、异常处理

  章节概要

  • 异常概述
  • 如何捕获异常
  • 自定义异常
  • 抛出异常及异常的传递

  5.1 什么是异常处理

  异常概述

  • 每个异常都是某个类的实例
  • 发生了异常如果不捕获,则程序将终止执行
  • 有一些内置的异常类

  内置异常类

类名 描述
Exception  几乎所有的异常类都是从它派生而来的
AttributeError  引用属性或给它赋值失败时引发
OSError  操作系统不能执行指定的任务(如打开文件)时引发,有多个子类
IndexError  使用序列中不存在的索引时引发,为LookupError的子类
KeyError  使用映射中不存在的键时引发,为LookupError的子类
NameError  找不到名称(变量)时引发
SyntaxError  代码不正确时引发
TypeError  将内置操作或函数用于类型不正确的对象时引发
 ValueError  将内置操作或函数用于这样的对象时引发:其类型正确但包含的值不合适
 ZeroDivisionError  在除法或求模运算的第二个参数为零时引发

 

  5.2 异常的捕获

  如何捕获异常

  • 使用try...except捕获所有异常
  • 使用try...except捕获多个指定异常
  • 使用try...except...finally处理必不可少的逻辑
 1 def test_div(num1, num2):
 2     """当除数为0时"""
 3     return num1 / num2
 4 
 5 def test_file():
 6     """读取文件"""
 7     try:
 8         f = open('test.txt', 'r', encoding='utf-8')
 9         rest = f.read()
10         print(rest)
11     except:
12         print('error')
13     finally:
14         f.close()
15         print('closed')
16 
17 
18 
19 if __name__ == '__main__':
20     # # 使用try...except捕获所有异常
21     # try:
22     #     rest = test_div(5, 's')
23     #     print(rest)
24     # except ZeroDivisionError:
25     #     print('报错了,除数不能为0')
26     # except TypeError:
27     #     print('报错了,请输入数字')
28     #
29     # # 使用try...except捕获多个指定异常
30     # try:
31     #     rest = test_div(5, 's')
32     #     print(rest)
33     # except (TypeError, ZeroDivisionError) as err:
34     #     print('反正就是报错了')
35     #     print(err)
36     # rest = test_div(5, 's')
37     # print(rest)
38     # 使用try...except...finally处理必不可少的逻辑
39     test_file()

 

  5.3 自定义异常

  自定义异常

  • 通过继承自Exception类来自定义异常
 1 # class MyException(Exception):
 2 #     """ 我的自定义异常 """
 3 #     pass
 4 
 5 
 6 class ApiException(Exception):
 7     """ 我的自定义异常 """
 8     err_code = ''
 9     err_msg = ''
10 
11     def __init__(self, err_code=None, err_msg=None):
12         self.err_code = self.err_code if self.err_code else err_code
13         self.err_msg = self.err_msg if self.err_msg else err_msg
14 
15     def __str__(self):
16         return 'Error:{0} - {1}'.format(self.err_code, self.err_msg)
17 
18 
19 class InvalidCtrlExec(ApiException):
20     """ 当参数不合法时触发 """
21     err_code = '40001'
22     err_msg = '不合法的调用凭证'
23 
24 
25 class BadPramsException(ApiException):
26     """ 参数不正确 """
27     err_code = '40002'
28     err_msg = '两个参数必须都是整数'
29 
30 
31 def divide(num1, num2):
32     """ 除法的实现 """
33     # 两个数必须为整数
34     if not isinstance(num1, int) or not isinstance(num2, int):
35         raise BadPramsException()
36     # 除数不能为0
37     if num2 == 0:
38         raise ApiException('400001', '除数不能为0')
39     return num1 / num2
40 
41 
42 if __name__ == '__main__':
43     try:
44         rest = divide(5, 's')
45         print(rest)
46     except BadPramsException as e:
47         print('------------------')
48         print(e)
49     except ApiException as err:
50         print('出错了')
51         print(err)

 

  5.4 异常的传递

  抛出异常及异常的传递

  • 如果在异常产生的地方不捕获,那么它会一层一层的往上传递
 1 class MyException(Exception):
 2     """ 自定义异常类 """
 3     pass
 4 
 5 
 6 def v_for():
 7     """ 自定义函数 """
 8     for i in range(1, 100):
 9         if i == 20:
10             raise MyException
11         print(i)
12 
13 
14 def call_v_for():
15     """ 调用vfor函数 """
16     print('开始调用v_for')
17     try:
18         v_for()
19     except MyException:
20         print('________')
21     print('结束调用vfor')
22 
23 
24 def test_rasie():
25     print('测试函数')
26     # try:
27     call_v_for()
28     # except MyException:
29     #     print('________')
30     print('测试完毕')
31 
32 
33 if __name__ == '__main__':
34     test_rasie()

 

posted on 2019-12-12 10:27  喵了个喵0507  阅读(203)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3