The example explains the things that should be paid attention to when using the function closure of Python, and the example explains python

Source: Internet
Author: User

The example explains the things that should be paid attention to when using the function closure of Python, and the example explains python

Yesterday, just as I used a finger to press the keyboard and coding in the dark, I was asked a question, and I almost lost my skills, if you don't talk much about it, go to the chestnut (Lite version to explain the problem only ):

from functools import wrapsfrom time import sleepdef retry(attempts=3, wait=2):  if attempts < 0 or attempts > 5:    retry_times = 3  else:    retry_times = attempts  if wait < 0 or wait > 5:    retry_wait = 2  else:    retry_wait = after  def retry_decorator(func):    @wraps(func)    def wrapped_function(*args, **kwargs):      while retry_times > 0:        try:          return func(*args, **kwargs)        except :          sleep(retry_wait)          retry_times -= 1    return wrapped_function  return retry_decorator

The simple retry modifier requires the variables to be perfectly captured by the closure, and the logic is quite simple and clear. The person who asked me said that the logic looks quite normal, but the error message that the variable retry_times cannot be found (unresolved reference) is always reported.

Right, let's take a look. This is a question: the variables captured by the closure (retry_times, retry_wait) are the local variables of the retry function referenced at the time, when the partial action of wrapped_function is performed on data of an unchangeable type, a new local variable is generated, but the newly generated local variable retry_times is not initialized before use, therefore, the system will prompt that the variable cannot be found; retry_wait can be used properly.

Python is the duck-typing programming language. Even if there is a warning running, write a function that is simple to the limit and use the decorator, make a breakpoint in the wrapped_function logic and check that the values of each variable can quickly locate the problem (the error UnboundLocalError: local variable 'retry _ attempts 'referenced before assignment can also be seen directly, at least more useful than warning msg ):

@retry(7, 8)def test():  print 23333  raise Exception('Call me exception 2333.')if __name__ == '__main__':  test()output: UnboundLocalError: local variable 'retry_times' referenced before assignment

To solve this problem, use a variable container to wrap the data of the immutable type to be used (say a question that has not been written C # code for a long time and is completely irresponsible, like in C #. net, when a closure is encountered, a class with a mixed name will be automatically generated and the value to be captured will be stored as a class attribute, so that the get can be easily used, the famous old zhao seems to have an article about Lazy Evaluation which seems to involve this topic ):

def retry(attempts=3, wait=2):  temp_dict = {    'retry_times': 3 if attempts < 0 or attempts > 5 else attempts,    'retry_wait': 2 if wait < 0 or wait > 5 else wait  }  def retry_decorate(fn):    @wraps(fn)    def wrapped_function(*args, **kwargs):      print id(temp_dict), temp_dict      while temp_dict.get('retry_times') > 0:        try:          return fn(*args, **kwargs)        except :          sleep(temp_dict.get('retry_wait'))          temp_dict['retry_times'] = temp_dict.get('retry_times') - 1        print id(temp_dict), temp_dict    print id(temp_dict), temp_dict    return wrapped_function  return retry_decorate@retry(7, 8)def test():  print 23333  raise Exception('Call me exception 2333.')if __name__ == '__main__':  test()

Output:

4405472064 {'retry_wait': 2, 'retry_times': 3}4405472064 {'retry_wait': 2, 'retry_times': 3}233334405472064 {'retry_wait': 2, 'retry_times': 2}233334405472064 {'retry_wait': 2, 'retry_times': 1}233334405472064 {'retry_wait': 2, 'retry_times': 0}

From the output, we can see that after packaging with dict, the program can work normally, as expected. In fact, we can also confirm from the closure value of the function again:

>>> test.func_closure[1].cell_contents{'retry_wait': 2, 'retry_times': 2}

I am the end, PEACE!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.