Header ads

Header ads
» » Decorator trong Python

Decorator được sử dụng tương đối nhiều trong Python. Ở bài viết này, Quantrimang.com sẽ cùng bạn tìm hiểu làm thế nào để tạo ra một Decorator và lý do tại sao bạn nên sử dụng nó. Hãy cùng đi tìm lời giải đáp! 

Decorator trong Python là gì?

Python có một tính năng khá thú vị gọi là decorator. Decorator là một hàm nhận tham số đầu vào là một hàm khác và mở rộng tính năng cho hàm đó mà không thay đổi nội dung của nó.

Đây cũng được gọi là metaprogramming - siêu lập trình, hiểu đơn giản là "Code sinh ra code", nghĩa là mình viết một chương trình và chương trình này sẽ sinh ra, điều khiển các chương trình khác hoặc làm một phần công việc ngay tại thời điểm biên dịch. 

Điều kiện để có Decorator

Để hiểu về decorator, trước tiên bạn cần xem lại một vài điều cơ bản trong Python.

Hàm là một khái niệm rất cơ bản trong lập trình nói chung. Tuy nhiên, trong Python, hàm cũng là đối tượng. Các tên hàm mà chúng ta khai báo chỉ đơn giản là định danh ràng buộc với các đối tượng này. Một đối tượng hàm cũng có thể được liên kết cùng với nhiều tên khác nhau. Ví dụ:

def first(msg):       print(msg)          first("Hello")      second = first   second("Hello")

Khi bạn chạy code, hàm firstsecond đều trả về cùng một output. Ở đây, firstsecond đề cập đến cùng một đối tượng hàm.

Hãy theo dõi tiếp, các hàm có thể được truyền dưới dạng tham số cho một hàm khác (tương tự như map, filterreduce trong Python).

Những hàm lấy hàm khác làm tham số đầu vào được gọi là hàm bậc cao (higher-order functions). Ví dụ như này:

def inc(x):       return x + 1      def dec(x):       return x - 1      def operate(func, x):       result = func(x)       return result

Chúng ta gọi hàm như sau.

>>> operate(inc,3)   4   >>> operate(dec,3)   2

Hơn nữa, một hàm có thể trả về kết quả một hàm khác.

def is_called():       def is_returned():           print("Hello")       return is_returned      new = is_called()      #Outputs "Hello"   new()

Ở đây, is_returned() là một hàm lồng nhau, hàm này sẽ được truy cập và trả về kết quả mỗi khi ta gọi hàm is_called().

Để rõ hơn, bạn có thể tham khảo thêm bài học Cách sử dụng Closure trong Python

Quay trở lại với Decorator, hiểu một cách cơ bản nhất, Decorator là một hàm có thể nhận các hàm khác, cho phép bạn chạy một số đoạn code trước hoặc sau hàm chính mà không thay đổi kết quả.

def make_pretty(func):       def inner():           print("I got decorated")           func()       return inner      def ordinary():       print("I am ordinary")

Chạy code trong Python shell:

>>> ordinary()   I am ordinary      >>> # Thử hàm decorate trong hàm ordinary   >>> pretty = make_pretty(ordinary)   >>> pretty()   I got decorated   I am ordinary

Trong ví dụ trên, make_pretty() là một decorator. Khi ta gọi

pretty = make_pretty(ordinary)   

thì hàm ordinary() được decorator truyền vào làm tham số và hàm trả về tên là pretty.

Bạn có thể thấy ở đây, decorator đã thêm một hàm mới cho hàm ban đầu. Hãy hình dung nó như kiểu đóng gói một món quá. Các decorator là lớp bọc ở ngoài, bản chất của đối tượng được decorator truyền vào làm tham số (món quà bên trong) không thay đổi, nhưng hiện giờ nó có thêm một lớp bọc decorator ở ngoài.

Nói chung, ở đây ta decorator một hàm và gán lại nó:

ordinary = make_pretty(ordinary)

Đây là một cấu trúc phổ biến, vì vậy Python có một cú pháp để đơn giản hóa việc này.

Bạn có thể sử dụng ký hiệu @ cùng với tên của hàm decorator và đặt nó lên trên định nghĩa của hàm được decorator. Ví dụ:

@make_pretty   def ordinary():       print("I am ordinary")

tương đương với:

def ordinary():       print("I am ordinary")   ordinary = make_pretty(ordinary)

Đây là một cú pháp đặc biệt để thực hiện decorator.

Tham số hàm decorator

Các decorator ở trên đều khá đơn giản và hoạt động cùng với các hàm không có bất kỳ tham số nào. Bây giờ ta hãy thử truyền tham số cho hàm trả về bởi decorator như sau:

def divide(a, b):       return a/b

Hàm này có hai tham số, a và b, sẽ báo lỗi nếu b=0

>>> divide(2,5)   0.4   >>> divide(2,0)   Traceback (most recent call last):   ...   ZeroDivisionError: division by zero

Khi ta gọi hàm là thực ra gọi hàm được trả về bởi decorator, nên nếu truyền tham số cho hàm này thì nó sẽ truyền cho hàm được decorate.

Bây giờ chúng ta hãy tạo một decorator để kiểm tra trường hợp này có xảy ra lỗi hay không.

def smart_divide(func):      def inner(a,b):         print("I am going to divide",a,"and",b)         if b == 0:            print("Whoops! cannot divide")            return            return func(a,b)      return inner      @smart_divide   def divide(a,b):       return a/b

