Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
384 views
in Technique[技术] by (71.8m points)

python - What is the purpose of decorators (why use them)?

I've been learning and experimenting with decorators. I understand what they do: they allow you to write modular code by allowing you to add functionality to existing functions without changing them.

I found a great thread which really helped me learn how to do it by explaining all the ins and outs here: How to make a chain of function decorators?

But what is missing from this thread (and from other resources I've looked at) is WHY do we need the decorator syntax? Why do I need nested functions to create a decorator? Why can't I just take an existing function, write another one with some extra functionality, and feed the first into the 2nd to make it do something else?

Is it just because this is the convention? What am I missing? I assume my inexperience is showing here.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I will try to keep it simple and explain it with examples. One of the things that I often do is measure the time taken by API's that I build and then publish them on AWS.

Since it is a very common use case I have created a decorator for it.

def log_latency():
def actual_decorator(f):
    @wraps(f)
    def wrapped_f(*args, **kwargs):
        t0 = time()
        r = f(*args, **kwargs)
        t1 = time()
        async_daemon_execute(public_metric, t1 - t0, log_key)
        return r
    return wrapped_f

return actual_decorator

Now if there is any method that I want to measure the latency, I just put annotate it with the required decorator.

@log_latency()
def batch_job_api(param):
    pass

Suppose you want to write a secure API which only works if you send a header with a particular value then you can use a decorator for it.

def secure(f):
@wraps(f)
def wrapper(*args, **kw):
    try:
        token = request.headers.get("My_Secret_Token")
        if not token or token != "My_Secret_Text":
            raise AccessDenied("Required headers missing")
    return f(*args, **kw)
return wrapper

Now just write

@secure
def my_secure_api():
    pass

I have also been using the above syntax for API specific exceptions, and if a method needs a database interaction instead of acquiring a connection I use @session decorator which tells that this method will use a database connection and you don't need to handle one yourself.

I could have obviously avoided it, by writing a function that checks for the header or prints time taken by API on AWS, but that just looks a bit ugly and nonintuitive.

There is no convention for this, at least I am not aware of them but it definitely makes the code more readable and easier to manage. Most of the IDE's also have different color syntax for annotation which makes it easier to understand and organize code.

So, I would it may just be because of inexperience; if you start using them you will automatically start knowing where to use them.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...