装饰器
在代码运行期间动态增加功能的方式,称为装饰器Decorator。常见的内置装饰器有:
- @property
- @setter
定一个装饰器升级now
装饰器 以一个函数作为参数,并返回一个函数
def log(f):
def write_log(*args, **kw): # 使用*是说可变参数,不限制参数的数量
with open('./module2/a.txt', 'w') as f1:
# 这样写的好处是不用再单独写f1.close,他会自动关闭,不会造成资源的浪费
f1.write(f.__name__)
print('写入日志成功,函数名字是:%s' % f.__name__)
return f(*args, **kw)
# 返回的是f这个方法,是把now传进来,然后封装成write_log,然后再把now返回出来,同时也对now进行了执行
return write_log
# 传出来的也是一个方法
# write_log 有两个功能,一个是打印日志的功能,一个是now打印日志的功能
# 由于返回的是函数名write_log,而不是write_log(),所以write_log中的now并没有执行两遍,
调用方法1
ff = log(now)
# 传进了now方法
ff()
# 其实代表的是write_log方法
print(ff.__name__)
调用方法2
这个方式比较反人类,所以用下面的@来进行装饰
import datetime
@log
def now():
print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
now()
python 内置装饰器
学习 @property 和 @setter
原始代码:
class Student():
def __init__(self, score):
self.__score = score
def get_score(self):
return self.__score
def set_score(self, value):
if not isinstance(value, int):
raise ValueError('Score must be an integer!')
if value < 0 or value> 100:
raise ValueError('Score must between 0~100!')
self.__score = value
stu1 = Student(90)
print(stu1.get_score())
stu1.set_score(85)
print(stu1.get_score())
加上装饰器,方法变成属性
class Student():
def __init__(self, score):
self.__score = score
@property
def score(self):
return self.__score
@score.setter
def score(self, value):
# 此时看着两个函数一样,但上面那个无参,下面这个有参
# 但尽量还是避免重复命名的参数
if not isinstance(value, int):
raise ValueError('Score must be an integer!')
if value < 0 or value> 100:
raise ValueError('Score must between 0~100!')
self.__score = value
stu2 = Student('98')
print(stu2.score)
print(type(stu2.score))
stu2 = Student(67)
print(stu2.score)
print(type(stu2.score))
# stu2.score = '59'
运行之后,得到的结果是:
98
<class 'str'>
67
<class 'int'>
这里要注意一下程序的流程:
stu2 = Student('98')
# 实例化一个对象stu2,同时调用__init__方法,将stu2的score属性变成了‘98’
print(stu2.score)
# 这里对stu2.score进行打印,Python内置的@property装饰器就是负责把一个方法变成属性调用的,所以会将绑定了self的score属性进行打印
print(type(stu2.score))
# 根据上面的结果,此时输出的值就是字符串类型
stu2 = Student(67)
# 和上面的字符串类型的一样,只不过这里传的参数是int类型的67
print(stu2.score)
print(type(stu2.score))
若果代码换成:
stu2.score = 88
print(stu2.score)
print(type(stu2.score))
stu2.score = '59'
会先输出:
88
<class 'int'>
然后报错,并且报错信息为我们自己定义的‘Score must be an integer!’’
这是因为这几句代码是先调用了被@score.setter装饰过的score方法,这样可以对stu2的score属性进行修改,而当传入的值为字符串类型的时候,就会提示我们自定义过的错误。
设计一个装饰器,作用于函数上,打印函数执行时间
import time
def metric(fn): # 设计装饰器
# 对程序进行封装
def wrapper():
# 在程序执行之前记录一次时间
start_time = time.time()
# 需要执行一次程序
fn()
# 在程序执行之后记录一次时间
end_time = time.time()
# 两次时间相见,得到的差就是程序执行时间
print('耗时:{:.8f}s'.format(end_time - start_time))
return wrapper
@metric
def multiplication_table():
# 利用生成九九乘法表进行测试
print('正常右上角写法的while思路')
row = 9
while row >= 1:
col = row
n = 0
while n < 9 - row:
print(' ' * 9, end='')
n += 1
while col >=1:
print('{}*{}={:<5d}'.format(row, col, row * col),end='')
col -= 1
print('')
row -= 1
multiplication_table()