Decorators là một công cụ quan trọng và hữu ích của Python. Nó cho phép chúng ta sửa đổi hành vi của hàm hoặc lớp. Cho đến giờ, chúng ta đã học cách tạo các bộ trang trí bằng cách sử dụng hàm, nhưng ở đây chúng ta sẽ thảo luận về việc định nghĩa một lớp làm bộ trang trí. Trong hướng dẫn này, chúng ta sẽ học cách trang trí lớp. Bạn đã quen thuộc với những người trang trí;
Trình trang trí cho phép chúng tôi bọc một chức năng khác để mở rộng hành vi của chức năng được bọc mà không thay đổi vĩnh viễn nó
Hãy xem ví dụ sau
Ví dụ -
đầu ra
********** 50 **********
Giải trình -
Trong đoạn mã trên, chúng ta đã tạo trình trang trí star[], lấy một số nguyên làm đối số và trả về một giá trị có thể gọi được. Hàm có thể gọi được lấy hàm func làm đối số, một hàm sẽ được trang trí. Ngoài ra, có thể gọi được có thể truy cập n từ nhà máy trang trí
Bây giờ chúng tôi sẽ triển khai trình trang trí này bằng cách sử dụng lớp Python
Trình trang trí lớp Python
Để xác định trình trang trí lớp, chúng ta cần sử dụng phương thức __call__[] của các lớp. Khi chúng ta cần tạo một đối tượng hoạt động giống như một hàm, trình trang trí chức năng phải trả về một đối tượng hoạt động giống như một hàm. Hãy hiểu ví dụ sau
Ví dụ 1
đầu ra
Giải trình -
Chúng tôi đã tạo trình trang trí đơn giản bằng cách sử dụng trình trang trí lớp bằng phương thức __call__. Chúng ta có thể sửa đổi nó như chúng ta muốn. Bây giờ, chúng ta viết lại đoạn mã trên bằng cách sử dụng trình trang trí lớp
Ví dụ - 2
đầu ra
Giải trình -
Mẫu [5] trả về một phiên bản của Mẫu và phiên bản đó có thể gọi được nên nó sẽ hoạt động như bên dưới
Trình trang trí lớp với Tuyên bố trả về
Chúng ta có thể sử dụng câu lệnh return trong trình trang trí lớp. Trong ví dụ trước, chúng tôi đã không trả lại bất cứ thứ gì, vì vậy không có vấn đề gì. Nhưng đôi khi, chúng ta cần trả về giá trị. Chúng tôi có thể làm điều đó như dưới đây
Ví dụ -
đầu ra
Given number is: 25 Cube of number is: 15625
Giải trình -
Trong đoạn mã trên, chúng ta đã tạo lớp CubeDecorataor làm công cụ trang trí và gọi phương thức __call__[]. Trong __call__[] chúng ta đã gọi hàm gọi và trả về kết quả
Sử dụng Trình trang trí lớp để in thời gian thực hiện chương trình
Chúng tôi sử dụng mô-đun thời gian với phương thức __call__ để lấy thời gian thực hiện chương trình. Hãy hiểu ví dụ sau
Ví dụ -
đầu ra
Execution took 4.004076242446899 seconds
Giải trình -
Chúng tôi đã nhập phương thức thời gian là t từ mô-đun thời gian trong đoạn mã trên. Sau đó, chúng tôi đã tạo lớp ExecutTimer làm công cụ trang trí, nơi chúng tôi có thời gian bắt đầu khi chương trình bắt đầu thực thi và thời gian kết thúc khi chương trình kết thúc. Chúng tôi đã trừ thời gian bắt đầu từ thời gian kết thúc và nhận được thời gian thực hiện chương trình
Phần kết luận
Trong hướng dẫn này, chúng tôi đã đề cập đến trình trang trí lớp với một số ví dụ. Trình trang trí là một công cụ quan trọng trong Python, nó thay đổi hành vi của chức năng khác mà không thay đổi cách triển khai thực tế của nó. Hầu hết thời gian, chúng tôi sử dụng các hàm Python để xác định các bộ trang trí, nhưng các bộ trang trí lớp cũng hữu ích và nâng cao khả năng đọc mã. Các trình trang trí lớp có thể được mở rộng dưới dạng lấy các đối số hoặc quay trở lại mặc định nếu không có đối số nào được thông qua
Bạn đã bao giờ tự hỏi làm thế nào một toán tử trang trí python [“@”] hoạt động chưa?
Hôm nay mình sẽ hướng dẫn các bạn cách hiện thực và sử dụng decorator trong python 3
THẬN TRỌNG. Đừng nhầm lẫn giữa decorator — biểu thị toán tử trang trí “@” — với Decorator Design Pattern
Trang trí là gì?Python là ngôn ngữ lập trình hạng nhất, có nghĩa là các hàm có thể được truyền xung quanh dưới dạng đối số, giống như bất kỳ đối tượng nào khác. Điều này cho phép tồn tại các hàm bậc cao hơn [HOF] có thể nhận và/hoặc trả về các hàm khác
Một trang trí về cơ bản là một HOF;
Hãy xem ví dụ sau
Ở đây, validate_is_function_signature_funky được sử dụng làm công cụ trang trí. Nó kiểm tra chữ ký của hàm mà nó trang trí, cụ thể là hàm funky_function và đưa ra lỗi nếu chữ ký của hàm không hợp lệ. Trong trường hợp này, trình trang trí không quan tâm đến giá trị trả về cũng như bản thân đầu vào
Trình trang trí về cơ bản là đường cú pháp. Hãy nhìn vào đây
Bằng cách trang trí một chức năng, bạn khéo léo cung cấp cho nó chức năng “đặc biệt” và xác định lại chức năng đó bằng các tính năng bổ sung
Bây giờ chúng ta đã có một ý tưởng sơ bộ về những gì một người trang trí có thể làm, hãy để chúng ta tìm hiểu sâu hơn về những người trang trí và cách họ làm việc
Chức năng trang tríTrình trang trí chức năng là một HOF lấy chức năng [đối tượng trang trí] làm đầu vào
Trường hợp 1 - trang trí không có đầu vào trực tiếp
Đôi khi trình trang trí không cần đầu vào bổ sung nào ngoài chức năng mà nó trang trí và các đối số của nó. Đây là một triển khai lớp của trình trang trí của chúng tôi
Rất nhiều thứ đang diễn ra ở đây, vì vậy hãy đi sâu vào. Đây là những gì đang xảy ra đằng sau hiện trường tại
- thời gian trang trí
- thời gian gọi
Đây là lý do tại sao __call__ được gọi với các đầu vào chức năng
Bạn cũng có thể triển khai các trình trang trí không có đầu vào bằng các hàm
Bạn có thể nói, những gì đang xảy ra ở đây?
Trường hợp 2 - trang trí với đầu vào trực tiếp
Nhưng nếu bạn cần chuyển trực tiếp [các] đối số cho trình trang trí của mình thì sao? . Hãy xem việc triển khai lớp sau
à há. Một cái gì đó thú vị đã xảy ra ở đây. Bạn có thể cho biết, tại sao điều này là?
Bởi vì ban đầu chúng ta đã truyền đối số cho trình trang trí, nên chúng ta phải truyền hàm trong lần gọi tiếp theo. Đây là những gì đang xảy ra tại
- Thời gian trang trí [cả __init__ và __call__ được gọi]
- Thời gian gọi [hàm được trả về bởi __call__ hiện được gọi với các đối số my_function, cụ thể là a, b và c
Bạn cũng có thể triển khai một trình trang trí như vậy bằng cách sử dụng các hàm. Bạn cần tạo hai hàm lồng nhau vì bản thân hàm trang trí sẽ được gọi với đầu vào của chính nó trước, sau đó là hàm bên trong với hàm trang trí làm đối số đầu vào. Cuối cùng, khi gọi hàm được trang trí, hàm bên trong nhất sẽ được gọi, lấy đầu vào của hàm được trang trí
Bây giờ bạn sẽ có thể nói những gì đang xảy ra đằng sau hiện trường. Vì vậy, tôi sẽ để lại cái này như một bài tập cho bạn
Nếu bạn đang tự hỏi những trường hợp sử dụng thực tế nào dành cho trình trang trí trong python, hãy xem thư viện python này có nhiều ví dụ như vậy. Chúng ta hãy xem xét một trường hợp sử dụng thực tế của người trang trí
Điều đó làm cho mã dễ đọc hơn. Lưu ý rằng nó cũng giới thiệu khớp nối lỏng lẻo hơn giữa các thành phần khác nhau và tăng cường đáng kể khả năng phục hồi của các chức năng. tôi thích nó
Một trình trang trí lớp là một trình trang trí một đối tượng lớp python. Nó hoạt động giống như trong trường hợp của hàm, ngoại trừ đối tượng được trang trí là một lớp. Bạn có thể đoán rằng trình trang trí mà bạn đang triển khai sẽ trả về một tham chiếu đến lớp có thứ tự cao hơn, sau đó
Một ví dụ về trình trang trí lớp là một ví dụ khi được sử dụng sẽ nhân mọi phương thức của lớp. Tất nhiên, một cách để đạt được điều đó là sử dụng một hàm trang trí, hãy gọi nó là time_this, như vậy
class ImportantStuff[object]:
@time_this
def do_stuff_1[self]:
..
@time_this
def do_stuff_2[self]:
...
@time_this
def do_stuff_3[self]:
...
Việc triển khai trình trang trí ở trên giống hệt với chức năng độc lập, vì vậy tôi sẽ để bạn thực hiện nó như một thông lệ
Nhưng chúng ta có thể làm tốt hơn bằng cách đơn giản là trang trí toàn bộ lớp bằng cách sử dụng trình trang trí lớp
@time_all_class_methods
class ImportantStuff:
def do_stuff_1[self]:
...
def do_stuff_2[self]:
...
Điều này giúp loại bỏ sự tẻ nhạt của việc thêm trình trang trí vào mọi chức năng. Trình trang trí trong trường hợp này nên kiểm tra xem thuộc tính đang được truy cập có phải là một phương thức của lớp hay không, mỗi khi đạt đến một thể hiện của lớp đó. Nếu đúng, thì nó gọi hàm đó và ghi lại thời gian trước và sau khi phương thức được gọi
May mắn thay, điều này có thể thực hiện được thông qua các bộ trang trí, miễn là bộ trang trí trả về một lớp đặc biệt. Lớp chúng ta cần triển khai phải có triển khai “__getattribute__” tùy chỉnh để kiểm tra thủ công xem thuộc tính đang được truy cập thuộc về lớp được trang trí hay của chính nó. Nếu phương thức không thuộc lớp trang trí đơn giản, điều đó có nghĩa là nó thuộc lớp trang trí, vì vậy chúng ta sẽ phải tính thời gian cho nó. Đó là tất cả
Hãy xem cách triển khai bên dưới. Thoạt nhìn có vẻ phức tạp, nhưng đó thực sự là tất cả những gì cần làm. Đây là cách chúng ta có thể đạt được điều này
Lưu ý rằng trình trang trí trả về lớp Trình bao bọc ở mức cao nhất. Điều này có nghĩa là tại thời điểm trang trí, MyClass được định nghĩa lại như một loại lớp “bao bọc” MyClass. Sử dụng đầu ra được đề cập trong ví dụ trên, chúng ta có thể hiểu rõ hơn về điều này
- Dòng 71–72. Thời kỳ trang trí
MyClass = Wrapper # That's it!
- Dòng 73 — 76. Khởi tạo MyClass
instance = MyClass[] # Wrapper[MyClass][]
- Dòng 77 — 81. Phương thức hạng nhất được gọi
instance.method_x[] # Wrapper[MyClass][MyClass.method_x]
- Dòng 83 — 87. Phương thức lớp thứ hai được gọi
Đây là lý do tại sao chúng ta cần triển khai thủ công hàm __getattribute__ dunder cho hàm bao bọc của mình
Tập thể dục. làm cách nào chúng ta có thể triển khai trình trang trí lớp trực tiếp nhận đầu vào của chính nó tại thời điểm trang trí?
Trang trí cực kỳ mạnh mẽ và có thể làm cho cuộc sống dễ dàng hơn. Không dễ để làm quen với chúng trước, nhưng nếu được sử dụng đúng cách, chúng có thể giải quyết vấn đề tốt. Trình trang trí lớp rõ ràng phức tạp hơn một chút so với trình trang trí chức năng
Trước tiên, hãy hiểu vấn đề bạn đang cố gắng giải quyết. Bạn có quan tâm đến chính hàm đó, các đối số của nó, giá trị trả về hoặc sự kết hợp của chúng không?
TL;DR — Tóm tắtTrình trang trí là cách của python để thao tác các phần tử của ngôn ngữ python. Về cơ bản, chúng là các hàm bậc cao lấy các phần tử mà chúng trang trí làm đầu vào và có thể nắm bắt đầu vào và đầu ra của đối tượng
Trường hợp sử dụng mẫu sẽ là trình trang trí bộ nhớ đệm lưu trữ cặp khóa-giá trị của đầu vào và đầu ra của hàm
@cache_io # caches the results
def fibo[n]:
if n in [0, 1]:
return n
return fibo[n - 1] + fibo[n - 2]
Thông thường, các bộ trang trí có thể được triển khai dưới dạng các hàm trả về các hàm hoặc các lớp
Người trang trí có thể có hoặc không có đối số. Nếu họ làm như vậy, nó sẽ thay đổi luồng trang trí và sau đó là việc gọi hàm được trang trí hoặc thể hiện của lớp. Do đó, việc triển khai sẽ cần điều chỉnh thêm một chút
Đây là một bộ sơ đồ đẹp cho các bộ trang trí chức năng
Trình trang trí chức năng không có đối số đầu vào
Trình trang trí chức năng với các đối số đầu vào
Nếu được sử dụng đúng cách, các trình trang trí có thể làm cho mã của bạn dễ đọc hơn và loại bỏ các thao tác trừu tượng không cần phải kết hợp quá chặt chẽ với mã của bạn