Khi tôi lần đầu tiên biết về các công cụ trang trí Python, việc sử dụng chúng giống như làm phép thuật voodoo. Trình trang trí có thể cung cấp cho bạn khả năng thêm các chức năng mới vào bất kỳ chức năng nào có thể gọi được mà không thực sự chạm vào hoặc thay đổi mã bên trong nó. Điều này thường có thể mang lại khả năng đóng gói tốt hơn và giúp bạn viết mã rõ ràng và dễ hiểu hơn. Tuy nhiên, decorator được coi là một chủ đề khá nâng cao trong Python vì để hiểu và viết nó yêu cầu bạn phải có lệnh đối với nhiều khái niệm bổ sung như đối tượng hạng nhất, hàm bậc cao hơn, bao đóng, v.v. Đầu tiên, tôi sẽ cố gắng giới thiệu những khái niệm này khi cần thiết và sau đó làm sáng tỏ khái niệm cốt lõi của lớp trang trí theo từng lớp. Vì vậy, hãy đi sâu vào
Đối tượng hạng nhất
Trong Python, về cơ bản mọi thứ đều là đối tượng và các hàm được coi là đối tượng hạng nhất. Điều đó có nghĩa là các hàm có thể được truyền xung quanh và được sử dụng làm đối số, giống như bất kỳ đối tượng nào khác [chuỗi, int, float, danh sách, v.v.]. Bạn có thể gán các hàm cho các biến và xử lý chúng như bất kỳ đối tượng nào khác. Hãy xem xét ví dụ này
def func_a[]:
return "I was angry with my friend."
def func_b[]:
return "I told my wrath, my wrath did end"
def func_c[*funcs]:
for func in funcs:
print[func[]]
main_func = func_c
main_func[func_a, func_b]
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
Ví dụ trên minh họa cách Python coi các chức năng là công dân hạng nhất. Đầu tiên, tôi định nghĩa hai hàm,
>>> 'Hello from the inner func'
6 và >>> 'Hello from the inner func'
7, sau đó >>> 'Hello from the inner func'
8 lấy chúng làm tham số. >>> 'Hello from the inner func'
8 chạy các hàm được lấy làm tham số và in kết quả. Sau đó, chúng tôi gán >>> 'Hello from the inner func'
8 cho biến def burger[name]:
def ingredients[]:
if name == "deli":
return ["steak", "pastrami", "emmental"]
elif name == "smashed":
return ["chicken", "nacho cheese", "jalapeno"]
else:
return None
return ingredients
1. Cuối cùng, chúng tôi chạy def burger[name]:
def ingredients[]:
if name == "deli":
return ["steak", "pastrami", "emmental"]
elif name == "smashed":
return ["chicken", "nacho cheese", "jalapeno"]
else:
return None
return ingredients
1 và nó hoạt động giống như >>> 'Hello from the inner func'
8Hàm bậc cao hơn
Python cũng cho phép bạn sử dụng các hàm làm giá trị trả về. Bạn có thể nhận một hàm khác và trả về hàm đó hoặc bạn có thể định nghĩa một hàm bên trong một hàm khác và trả về hàm bên trong
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
0>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
1Bây giờ bạn có thể gán kết quả của
def burger[name]:
def ingredients[]:
if name == "deli":
return ["steak", "pastrami", "emmental"]
elif name == "smashed":
return ["chicken", "nacho cheese", "jalapeno"]
else:
return None
return ingredients
4 cho một biến khác và thực hiện chức năng đầu ra>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
3>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
4Hãy xem xét một ví dụ khác nơi bạn có thể định nghĩa một hàm lồng trong một hàm và trả về hàm lồng thay vì kết quả của nó
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
5>>> 'Hello from the inner func'
Lưu ý cách hàm lồng nhau
def burger[name]:
def ingredients[]:
if name == "deli":
return ["steak", "pastrami", "emmental"]
elif name == "smashed":
return ["chicken", "nacho cheese", "jalapeno"]
else:
return None
return ingredients
5 được định nghĩa bên trong hàm def burger[name]:
def ingredients[]:
if name == "deli":
return ["steak", "pastrami", "emmental"]
elif name == "smashed":
return ["chicken", "nacho cheese", "jalapeno"]
else:
return None
return ingredients
6 và sau đó câu lệnh return của hàm def burger[name]:
def ingredients[]:
if name == "deli":
return ["steak", "pastrami", "emmental"]
elif name == "smashed":
return ["chicken", "nacho cheese", "jalapeno"]
else:
return None
return ingredients
6 trả về hàm lồng nhau. Sau khi định nghĩa, để đến hàm lồng nhau, đầu tiên chúng ta gọi hàm def burger[name]:
def ingredients[]:
if name == "deli":
return ["steak", "pastrami", "emmental"]
elif name == "smashed":
return ["chicken", "nacho cheese", "jalapeno"]
else:
return None
return ingredients
6 và nhận kết quả là một hàm khác. Sau đó thực hiện kết quả của hàm def burger[name]:
def ingredients[]:
if name == "deli":
return ["steak", "pastrami", "emmental"]
elif name == "smashed":
return ["chicken", "nacho cheese", "jalapeno"]
else:
return None
return ingredients
6 in ra thông báo từ hàm def burger[name]:
def ingredients[]:
if name == "deli":
return ["steak", "pastrami", "emmental"]
elif name == "smashed":
return ["chicken", "nacho cheese", "jalapeno"]
else:
return None
return ingredients
5đóng cửa
Bạn đã thấy các ví dụ về chức năng bên trong hoạt động trong phần trước. Các hàm lồng nhau có thể truy cập các biến của phạm vi kèm theo. Trong Python, các biến không cục bộ này chỉ được đọc theo mặc định và chúng ta phải khai báo chúng một cách rõ ràng là không cục bộ [sử dụng từ khóa
>>> 'Hello from the inner func'
31] để sửa đổi chúng. Sau đây là một ví dụ về hàm lồng nhau truy cập một biến không cục bộdef burger[name]:
def ingredients[]:
if name == "deli":
return ["steak", "pastrami", "emmental"]
elif name == "smashed":
return ["chicken", "nacho cheese", "jalapeno"]
else:
return None
return ingredients
Bây giờ chạy chức năng,
>>> 'Hello from the inner func'
3>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
0Chà, thật bất thường
Hàm
>>> 'Hello from the inner func'
32 được gọi với chuỗi >>> 'Hello from the inner func'
33 và hàm trả về được gắn với tên >>> 'Hello from the inner func'
34. Khi gọi >>> 'Hello from the inner func'
35, thông báo vẫn được ghi nhớ và được sử dụng để lấy kết quả mặc dù chức năng bên ngoài >>> 'Hello from the inner func'
32 đã hoàn thành việc thực hiệnKỹ thuật này mà một số dữ liệu [“deli”] được gắn vào mã được gọi là đóng trong Python. Giá trị trong phạm vi kèm theo được ghi nhớ ngay cả khi biến nằm ngoài phạm vi hoặc chính hàm đó bị xóa khỏi không gian tên hiện tại. Người trang trí sử dụng ý tưởng về các biến không cục bộ nhiều lần và bạn sẽ sớm thấy cách
Viết một Decorator cơ bản
Với những điều kiện tiên quyết này, hãy tiếp tục và tạo công cụ trang trí đơn giản đầu tiên của bạn
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
1Trước khi sử dụng decorator, hãy xác định một hàm đơn giản không có bất kỳ tham số nào
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
2Coi các chức năng là đối tượng hạng nhất, bạn có thể sử dụng trình trang trí của mình như thế này
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
3>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
4Trong hai dòng trên, bạn có thể thấy một trình trang trí rất đơn giản đang hoạt động. Hàm
>>> 'Hello from the inner func'
37 của chúng tôi nhận một hàm mục tiêu, thao tác hàm mục tiêu bên trong hàm >>> 'Hello from the inner func'
38 và sau đó trả về hàm >>> 'Hello from the inner func'
38. Chạy hàm được trả về bởi trình trang trí, bạn sẽ nhận được kết quả đã sửa đổi của mình. Nói một cách đơn giản, các trình trang trí bao bọc một chức năng và sửa đổi hành vi của nóChức năng trang trí chạy tại thời điểm chức năng trang trí được nhập/xác định, không phải khi nó được gọi
Trước khi chuyển sang phần tiếp theo, hãy xem cách chúng ta có thể lấy giá trị trả về của hàm mục tiêu thay vì chỉ in nó
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
5Trong ví dụ trên, hàm trình bao bọc trả về kết quả của hàm đích và chính trình bao bọc. Điều này giúp có thể nhận được kết quả của hàm đã sửa đổi
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
6>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
7Bạn có đoán được tại sao giá trị trả về của hàm được trang trí lại xuất hiện ở dòng cuối cùng thay vì ở giữa như trước đây không?
Đường cú pháp @
Cách bạn đã sử dụng công cụ trang trí trong phần trước có thể cảm thấy hơi rắc rối. Trước tiên, bạn phải gõ tên
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
00 ba lần để gọi và sử dụng trình trang trí. Ngoài ra, việc phân biệt nơi trang trí đang thực sự hoạt động trở nên khó khăn hơn. Vì vậy, Python cho phép bạn sử dụng trình trang trí với cú pháp đặc biệt >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
01. Bạn có thể áp dụng các công cụ trang trí của mình trong khi xác định các chức năng của mình, như thế này>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
8Đôi khi cú pháp trên được gọi là cú pháp chiếc bánh và nó chỉ là một cú pháp đường cho
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
02Trang trí các chức năng với các đối số
Trình trang trí ngây thơ mà chúng tôi đã triển khai ở trên sẽ chỉ hoạt động đối với các hàm không có đối số. Nó sẽ thất bại và tăng
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
03 nếu bạn cố trang trí một hàm có đối số với >>> 'Hello from the inner func'
37. Bây giờ, hãy tạo một trình trang trí khác có tên là >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
05 sẽ nhận một hàm trả về một giá trị chuỗi và chuyển đổi giá trị chuỗi đó thành chữ hoa>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
9Tạo hàm mục tiêu trả về giá trị chuỗi
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
00>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
01>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
02Hàm
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
06 lấy một tham số là >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
07 và trả về một thông báo dưới dạng chuỗi. Hãy xem cách trình trang trí >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
05 đang sửa đổi chuỗi trả về ban đầu, chuyển đổi chuỗi đó thành chữ hoa và thêm ký hiệu >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
09 bổ sung mà không thay đổi trực tiếp bất kỳ mã nào trong hàm >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
06Giải quyết khủng hoảng danh tính
Trong Python, bạn có thể xem xét bất kỳ đối tượng nào và các thuộc tính của nó thông qua trình bao tương tác. Một hàm biết danh tính của nó, chuỗi tài liệu, v.v. Chẳng hạn, bạn có thể kiểm tra hàm
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
11 tích hợp theo các cách sau>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
03>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
04>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
05>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
06>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
07>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
08>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
09>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
10Việc xem xét nội quan này hoạt động tương tự đối với các chức năng mà bạn đã tự xác định. Tôi sẽ sử dụng hàm
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
06 đã xác định trước đó>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
11>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
12>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
13>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
14Bây giờ những gì đang xảy ra ở đó. Trình trang trí
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
05 đã làm cho chức năng >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
06 bối rối về danh tính của chính nó. Thay vì báo cáo tên của chính nó, nó lấy danh tính của hàm bên trong >>> 'Hello from the inner func'
38. Điều này có thể gây nhầm lẫn trong khi gỡ lỗi. Bạn có thể sửa lỗi này bằng cách sử dụng trình trang trí >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
16 dựng sẵn từ mô-đun >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
17. Điều này sẽ đảm bảo rằng bản sắc ban đầu của chức năng được trang trí vẫn được bảo tồn>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
15>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
16>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
17Xem xét kỹ hàm
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
06 được trang trí bằng trình trang trí đã sửa đổi sẽ cho bạn kết quả mong muốn>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
11>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
19>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
13>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
31Trang trí trong tự nhiên
Trước khi chuyển sang phần tiếp theo, hãy xem một vài ví dụ thực tế về decorator. Để xác định tất cả các trình trang trí, chúng tôi sẽ sử dụng mẫu sau mà chúng tôi đã hoàn thiện cho đến nay
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
32hẹn giờ
Trình trang trí hẹn giờ sẽ giúp bạn định thời gian cho các cuộc gọi của mình theo cách không xâm phạm. Nó có thể giúp bạn trong khi gỡ lỗi và định hình các chức năng của bạn
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
33Theo cách trên, chúng ta có thể xem xét thời gian cần thiết để hàm
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
19 hoàn thành quá trình thực thi của nó>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
34>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
35Bộ ghi ngoại lệ
Cũng giống như trình trang trí
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
20, chúng ta có thể định nghĩa trình trang trí logger sẽ ghi lại trạng thái của một hàm có thể gọi được. Đối với phần trình diễn này, tôi sẽ xác định một trình ghi ngoại lệ sẽ hiển thị thông tin bổ sung như dấu thời gian, tên đối số khi một ngoại lệ xảy ra bên trong có thể gọi được trang trí>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
36Hãy gọi ZeroDivisionError để xem hoạt động của bộ ghi nhật ký
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
37>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
38Đầu tiên, trình trang trí in một vài thông tin liên quan đến chức năng và sau đó đưa ra lỗi ban đầu
Xác thực & Kiểm tra thời gian chạy
Hệ thống kiểu của Python được gõ mạnh nhưng rất năng động. Đối với tất cả các lợi ích của nó, điều này có nghĩa là một số lỗi có thể cố gắng len lỏi vào, mà các ngôn ngữ được nhập tĩnh hơn [như Java] sẽ bắt gặp tại thời điểm biên dịch. Nhìn xa hơn nữa, bạn có thể muốn thực thi các kiểm tra tùy chỉnh, phức tạp hơn đối với dữ liệu đi vào hoặc ra. Người trang trí có thể cho phép bạn dễ dàng xử lý tất cả những điều này và áp dụng nó cho nhiều chức năng cùng một lúc
Hãy tưởng tượng điều này. bạn có một tập hợp các hàm, mỗi hàm trả về một từ điển, từ điển này [trong số các trường khác] bao gồm một trường có tên là “tóm tắt. ” Giá trị của phần tóm tắt này không được dài quá 30 ký tự; . Đây là một công cụ trang trí làm tăng ValueError nếu điều đó xảy ra
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
39>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
40Thử lại
Hãy tưởng tượng một tình huống trong đó khả năng gọi được xác định của bạn không thành công do một số vấn đề liên quan đến I/O và bạn muốn thử lại lần nữa. Decorator có thể giúp bạn đạt được điều đó theo cách có thể tái sử dụng. Hãy xác định một trình trang trí
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
21 sẽ chạy lại chức năng được trang trí nhiều lần nếu xảy ra lỗi http>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
41>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
42Áp dụng nhiều trang trí
Bạn có thể áp dụng nhiều trình trang trí cho một chức năng bằng cách xếp chồng chúng lên nhau. Hãy xác định hai trình trang trí đơn giản và sử dụng cả hai trên một chức năng
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
43>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
44Các decorator được gọi theo thứ tự từ dưới lên. Đầu tiên, trình trang trí
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
22 được áp dụng trên kết quả của hàm >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
23 và sau đó kết quả của >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
22 được chuyển đến trình trang trí >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
25. Ngăn xếp trang trí ở trên có thể được viết là >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
26. Thay đổi thứ tự của các trang trí và xem điều gì sẽ xảy raTrang trí với Arguments
Trong khi xác định trình trang trí
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
21 trong phần trước, bạn có thể nhận thấy rằng tôi đã mã hóa cứng số lần tôi muốn chức năng thử lại nếu xảy ra lỗi. Sẽ rất hữu ích nếu bạn có thể đưa số lần thử làm tham số vào trình trang trí và làm cho nó hoạt động tương ứng. Đây không phải là một nhiệm vụ tầm thường và bạn sẽ cần ba cấp hàm lồng nhau để đạt được điều đóTrước khi làm điều đó, hãy tạo một ví dụ nhỏ về cách bạn có thể xác định các trình trang trí bằng các tham số
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
45>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
46Trình trang trí
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
28 nhận một tham số duy nhất có tên là >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
29. Nó chia đầu ra chuỗi của hàm được trang trí bằng một khoảng trắng và sau đó nối chúng bằng dấu phân cách do người dùng xác định được chỉ định trong đối số >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
29. Định nghĩa lồng nhau ba lớp trông có vẻ đáng sợ nhưng chúng ta sẽ làm được điều đó ngay lập tức. Lưu ý cách bạn có thể sử dụng trình trang trí với các tham số khác nhau. Trong ví dụ trên, tôi đã định nghĩa ba hàm khác nhau để chứng minh việc sử dụng >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
28. Điều quan trọng cần lưu ý là trong trường hợp trình trang trí nhận tham số, bạn sẽ luôn cần truyền một thứ gì đó cho nó và ngay cả khi bạn không muốn truyền bất kỳ tham số nào [chạy với mặc định], bạn vẫn cần phải trang trí . Hãy thử thay đổi decorator trên hàm >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
34 từ >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
35 thành >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
28 và xem điều gì sẽ xảy raThông thường, một trình trang trí tạo và trả về một hàm bao bọc bên trong nhưng ở đây trong trình trang trí
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
37, có một hàm bên trong bên trong một hàm bên trong khác. Điều này gần giống như một giấc mơ trong một giấc mơ từ bộ phim InceptionCó một vài điều tế nhị xảy ra trong hàm
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
35Xác định
39 là một hàm bên trong có nghĩa là>>> I was angry with my friend. >>> I told my wrath, my wrath did end
40 sẽ tham chiếu đến một đối tượng hàm>>> I was angry with my friend. >>> I told my wrath, my wrath did end
41>>> I was angry with my friend. >>> I told my wrath, my wrath did end
Đối số
29 dường như không được sử dụng trong chính>>> I was angry with my friend. >>> I told my wrath, my wrath did end
35. Nhưng bằng cách chuyển>>> I was angry with my friend. >>> I told my wrath, my wrath did end
29, một bao đóng được tạo trong đó giá trị của>>> I was angry with my friend. >>> I told my wrath, my wrath did end
29 được lưu trữ cho đến khi nó sẽ được sử dụng sau bởi>>> I was angry with my friend. >>> I told my wrath, my wrath did end
46>>> I was angry with my friend. >>> I told my wrath, my wrath did end
Trang trí có và không có đối số
Bạn đã thấy trước đó rằng một trình trang trí được thiết kế đặc biệt để lấy tham số không thể được sử dụng nếu không có tham số; . Nhưng nếu bạn muốn thiết kế một cái có thể sử dụng cả có và không có đối số thì sao?. Hãy xác định lại trình trang trí
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
28 để bạn có thể sử dụng nó với các tham số hoặc giống như một trình trang trí ít tham số thông thường mà chúng ta đã thấy trước đây>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
47>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
48Ở đây, đối số
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
49 đóng vai trò là điểm đánh dấu, cho biết liệu trình trang trí có được gọi với đối số hay khôngNếu
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
28 đã được gọi mà không có đối số, hàm được trang trí sẽ được chuyển vào dưới dạng >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
49. Nếu nó đã được gọi với các đối số, thì >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
49 sẽ là Không có. Dấu * trong danh sách đối số có nghĩa là các đối số còn lại không thể được gọi là đối số vị trí. Lần này bạn có thể sử dụng >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
28 có hoặc không có đối số và chức năng >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
06 và >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
22 ở trên chứng minh rằngMột mẫu chung
Cá nhân tôi thấy nó cồng kềnh khi bạn cần ba lớp hàm lồng nhau để xác định một trình trang trí tổng quát có thể được sử dụng có hoặc không có đối số. David Beazly trong cuốn sách Python Cookbook của anh ấy cho thấy một cách tuyệt vời để xác định các trình trang trí tổng quát mà không cần viết ba cấp hàm lồng nhau. Nó sử dụng hàm
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
56 tích hợp để đạt được điều đó. Sau đây là mẫu bạn có thể sử dụng để xác định các trình trang trí tổng quát theo cách thanh lịch hơn>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
49Hãy xác định lại trình trang trí
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
21 của chúng tôi bằng cách sử dụng mẫu này>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
50>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
51Trong trường hợp này, bạn không cần phải viết các hàm lồng ba cấp độ và
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
56 sẽ lo việc đó. Các phần có thể được sử dụng để tạo các hàm dẫn xuất mới có một số tham số đầu vào được gán trước. Khoảng >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
59 làm như sau>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
52Điều này giúp loại bỏ sự cần thiết phải viết nhiều lớp chức năng xuất xưởng lồng nhau, có được một trình trang trí tổng quát
Xác định Decorators với các lớp
Lần này, tôi sẽ sử dụng một class để soạn một decorator. Các lớp có thể hữu ích để tránh kiến trúc lồng nhau trong khi viết các bộ trang trí. Ngoài ra, có thể hữu ích khi sử dụng một lớp trong khi viết các trình trang trí trạng thái. Bạn có thể làm theo mẫu bên dưới để soạn các trang trí với các lớp
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
53Hãy sử dụng mẫu trên để viết một trình trang trí có tên là
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
60 sẽ thêm các thẻ in đậm >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
61 vào đầu ra chuỗi của một hàm>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
54>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
55Phương thức init[] lưu trữ một tham chiếu đến hàm num_calls và có thể thực hiện các khởi tạo cần thiết khác. Phương thức call[] sẽ được gọi thay vì hàm được trang trí. Về cơ bản, nó thực hiện giống như hàm
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
62 trong các ví dụ trước đây của chúng tôi. Lưu ý rằng bạn cần sử dụng hàm >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
63 thay vì >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
64Trước khi tiếp tục, hãy viết một trình trang trí trạng thái bằng cách sử dụng các lớp. Các nhà trang trí có trạng thái có thể nhớ trạng thái của lần chạy trước đó của họ. Đây là một công cụ trang trí có trạng thái có tên là
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
65 sẽ theo dõi số lần các chức năng được trang trí được gọi trong từ điển. Các khóa của từ điển sẽ chứa tên của các chức năng và các giá trị tương ứng sẽ chứa số lượng cuộc gọi>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
56>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
57Một vài ví dụ khác
Giá trị trả về bộ đệm
Trình trang trí có thể cung cấp một cách thanh lịch để ghi nhớ các giá trị trả về của hàm. Hãy tưởng tượng bạn có một API đắt tiền và bạn muốn gọi nó càng ít lần càng tốt. Ý tưởng là lưu và lưu vào bộ đệm các giá trị do API trả về cho các đối số cụ thể, để nếu các đối số đó xuất hiện lại, bạn có thể cung cấp kết quả từ bộ đệm thay vì gọi lại API. Điều này có thể cải thiện đáng kể hiệu suất của ứng dụng của bạn. Ở đây tôi đã mô phỏng một lệnh gọi API đắt tiền và cung cấp bộ nhớ đệm với một trình trang trí
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
58>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
59Bạn sẽ thấy rằng việc chạy chức năng này mất khoảng 3 giây. Để cache kết quả, chúng ta có thể sử dụng funcools tích hợp sẵn của Python. lru_cache để lưu kết quả đối với một đối số trong từ điển và phục vụ kết quả đó khi nó gặp lại đối số tương tự. Hạn chế duy nhất ở đây là, tất cả các đối số cần phải được băm
>>> 'Hello from the inner func'
0>>> 'Hello from the inner func'
1Bộ nhớ đệm ít sử dụng gần đây nhất [LRU] sắp xếp các mục theo thứ tự sử dụng, cho phép bạn nhanh chóng xác định mục nào không được sử dụng trong khoảng thời gian dài nhất. Trong trường hợp trên, tham số
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
66 đề cập đến số lượng phản hồi tối đa được lưu trước khi bắt đầu xóa những phản hồi sớm nhất. Trong khi bạn chạy chức năng trang trí, bạn sẽ thấy lần đầu tiên sẽ mất khoảng 3 giây để trả về kết quả. Nhưng nếu bạn chạy lại chức năng với cùng một tham số, nó sẽ lấy kết quả từ bộ đệm gần như ngay lập tứcchuyển đổi đơn vị
Trình trang trí sau chuyển đổi độ dài từ đơn vị SI sang nhiều đơn vị khác mà không làm ô nhiễm chức năng mục tiêu của bạn với logic chuyển đổi
>>> 'Hello from the inner func'
2Hãy sử dụng nó trên một hàm trả về diện tích hình chữ nhật
>>> 'Hello from the inner func'
3>>> 'Hello from the inner func'
4Sử dụng công cụ trang trí chuyển đổi trên hàm vùng cho biết cách nó in ra đơn vị chuyển đổi trước khi trả về kết quả mong muốn. Thử nghiệm với các đơn vị chuyển đổi khác và xem điều gì sẽ xảy ra
Đăng ký chức năng
Sau đây là một ví dụ về đăng ký chức năng logger trong khung Flask. Trình trang trí
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
67 không thực hiện bất kỳ thay đổi nào đối với chức năng >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
68 được trang trí. Thay vào đó, nó nhận chức năng và đăng ký nó trong một danh sách có tên là >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
69 mỗi khi nó được gọi>>> 'Hello from the inner func'
5Nếu bạn chạy máy chủ và nhấn vào url
>>> I was angry with my friend.
>>> I told my wrath, my wrath did end
70, nó sẽ chào đón bạn bằng một thông báo >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
71. Ngoài ra, bạn sẽ có thể thấy bản in >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
72 và >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
73 của yêu cầu http của mình trên thiết bị đầu cuối. Hơn nữa, nếu bạn kiểm tra >>> I was angry with my friend.
>>> I told my wrath, my wrath did end
69, bạn sẽ tìm thấy thiết bị ghi nhật ký đã đăng ký ở đó. Bạn sẽ tìm thấy nhiều cách sử dụng decorator thực tế hơn trong Flask frameworkNhận xét
Tất cả các đoạn mã trong blog đã được viết và thử nghiệm với python 3. 8 trên máy chạy Ubuntu 20. 04