Trong Python, các hàm đều là các first class objects – các đối tượng hạng nhất, điều này có nghĩa là:

– Các hàm đều là đối tượng nên chúng có thể được tham chiếu tới, được truyền cho một biến, và được trả về từ các hàm khác.

– Các hàm có thể được khai báo bên trong một hàm khác và cũng có thể được truyền làm đối số cho một hàm khác.

Decorator là công cụ hữu ích và mạnh mẽ trong Python bởi vì nó cho phép các lập trình viên có thể sửa đổi hành vi của hàm hoặc lớp (class). Các decorators cho phép chúng ta đóng gói một hàm để mở rộng hành vi của hàm đã được đóng gói đó, mà không cần phải chỉnh sửa nó.

Trong Decorator, các hàm được nhận vào làm đối số cho một hàm khác, và sau đó được gọi ở bên trong hàm đóng gói đó (wrapper function – chính là cái hàm mà nhận hàm khác làm đối số của nó).

1. Cú pháp của Decorator

# -----------------------------------------------------------
#Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
#@author cafedevn
#Contact: cafedevn@gmail.com
#Fanpage: https://www.facebook.com/cafedevn
#Instagram: https://instagram.com/cafedevn
#Twitter: https://twitter.com/CafedeVn
#Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
# -----------------------------------------------------------

@gfg_decorator
def hello_decorator(): 
    print("Gfg") 
  
'''Above code is equivalent to - 
  
def hello_decorator(): 
    print("Gfg") 
      
hello_decorator = gfg_decorator(hello_decorator)'''

Trong đoạn code trên, gfg_decorator là một hàm có thể gọi được (callable function), sẽ bổ sung thêm một số code vào phần đầu của hàm hello_decorator và trả về hàm đã được đóng gói.

2. Decorator có thể thay đổi hành vi của hàm

# -----------------------------------------------------------
#Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
#@author cafedevn
#Contact: cafedevn@gmail.com
#Fanpage: https://www.facebook.com/cafedevn
#Instagram: https://instagram.com/cafedevn
#Twitter: https://twitter.com/CafedeVn
#Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
# -----------------------------------------------------------


# defining a decorator 
def hello_decorator(func): 
  
    # inner1 is a Wrapper function in  
    # which the argument is called 
      
    # inner function can access the outer local 
    # functions like in this case "func" 
    def inner1(): 
        print("Hello, this is before function execution") 
  
        # calling the actual function now 
        # inside the wrapper function. 
        func() 
  
        print("This is after function execution") 
          
    return inner1 
  
  
# defining a function, to be called inside wrapper 
def function_to_be_used(): 
    print("This is inside the function !!") 
  
  
# passing 'function_to_be_used' inside the 
# decorator to control its behavior 
function_to_be_used = hello_decorator(function_to_be_used) 
  
  
# calling the function 
function_to_be_used() 

Kết quả in ra là:

Hello, this is before function execution
This is inside the function !!
This is after function execution

Chúng ta cùng xem hành vi của đoạn code trên, và cách nó chạy từng bước một như thế nào khi hàm “function_to_be_used” được gọi

Ví dụ sau đây sẽ thực hiện tìm ra thời gian thực thi của một hàm bằng cách sử dụng decorator.

# -----------------------------------------------------------
#Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
#@author cafedevn
#Contact: cafedevn@gmail.com
#Fanpage: https://www.facebook.com/cafedevn
#Instagram: https://instagram.com/cafedevn
#Twitter: https://twitter.com/CafedeVn
#Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
# -----------------------------------------------------------


# importing libraries 
import time 
import math 
  
# decorator to calculate duration 
# taken by any function. 
def calculate_time(func): 
      
    # added arguments inside the inner1, 
    # if function takes any arguments, 
    # can be added like this. 
    def inner1(*args, **kwargs): 
  
        # storing time before function execution 
        begin = time.time() 
          
        func(*args, **kwargs) 
  
        # storing time after function execution 
        end = time.time() 
        print("Total time taken in : ", func.__name__, end - begin) 
  
    return inner1 
  
  
  
# this can be added to any function present, 
# in this case to calculate a factorial 
@calculate_time
def factorial(num): 
  
    # sleep 2 seconds because it takes very less time 
    # so that you can see the actual difference 
    time.sleep(2) 
    print(math.factorial(num)) 
  
# calling the function. 
factorial(10) 

Kết quả in ra là:

3628800
Total time taken in :  factorial 2.0061802864074707

3. Sẽ thế nào nếu một hàm có trả về thứ gì đó

Trong tất cả các ví dụ trên, các hàm đều không trả về bất cứ thứ gì, vì vậy ta không gặp trở ngại nào, nhưng hàm trả về kết quả sẽ là trường hợp ta thường xuyên gặp phải, ví dụ sau sẽ minh họa điều này:


def hello_decorator(func): 
    def inner1(*args, **kwargs): 
          
        print("before Execution") 
          
        # getting the returned value 
        returned_value = func(*args, **kwargs) 
        print("after Execution") 
          
        # returning the value to the original frame 
        return returned_value 
          
    return inner1 
  
  
# adding decorator to the function 
@hello_decorator
def sum_two_numbers(a, b): 
    print("Inside the function") 
    return a + b 
  
a, b = 1, 2
  
# getting the value through return of the function 
print("Sum =", sum_two_numbers(a, b)) 

Kết quả in ra là:

before Execution
Inside the function
after Execution
Sum = 3

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!