Python学习笔记#10 面向对象的应用(异常处理、文件备份)
1.装饰器
(1) 用于拓展原来函数功能的一种函数
(2) 返回函数的函数
(3) 在不用更改原函数代码的前提下给函数增加新的功能
例:
def log(func):
"""记录函数执行的日志"""
def wrapper():
print('开始执行')
func()
print('执行完毕')
return wrapper
@log
def hello():
"""简单功能模拟"""
print("Hello PyCharm")
if __name__ == '__main__':
hello()
输出 -->
开始执行
Hello PyCharm
执行完毕
2.带参数的装饰器
(1)
def log(name = None):
def decorator(func):
def wrapper():
print('{0}开始执行'.format(name))
func()
print('{0}执行完毕'.format(name))
return wrapper
return decorator
@log('装饰器函数')
def hello():
"""简单功能模拟"""
print("Hello PyCharm")
if __name__ == '__main__':
hello()
输出 -->
装饰器函数开始执行
Hello PyCharm
装饰器函数执行完毕
(2) 带魔法参数的装饰器 :
PS: 当函数的参数不确定时,可以使用*args 和**kwargs。
*args:表示的就是将实参中按照位置传值,多出来的值都给args,且以元组的方式呈现
**kwargs:表示的就是形参中按照关键字传值把多余的传值以字典的方式呈现
def log(name=None):
def decorator(func):
def wrapper(*args, **kwargs):
print('{0}开始执行'.format(name))
print(args, kwargs)
func(*args, **kwargs)
print('{0}执行完毕'.format(name))
return wrapper
return decorator
@log('from add')
def add(a, b):
return a + b
if __name__ == '__main__':
add(5, 6)
输出 -->
from add开始执行
(5, 6) {}
from add执行完毕
(3) @wraps
当装饰器装饰一个函数时,实际上就是将被装饰的函数作为一个参数传入装饰器函数,返回一个闭包,而闭包内部调用这个函数,再另外多做一些事情。然后再由我们的函数名字去接收那个返回值的闭包的引用,达到了我们装饰的目的,所以此时,我们的函数的__name__等属性其实已经改变,变成了我们闭包的私有属性。
functools.wraps()这个函数,作为一个装饰器去装饰闭包,并且给这个装饰器传入一个参数,这个参数是闭包外的装饰器装饰的那个外部的被装饰函数,此时,外部我们的自定义的函数的私有属性如_name__、_doc__等还是为我们自定义的函数本身的私有属性,而不会变成闭包的私有属性。
@wraps 可以确保我们调用文档、查看帮助时, 查找到的是我们原函数的属性, 而非所用装饰器的属性
(4) 类的装饰器
def eat(cls):
"""吃东西装饰器"""
cls.eat = lambda self: print("{0}:我要吃东西".format(self.name))
return cls
@eat
class Cat(object):
"""猫类"""
def __init__(self, name):
self.name = name
if __name__ == '__main__':
cat = Cat('小黑')
cat.eat()
输出 -->
小黑:我要吃东西
3.迭代器与生成器
(1) 迭代器
1 实现了__iter__的对象是可迭代的, 而实现了方法__next__的对象是迭代器
2 调用方法__next__( 或next() )时, 迭代器返回下一个值
3 如果迭代器没有可供返回的值, 触发Stoplteration异常
(2) 生成器
1 生成器是一种使用普通函数语法定义的迭代器
2 包含yield语句的函数都被称为生成器
每次使用yield生成一个值后, 函数都将冻结, 即在此停止执行;
被重新唤醒后, 函数将从停止的地方开始继续执行。
3 不使用return返回一个值, 而是可以生成多个值, 每次一个
4.文件备份
import os
import os.path
class FileBackup(object):
"""
文本文件备份
"""
def __init__(self, src, dist):
"""
构造方法
:param src: 目录 需要备份的文件目录
:param dist: 目录 备份后的目录
"""
self.src = src
self.dist = dist
def read_files(self):
"""读取src目录下的所有文件"""
ls = os.listdir(self.src)
print("ls:{0}".format(ls))
for l in ls:
# 循环处理每一个文件/文件夹
self.backup_file(l)
def backup_file(self, file_name):
"""
处理备份
:param file_name: 文件/文件夹目录
"""
# 1 判断dist是否存在. 若不存在, 则创建该目录
if not os.path.exists(self.dist):
os.makedirs(self.dist)
print('指定的目录不存在, 创建完成')
# 2 判断文件是否为我们要备份的文件
# 拼接文件的完整路径
full_src_path = os.path.join(self.src, file_name)
full_dist_path = os.path.join(self.dist, file_name)
# 首先要判断是否为文件夹, 然后可以借助文件的后缀名进行判断
if os.path.isfile(full_src_path) and os.path.splitext(file_name)[-1].lower() == '.txt':
print("full_src_path:{0}".format(full_src_path))
# 3 读取文件内容
with open(full_dist_path, 'w', encoding='utf-8') as f_dist:
print(">>开始备份【{0}】".format(file_name))
with open(full_src_path, 'r', encoding='utf-8') as f_src:
while True:
rest = f_src.read(100)
if not rest:
break
# 4 把读取到的文件内容写入到新的文件中
f_dist.write(rest)
f_dist.flush()
print(">>>备份完成【{0}】".format(file_name))
else:
print("文件类型不符合备份要求, 跳过>>")
if __name__ == '__main__':
# 要备份的文件目录地址
# src_path = 'E:\\PyCharmWP\\src'
# 备份后的目录地址
# dist_path = 'E:\\PyCharmWP\\dict'
base_path = os.path.dirname(os.path.abspath(__file__))
print("base_path:{0}".format(base_path))
# 要备份的文件目录地址
src_path = os.path.join(base_path, 'src')
print("src_path:{0}".format(src_path))
# 备份后的目录地址
dist_path = os.path.join(base_path, 'dist')
print("dist_path:{0}".format(dist_path))
bak = FileBackup(src_path, dist_path)
bak.read_files()
5.异常处理
自定义异常:
class ApiException(Exception):
"""我的自定义异常"""
err_code = ''
err_msg = ''
def __init__(self, err_code=None, err_msg=None):
self.err_code = self.err_code if self.err_code else err_code
self.err_msg = self.err_msg if self.err_msg else err_msg
def __str__(self):
return 'Error: {0} - {1}'.format(self.err_code, self.err_msg)
class BadPramsException(ApiException):
"""参数不正确"""
err_code = '400002'
err_msg = '两个参数都必须是整数'
def divide(num1, num2):
# 两个数必须为整数
if not isinstance(num1, int) or not isinstance(num2, int):
raise BadPramsException()
# 除数不能为0
if num2 == 0:
raise ApiException('400000', '除数不能为0')
return num1 / num2
if __name__ == '__main__':
try:
rest = divide(5, 's')
print(rest)
except BadPramsException as e:
print("----------")
print(e)
except ApiException as err:
print("出错了")
print(err)
输出:Error: 400002 - 两个参数都必须是整数