Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to write a decorator in Python

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly explains "how to write a decorator with Python". Interested friends may wish to have a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn "how to write a decorator with Python".

First of all, the concept is that decorators are an application of closures that need to meet the following rules:

1. Add new functions to the original function without changing the internal code of the original function and changing the calling method

two。 Follow the principle of opening and closing, what is the principle of opening and closing?

a. Implemented functions can be added or extended (open principle)

b. Do not modify the internal code of the implemented function (closure principle)

Secondly, login verification, statistics of the running time of the function, preparation work done before the execution of the function, cleaning function after the execution of the function, in short, most of the extended functions you can think of can be realized. and it can be done elegantly without modification to the original function code!

Let's take a look at the practice of the decorator and the problems experienced by ourselves! Because we often need to obtain interface data in our work, we simply encapsulate a method to obtain data. The code is as follows:

Import requestsimport redef send_request_by (method, url, data): "" request API to obtain data: param method: how to initiate a request: param url: request address: param data: request data: return: "" if re.match ("POST", method, flags=re.IGNORECASE): response = requests.post (url, data=data) if re.match ("GET", method, flags=re.IGNORECASE): response = requests.get (url, data=data) return response

At present, it seems that my needs have been met, but I still report an error every time I ask for it. Finally, through the analysis of the packet grabbing tool, it is found that there is an extra "sign" field when the client makes the interface call. How did this field come from? After analyzing that "sign" is obtained after encryption, the code has been modified to solve this problem. The code is as follows:

Def send_request_by (method, url, data): md5_pwd = MD5Password () data ['sign'] = md5_pwd (data) if re.match ("POST", method, flags=re.IGNORECASE): response = requests.post (url, data=data) if re.match ("GET", method, flags=re.IGNORECASE): response = requests.get (url, data=data) return response

This seems to solve the problem, but in fact there is no flexible solution to the problem. I would like to ask, if one day there is no need for encryption and signature, do you have to kill the two new lines of code? How can you add encryption without modifying the original function? After consulting with the boss, it is found that it can be realized through the decorator, and the code has been modified again, as follows:

Def sign_md5 (func): def wrapper (* args, * * kwargs): if not kwargs.get ('data'): raise KeyError ("not found Key' data'") if kwargs.get ('data') is None: raise ValueError (f' {kwargs.get ("data")} of value is None') # acronym sort_data = json.loads (json.dumps (kwargs.get ('data'), sort_keys=True)) # Private encryption rules Generate signature md5_pwd = MD5Password () sign = md5_pwd (sort_data) sort_data ['sig'] = sign kwargs [' data'] = sort_data ret = func (* args, * * kwargs) return ret return wrapper @ sign_md5 # send_request_by = sign_md5 (send_request_by) def send_request_by (method, url, data): # md5_pwd = MD5Password () # data ['sign'] = md5_pwd (data) if re.match ("POST", method) Flags=re.IGNORECASE): response = requests.post (url, data=data) if re.match ("GET", method, flags=re.IGNORECASE): response = requests.get (url, data=data) return response

After testing, I found that it is very flexible to solve the problem and comment out @ sign_md5 when there is no need for encryption. So what exactly did this @ sign_md5 do?

In essence, it is sign_md5 (send_request_by) (method, ulr, data) without using "@" magic. When decorated with "@" magic, the parser passes the decorated send_request_by as an argument to sign_md5 when the code is executed on this line, that is, the function send_request_by has been passed to the func parameter in sign_md (func) as a variable, and the function wrapper is returned. When the function send_request_by (method, url, data) is called next, send_request_by is no longer the send_request_by in the original def send_request_by (method, url, data), but points to the function wrapper (* args, * * kwargs). Wrapper this function accepts arbitrary parameters, so when you execute the send_request_by (method, url, data) function, you actually pass the method, url, data parameters to the warpper function and execute the internal code of wrapper, and the func inside the wrapper function is our incoming send_request_by function, which can be understood to mean that we pass the parameters to the wrapper function and encrypt the request parameters in the wrapper function. It is passed to the send_request_by function to make the request, thus completing the encryption process before the request. The func (* args, * * kwargs) in the wrapper function points to send_request_by (method, url, data), and ret is the return result of the send_request_by (method, url, data) function, so ret is returned. This piece is more tongue-twisting. I'm sure you'll understand it with your intelligence. Then you must think, Wow! It's so simple! And so far, the simplest no-parameter decorator is complete! The leader will praise you, Xiuer!

So, after solving this requirement, I have a new doubt. If one day the developer is not sorted by the first letter of the field, what should I do? Is it time to rewrite the decorator? Is there any way to control the ordering in the decorator? Then, after a variety of brain supplements, the code has been modified again, and the code is as follows:

Def sign_sort (sort=True): def sign_md5 (func): def wrapper (* args, * * kwargs): if not kwargs.get ('data'): raise KeyError ("not found Key' data'") if kwargs.get ('data') is None: raise ValueError (f' {kwargs.get ("data")} of value is None') # sort parameter controls whether sort_data = json.dumps (kwargs.get ('data') is sorted by acronym Sort_keys=True) if sort else json.dumps (kwargs.get ('data')) sort_data = json.loads (sort_data) # Private encryption rules Generate signature md5_pwd = MD5Password () sign = md5_pwd (sort_data) sort_data ['sig'] = sign kwargs [' data'] = sort_data ret = func (* args, * * kwargs) return ret return wrapper return sign_md5@sign_sort (sort=True) # send_request_by = sign_sort (sort=Ture) (send_request_by) def send_request_by (method, url, data): print (data) if re.match ("POST", method, flags=re.IGNORECASE): response = requests.post (url) Data=data) elif re.match ("GET", method, flags=re.IGNORECASE): response = requests.get (url, data=data) return respons

So what optimizations have been made this time? In fact, on the basis of learning the no-parameter decorator, I learned the decorator with parameters. It's still the same. Let's analyze it together.

First of all, let's look at sign_sort (sort=True). Sign_sort is essentially a function that takes an argument and returns a sign_md5 function.

When the code executes to the line "@", the decorated send_request_by function is also passed as an argument to the result of the call to the sign_sort (sort=True) function (that is, sign_md5).

In other words, the send_request_by function is passed to the func parameter in the sign_md5 function as a variable (the function can also be a variable), and a wrapper function is returned.

When the send_request_by (method, url, data) function is called later, send_request_by is no longer the send_request_by in the def send_request_by (method, url, data) function, but the wrapper (* args, * * kwargs) function.

The wrapper function accepts arbitrary parameters, so when send_request_by (method, url, data) is executed, method, url, data will be passed to the wrapper function to execute the code in the wrapper function, while the func (* args, * * kwargs) inside the wrapper still points to send_request_by, which can be understood as passing the parameter to the send_request_by function through the wrapper function, and we can do any operation on the parameter before passing it to send_request_by. Therefore, before passing it, I determine whether the sort parameter is True as the sorting switch, then encrypt the request data data, and finally pass it to the send_request_by function with the encrypted signature to send the request.

At this point, I believe you have a deeper understanding of "how to write a decorator with Python". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report