Chương trình sẽ trả về None nếu có lỗi phát sinh.

>>> divide(2,5)   I am going to divide 2 and 5   0.4   >>> divide(2,0)   I am going to divide 2 and 0   Whoops! cannot divide

Đây chính là cách sử dụng hàm decorator có tham số.

Ngoài ra, bạn có thể xây dựng một decorator với số lượng tham số khác nhau tùy ý, chỉ cần sử dụng cú pháp *args**kwargs.

def works_for_all(func):       def inner(*args, **kwargs):           print("I can decorate any function")           return func(*args, **kwargs)       return inner

Khi ta gọi hàm, thực ra là chúng ta gọi hàm được trả về bởi decorator, nên nếu chúng ta truyền tham số cho hàm này thì nó sẽ truyền cho hàm được decorate.

Chuỗi Decorator trong Python

Nhiều decorator có thể được tạo thành chuỗi decorator trong Python.

Nghĩa là một hàm có thể được decorate nhiều lần với các decorator giống hoặc khác nhau, chỉ cần đặt decorator lên trước hàm bạn muốn là được.

def star(func):       def inner(*args, **kwargs):           print("*" * 30)           func(*args, **kwargs)           print("*" * 30)       return inner      def percent(func):       def inner(*args, **kwargs):           print("%" * 30)           func(*args, **kwargs)           print("%" * 30)       return inner      @star   @percent   def printer(msg):       print(msg)   printer("Hello")

Chương trình sẽ trả về output:

******************************   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%   Hello   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%   ******************************

Cú pháp:

@star   @percent   def printer(msg):       print(msg)   

tương đương với:

def printer(msg):       print(msg)   printer = star(percent(printer))

Thứ tự của decorator cũng quan trọng, nếu bạn đảo ngược: 

@percent   @star   def printer(msg):       print(msg)

Kết quả sẽ khác:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%   ******************************   Hello   ******************************   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Bài trước: Cách sử dụng Closure trong Python

Bài tiếp: Khai báo @property trong Python


Khóa đào tạo Power BI phân tích báo cáo để bán hàng thành công

Khóa học Lập trình Visual Foxpro 9 - Dành cho nhà quản lý và kế toán

Khóa học hướng dẫn về Moodle chuyên nghiệp và hay
Xây dựng hệ thống đào tạo trực tuyến chuyên nghiệp tốt nhất hiện nay.


Khóa học AutoIt dành cho dân IT và Marketing chuyên nghiệp

Khóa học hướng dẫn sử dụng Powerpoint từ đơn giản đến phức tạp HIỆU QUẢ
Khóa học Thiết kế, quản lý dữ liệu dự án chuyên nghiệp cho doanh nghiệp bằng Bizagi
 Khoa hoc hay
Khóa học Phân tích dữ liệu sử dụng Power Query trong Excel
Khóa học Phân tích dữ liệu sử dụng TableAU - Chìa khóa thành công!
Nhấn vào đây để bắt đầu khóa học

Khóa học "Thiết kế bài giảng điện tử", Video, hoạt hình 
kiếm tiền Youtube bằng phần mềm Camtasia Studio
Khóa học HƯỚNG DẪN THIẾT KẾ VIDEO CLIP CHO DÂN MARKETING CHUYÊN NGHIỆP
 Xây dựng website​​​​
HƯỚNG DẪN THIẾT KẾ QUẢNG CÁO VÀ ĐỒ HỌA CHUYÊN NGHIỆP VỚI CANVA
Hãy tham gia khóa học để trở thành người chuyên nghiệp. Tuyệt HAY!😲👍
 Khoa hoc hay
MICROSOFT ACCESS



GOOGLE SPREADSHEETS phê không tưởng
 Khoa hoc hay
Khóa hoc lập trình bằng Python tại đây

Hacker mũ trắng




Hãy tham gia khóa học để biết mọi thứ

Để tham gia tất cả các bài học, Bạn nhấn vào đây 
Khóa học sử dụng Adobe Presenter-Tạo bài giảng điện tử
 Khoa hoc hay

Khóa học sử dụng Edmodo để dạy và học hiện đại để thành công


Cập nhật công nghệ từ Youtube tại link: http://congnghe.hocviendaotao.com
Tham gia nhóm Facebook
Để tham gia khóa học công nghệ truy cập link: http://thuvien.hocviendaotao.com
Mọi hỗ trợ về công nghệ email: dinhanhtuan68@gmail.com

About Học viện đào tạo trực tuyến

Xinh chào bạn. Tôi là Đinh Anh Tuấn - Thạc sĩ CNTT. Email: dinhanhtuan68@gmail.com .
- Nhận đào tạo trực tuyến lập trình dành cho nhà quản lý, kế toán bằng Foxpro, Access 2010, Excel, Macro Excel, Macro Word, chứng chỉ MOS cao cấp, IC3, tiếng anh, phần mềm, phần cứng .
- Nhận thiết kế phần mềm quản lý, Web, Web ứng dụng, quản lý, bán hàng,... Nhận Thiết kế bài giảng điện tử, số hóa tài liệu...
HỌC VIỆN ĐÀO TẠO TRỰC TUYẾN:TẬN TÂM-CHẤT LƯỢNG.
«
Next
Bài đăng Mới hơn
»
Previous
Bài đăng Cũ hơn