装饰器1

装饰器的本质:一个闭包函数

装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展

开放封闭原则

程序实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。

而装饰器就很好的适应这个原则

装饰器运用到的知识

函数中嵌套函数;函数返回一个函数;将函数作为参数传给另⼀个函数。

def sayhi():
    print('hi')
def saybefore(func):
    print('who is he?')
    return func
#saybefore就是一个装饰器

装饰器的实现

def decorator(F):
# Process function F
return F
@decorator
def func(): ... # func = decorator(func)

所以上面等同于

def saybefore(func):
    print('who is he?')
    return func
@saybefore
def sayhi():
    print('hi')
# 运行发现saybefore被调用了!并返回了一个函数。

现在想要每次“说的内容不一样”:sayhi中可以打印其他内容

def saybefore(func):
    print('who is he?')
    return func
@saybefore
def sayhi(arg):
    print(c)
sayhi('Hellow')
# -----------------------------
def saybefore(func):
	def inner(arg):
		print('who is he')
		return func(arg)
    return inner

装饰器的使用

日志

在系统中被调用(执行)的函数(程序),有很多种。
要求:打印被调用的函数名,并返回函数的结果,
试想一下不使用装饰器如何编写代码:每个函数除实现原有功能中都要添加返回自身函数名的代码
而有时又不希望打印函数名。。。

#使用装饰器,只要事先写好好需要扩展的功能,对需要扩展功能的函数修饰就可以了
from functools import wraps
def logit(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return with_logging
@logit       
def addition_func(x):
    '''Do some math'''
    return x + x
result = addition_func(4)

装饰器的wraps作用

​ 被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools模块中提供了一个叫wraps的decorator来消除这样的副作用。

#将上面代码中的@wraps(func)去掉,执行下面代码
print(addition_func.__doc__)    #None
print(addition_func.__name__)   #with_logging
#添加 @wraps(func)后,就变得“正常”了,wraps装饰装饰器内的函数,就会代指元信息和函数。

带参数的装饰器

@wraps(func)就是一个带参数的装饰器;上面使⽤@decorator语法时,是在应⽤⼀个以单个函数作为参数的⼀个包裹函数。我们可以编写⼀下能返回⼀个包裹函数的函数。

#将每个函数的运行,单独生成一份日志
from functools import wraps
def logit(logfile='out.log'):
	def logging_decorator(func):
		@wraps(func)
		def wrapped_function(*args, **kwargs):
			log_string = func.__name__ + " was called"
			print(log_string)
			# 打开logfile,并写⼊内容
			with open(logfile, 'a') as opened_file:
			# 现在将⽇志打到指定的logfile
				opened_file.write(log_string + '\n')
		return wrapped_function
	return logging_decorator
@logit()
def myfunc1():
pass
myfunc1()
# Output: myfunc1 was called
# 现在⼀个叫做 out.log 的⽂件出现了,⾥⾯的内容就是上⾯的字符串
@logit(logfile='func2.log')
def myfunc2():
pass
myfunc2():
pass
myfunc2()
myfunc2()
# Output: myfunc2 was called
# 现在⼀个叫做 func2.log 的⽂件出现了,⾥⾯的内容就是上⾯的字符串
posted @ 2019-09-19 12:13  Sroxi  阅读(143)  评论(0编辑  收藏  举报