Primer on Python Decorators (Translated Article)
Trong tutorial mở đầu này, chúng ta sẽ tìm hiểu xem decorator là gì và làm thế nào để tạo và sử dụng chúng. Decorator cung cấp cú pháp (syntax) đơn giản để gọi function cấp cao hơn (higher-class function). Theo định nghĩa, decorator là một function nhận một function khác và mở rộng behaviour của ...
Trong tutorial mở đầu này, chúng ta sẽ tìm hiểu xem decorator là gì và làm thế nào để tạo và sử dụng chúng. Decorator cung cấp cú pháp (syntax) đơn giản để gọi function cấp cao hơn (higher-class function). Theo định nghĩa, decorator là một function nhận một function khác và mở rộng behaviour của function này mà không chỉnh sửa nó một cách tường minh. Nghe có vẻ khó hiểu - nhưng không thực sự vậy, đặc biệt là sau khi chúng ta đi qua một số ví dụ.
Functions
Trước khi bạn có thể hiểu decorator, đầu tiên bạn phải hiểu cách một function hoạt động. Về cơ bản, function sẽ trả về một giá trị dựa vào các tham số đầu vào.
def foo(bar): return bar + 1 print(foo(2) == 3)
First Class Objects
Trong Python, function là các first-class object. Điều này có nghĩa là function có thể được truyền và sử dụng như một tham số đầu vào, trả về từ một function cũng như là được assign cho một biến (variable).
def foo(bar): return bar + 1 print(foo) print(foo(2)) print(type(foo)) def call_foo_with_arg(foo, arg): return foo(arg) print(call_foo_with_arg(foo, 3))
Nested Functions
Bởi vì đặc tính first-class của function trong Python, bạn có thể định khai báo một function trong một function khác. Các function như vậy gọi là nested function.
def parent(): print("Printing from the parent() function.") def first_child(): return "Printing from the first_child() function." def second_child(): return "Printing from the second_child() function." print(first_child()) print(second_child())
Điều gì sẽ xảy ra nếu bạn gọi function parent()? Nghĩ về điều này một chút. Bạn sẽ nhận được:
Printing from the parent() function. Printing from the first_child() function. Printing from the second_child() function
Thử gọi hàm first_child(), bạn sẽ nhận được lỗi:
Traceback (most recent call last): File "decorator03.py", line 15, in <module> first_child() NameError: name 'first_child' is not defined
What have we learned?
Bất cứ khi nào bạn gọi function parent(), các function con, first_child() và second_child() cũng sẽ được gọi theo và bởi vì tính chất scope, cả hai function con này đều không tồn tại bên ngoài function cha, tức là chúng ta không thể được gọi trực tiếp từ bên ngoài function parent().
Returning Functions
Python cũng cho phép bạn trả về một function từ một function khác. Hãy sửa lại function trong ví dụ trước như sau:
def parent(num): def first_child(): return "Printing from the first_child() function." def second_child(): return "Printing from the second_child() function." try: assert num == 10 return first_child except AssertionError: return second_child foo = parent(10) bar = parent(11) print(foo) print(bar) print(foo()) print(bar())
Output của hai lệnh print đầu tiên là:
<function first_child at 0x1004a8c08> <function second_child at 0x1004a8cf8>
Điều này đơn giản có nghĩa là foo trỏ đến function first_child() trong khi bar trỏ đến function sencond_child()
Output của hai lệnh print sau:
Printing from the first_child() function. Printing from the second_child() function.
Sau cùng, bạn có để ý rằng trong ví dụ thứ ba, chúng ta thực thi các hàm con trong hàm cha - ví dụ như second_child(). Trong khi ở ví dụ cuối cùng, chúng ta không thêm cặp dấu ngoặc đơn () vào các hàm con - first_child - khi được gọi như vậy, chúng ta có thể sử dụng chúng trong tương lai. Okay?
Bây giờ thì chúng ta đã sẵn sàng tiếp nhận decorator.
Decorators
Hãy cùng xét hai ví dụ sau:
Example 1
def my_decorator(some_function): def wrapper(): print("Something is happening before some_function() is called.") some_function() print("Something is happening after some_function() is called.") return wrapper def just_some_function(): print("Wheee!") just_some_function = my_decorator(just_some_function) just_some_function()
Các bạn có thể đoán được output không? Hãy thử xem