Decorator methods outside the class decorate class methods and call other methods of the class
Scenario: a class that links to a database often disconnects when performing database operations. At this time, you need to call the class's connect database method to re link to the database
class My_dbclient(): def __init__(self): self.try_count=10 self.connect() def connect(self): print("Database link succeeded") def insert(self): # Database disconnection exception may occur print("Saving operation in progress") for i in range(self.try_count): try: print("Save data") # raise NameError return except Exception: time.sleep(1) self.connect() print(traceback.format_exc()) def select(self): # Database disconnection exception may occur print("Query data") def delete(self): # Database disconnection exception may occur print("Delete data")
As in the insert method, you can catch exceptions, relink them, and then operate.
However, no matter how to add, delete, modify or search, it needs to be written in this way. The code is redundant. It's natural to use decorators.
Example:
The conventional way of writing decorators
def catch_error(fun): def wrapper(*args, **kwargs): for i in range(1, 10): try: fun(*args, **kwargs) return except Exception: time.sleep(1) print("link error---{}---second".format(i)) print("Call the database link method, and link the database again") print("Information saving failed") return wrapper @catch_error def insert(): print("Start insert statement") raise TimeoutError
Now we want to decorate the class method and call the database link method to re link after catching the database link exception.
Solution: add the self parameter to the wrapper parameter of the decorator's internal function, as follows, you can use self to call the connect method.
def catch_error(fun): def wrapper(self,*args, **kwargs): for i in range(1, 10): try: fun(*args, **kwargs) return except Exception: time.sleep(1) print("link error---{}---second".format(i)) print("Call the database link method, and link the database again") self.connect() print("Information saving failed") return wrapper
Full code:
import time import traceback def catch_error(fun): def wrapper(self,*args, **kwargs): for i in range(1, 10): try: fun(*args, **kwargs) return except Exception: time.sleep(1) print("link error---{}---second".format(i)) print("Call the database link method, and link the database again") self.connect() print("Information saving failed") return wrapper @catch_error def insert(): print("Start insert statement") raise TimeoutError class My_dbclient(): def __init__(self): self.try_count = 10 self.connect() def connect(self): print("Database link succeeded") @catch_error def insert(self): # Database disconnection exception may occur print("Save data") raise TimeoutError def select(self): # Database disconnection exception may occur print("Query data") def delete(self): # Database disconnection exception may occur print("Delete data") if __name__ == '__main__': t = My_dbclient() t.insert()
But there is a hole in it:
- In this decorator, to catch an Exception, you must use Exception to catch it! It cannot be any other Exception, even if the Exception thrown and the Exception to be caught are the same Exception.
- Decorating ordinary functions has no effect
As follows:
def catch_error(fun): def wrapper(self,*args, **kwargs): for i in range(1, 10): try: fun(*args, **kwargs) return except NameError: time.sleep(1) print("link error---{}---second".format(i)) print("Call the database link method, and link the database again") self.connect() print("Information saving failed") return wrapper @catch_error def insert(self): # Class method # Database disconnection exception may occur print("Save data") raise NameError //Database link succeeded Traceback (most recent call last): File "D:/test.py", line 54, in <module> t.insert() File "D:/test.py", line 9, in wrapper fun(*args, **kwargs) TypeError: insert() missing 1 required positional argument: 'self'