Catalog
Decorator
Use scenarios
to grant authorization (Authorization)
journal (Logging)
Parameter decorator
Embed decorators in functions
Decorator class
Now let's take a look at where the decorator is particularly dazzling , And using it can make some things easier to manage .
A decorator can help to check if someone is authorized to use a web The endpoint of the application (endpoint). They are
Used in Flask and Django web In the frame . Here is an example of using decorator Based Authorization :
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
Log is another highlight of decorator application . This is an example :
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
I'm sure you're already thinking about one of the other clever uses of decorators .
Think about this problem , Don't @wraps Isn't it also a decorator ? however , It takes a parameter , Just like any ordinary function can do . that , Why don't we do the same ?
This is because , When you use @my_decorator Grammatical time , You are applying a wrapped function with a single function as an argument . remember ,Python Everything in the is an object , And this includes functions ! Remember these , We can write a function that can return a wrapped function .
Let's go back to the example of logs , And create a wrap function , Allows us to specify a log file for output .
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)
# open logfile, And write content
with open(logfile, 'a') as opened_file:
# Now type the log to the specified logfile
opened_file.write(log_string + '\n')
return func(*args, **kwargs)
return wrapped_function
return logging_decorator
@logit()
def myfunc1():
pass
myfunc1()
# Output: myfunc1 was called
# Now one is called out.log Your file appears , The content is the string above
@logit(logfile='func2.log')
def myfunc2():
pass
myfunc2()
# Output: myfunc2 was called
# Now one is called func2.log Your file appears , The content is the string above
Now we have... That can be used in a formal environment logit Decorator , But when some parts of our application are still fragile , Exceptions may be something that needs more urgent attention . For example, sometimes you just want to log to a file . And sometimes you want to send a question that gets your attention to email, Also keep logs , Keep a record . This is a scenario using inheritance , But so far we've only seen the functions used to build the decorator .
Fortunately, , Class can also be used to build decorators . So now we're using a class instead of a function , To rebuild 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)
# open logfile And write
with open(self.logfile, 'a') as opened_file:
# Now print the log to the specified file
opened_file.write(log_string + '\n')
# Now? , Send a notification
self.notify()
return func(*args, **kwargs)
return wrapped_function
def notify(self):
# logit Just log , Nothing else
pass
This implementation has an additional advantage , It's cleaner than nesting functions , And wrapping a function still uses the same syntax as before :
@logit()
def myfunc1():
pass
Now? , We give logit Create subclass , To add email The function of ( although email This topic will not start here ).
class email_logit(logit):
One logit Implementation version of , Can be sent on function call email To the administrator
def __init__(self, email='[email protected]', *args, **kwargs)
self.email = email
super(logit, self).__init__(*args, **kwargs)
def notify(self):
# Send a email To self.email
# It's not going to happen here
pass
From now on ,@email_logit Will and @logit Same effect , But based on the log , An additional email will be sent to the administrator .