单独一章复习:Python 函数装饰器,廖雪峰讲装饰器html
子函数写在外面貌似也能够,可这样就少了“封装性”。python
def greet(): return "now you are in the greet() function" def welcome(): return "now you are in the welcome() function" def hi(name="yasoob"): if name == "yasoob": return greet else: return welcome
a = hi()
print(a) #outputs: <function greet at 0x7f2143c01500> print(a()) #outputs: now you are in the greet() function
def hi(): return "hi yasoob!" def doSomethingBeforeHi(func): print("I am doing some boring work before executing hi()") print(func()) doSomethingBeforeHi(hi) #outputs:I am doing some boring work before executing hi() # hi yasoob!
a_function_requiring_decoration经过a_new_decorator得到了加强版的本身。git
def a_new_decorator(a_func): def wrapTheFunction(): print("I am doing some boring work before executing a_func()") a_func() print("I am doing some boring work after executing a_func()") return wrapTheFunction def a_function_requiring_decoration(): print("I am the function which needs some decoration to remove my foul smell")
a_function_requiring_decoration() #outputs: "I am the function which needs some decoration to remove my foul smell" a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration) # <---- 函数(A)把本身"装饰"了一下,加强了功能 #now a_function_requiring_decoration is wrapped by wrapTheFunction() a_function_requiring_decoration() #outputs:I am doing some boring work before executing a_func() # I am the function which needs some decoration to remove my foul smell # I am doing some boring work after executing a_func()
写好a_new_decorator装饰器函数后,只要在须要“被装饰”的函数上添加@语法糖就行了。web
如此,就省掉了上述中的 函数(A)的步骤。闭包
一篇通俗易懂的博文:这是我见过最全面的Python装饰器详解!没有学不会这种说法!app
@a_new_decorator def a_function_requiring_decoration(): """Hey you! Decorate me!""" print("I am the function which needs some decoration to " "remove my foul smell")
However,只是表面上完美,抽象的还不够完全。 框架
上面的例子没有参数,若是有参数会如何?函数
并且只会写“一个装饰器”,因此“参数个数不定”也须要考虑进去。ui
# 万能装饰器,修饰各类参数
def celebrator(func): def inner(*args, **kwargs): print('我是新功能') func(*args, **kwargs) return inner
@celebrator def myprint(a): print(a) myprint('python小白联盟')
def celebrator(func): def inner(*args, **kwargs): print('我是新功能') ret = func(*args, **kwargs)
return ret return inner
装饰的函数,若是有返回值,则一致;若是没有返回值,则返回 None。spa
最外层的语法糖先执行。
使用带参的语法糖来进行简化;也就是再嵌套一层函数,同时也保证了“参数的独立性”
有点相似于“闭包”的如下这个例子,保持了子函数的参数的独立性。
def count():
------------------------- def f(j): # 由于通过了函数的封装,因此保持了函数内部变量的独立性 def g(): return j*j return g ------------------------- fs = [] for i in range(1, 4): fs.append(f(i)) # f(i)马上被执行,所以i的当前值被传入f() return fs f1, f2, f3 = count()
以下可见,返回的函数名字是装饰器中的wrap函数的名字,这是个封装缺陷。
print(a_function_requiring_decoration.__name__) # Output: wrapTheFunction
经过wraps告诉wrap函数:“你的扮演人物的身份是谁”。
注意:@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可让咱们在装饰器里面访问在装饰以前的函数的属性。
from functools import wraps def a_new_decorator(a_func): @wraps(a_func)
def wrapTheFunction(): print("I am doing some boring work before executing a_func()") a_func() print("I am doing some boring work after executing a_func()") return wrapTheFunction @a_new_decorator def a_function_requiring_decoration(): """Hey yo! Decorate me!""" print("I am the function which needs some decoration to " "remove my foul smell") print(a_function_requiring_decoration.__name__) # Output: a_function_requiring_decoration
装饰器能有助于检查某我的是否被受权去使用一个web应用的端点(endpoint)。它们被大量使用于Flask和Django web框架中。
这里是一个例子来使用基于装饰器的受权:
from functools import wraps def requires_auth(f): @wraps(f) def decorated(*args, **kwargs): auth = request.authorization if not auth or not check_auth(auth.username, auth.password): authenticate() return f(*args, **kwargs) return decorated
日志是装饰器运用的另外一个亮点。这是个例子:
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) # Output: addition_func was called
【在类的章节再详解】
咱们的应用的某些部分还比较脆弱时,异常也许是须要更紧急关注的事情。比方说有时你只想打日志到一个文件。而有时你想把引发你注意的问题发送到一个email,同时也保留日志,留个记录。这是一个使用继承的场景,但目前为止咱们只看到过用来构建装饰器的函数。
幸运的是,类也能够用来构建装饰器。那咱们如今以一个类而不是一个函数的方式,来从新构建logit。
from functools import wraps class logit(object): def __init__(self, logfile='out.log'): self.logfile = logfile def __call__(self, func): @wraps(func) def wrapped_function(*args, **kwargs): log_string = func.__name__ + " was called" print(log_string) # 打开logfile并写入 with open(self.logfile, 'a') as opened_file: # 如今将日志打到指定的文件 opened_file.write(log_string + '\n') # 如今,发送一个通知 self.notify() return func(*args, **kwargs) return wrapped_function def notify(self): # logit只打日志,不作别的 pass
如今,咱们给 logit 建立子类,来添加 email 的功能。
class email_logit(logit): ''' 一个logit的实现版本,能够在函数调用时发送email给管理员 ''' def __init__(self, email='admin@myproject.com', *args, **kwargs): self.email = email super(email_logit, self).__init__(*args, **kwargs) def notify(self): # 发送一封email到self.email # 这里就不作实现了 pass
End.