Hướng dẫn what is decorator in python class? - decorator trong lớp python là gì?

Xem bây giờ hướng dẫn này có một khóa học video liên quan được tạo bởi nhóm Python thực sự. Xem nó cùng với hướng dẫn bằng văn bản để làm sâu sắc thêm sự hiểu biết của bạn: Người trang trí Python 101 This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Python Decorators 101

Show

Trong hướng dẫn này về các nhà trang trí, chúng tôi sẽ xem xét chúng là gì và cách tạo và sử dụng chúng. Các nhà trang trí cung cấp một cú pháp đơn giản để gọi các chức năng bậc cao.

Theo định nghĩa, một bộ trang trí là một hàm có một chức năng khác và mở rộng hành vi của hàm sau mà không sửa đổi rõ ràng nó.

Điều này nghe có vẻ khó hiểu, nhưng nó thực sự không, đặc biệt là sau khi bạn đã thấy một vài ví dụ về cách các nhà trang trí hoạt động. Bạn có thể tìm thấy tất cả các ví dụ từ bài viết này ở đây.

Updates:

  • 22/08/2018: Cập nhật chính thêm các ví dụ và trang trí nâng cao hơn
  • 01/12/2016: Cập nhật các ví dụ về cú pháp Python 3 (v3.5.1) và thêm một ví dụ mới
  • 11/01/2015: Đã thêm một lời giải thích ngắn gọn về người trang trí
    def my_decorator(func):
        def wrapper():
            print("Something is happening before the function is called.")
            func()
            print("Something is happening after the function is called.")
        return wrapper
    
    def say_whee():
        print("Whee!")
    
    say_whee = my_decorator(say_whee)
    
    6

Chức năng

Trước khi bạn có thể hiểu các nhà trang trí, trước tiên bạn phải hiểu cách thức hoạt động của các chức năng. Đối với mục đích của chúng tôi, một hàm trả về một giá trị dựa trên các đối số đã cho. Đây là một ví dụ rất đơn giản:a function returns a value based on the given arguments. Here is a very simple example:

>>>

>>> def add_one(number):
...     return number + 1

>>> add_one(2)
3

Nói chung, các chức năng trong Python cũng có thể có tác dụng phụ thay vì chỉ biến đầu vào thành đầu ra. Hàm

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
7 là một ví dụ cơ bản về điều này: nó trả về
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
8 trong khi có tác dụng phụ của việc xuất ra thứ gì đó vào bảng điều khiển. Tuy nhiên, để hiểu các nhà trang trí, nó đủ để suy nghĩ về các chức năng như một cái gì đó biến các lập luận được đưa ra thành một giá trị.

Đối tượng hạng nhất

Trong Python, các chức năng là các đối tượng hạng nhất. Điều này có nghĩa là các chức năng 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.). Xem xét ba chức năng sau:functions can be passed around and used as arguments, just like any other object (string, int, float, list, and so on). Consider the following three functions:

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")

Ở đây,

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
9 và
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
00 là các chức năng thường xuyên mong đợi một tên được đặt dưới dạng chuỗi. Tuy nhiên, hàm
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
01 mong đợi một chức năng như đối số của nó. Ví dụ, chúng ta có thể chuyển nó cho chức năng
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
9 hoặc
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
00:

>>>

Nói chung, các chức năng trong Python cũng có thể có tác dụng phụ thay vì chỉ biến đầu vào thành đầu ra. Hàm
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
7 là một ví dụ cơ bản về điều này: nó trả về
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
8 trong khi có tác dụng phụ của việc xuất ra thứ gì đó vào bảng điều khiển. Tuy nhiên, để hiểu các nhà trang trí, nó đủ để suy nghĩ về các chức năng như một cái gì đó biến các lập luận được đưa ra thành một giá trị.

Đối tượng hạng nhất

Trong Python, các chức năng là các đối tượng hạng nhất. Điều này có nghĩa là các chức năng 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.). Xem xét ba chức năng sau:

Ở đây,

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
9 và
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
00 là các chức năng thường xuyên mong đợi một tên được đặt dưới dạng chuỗi. Tuy nhiên, hàm
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
01 mong đợi một chức năng như đối số của nó. Ví dụ, chúng ta có thể chuyển nó cho chức năng
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
9 hoặc
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
00:

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'

>>>

>>> parent()
Printing from the parent() function
Printing from the second_child() function
Printing from the first_child() function

Nói chung, các chức năng trong Python cũng có thể có tác dụng phụ thay vì chỉ biến đầu vào thành đầu ra. Hàm

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
7 là một ví dụ cơ bản về điều này: nó trả về
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
8 trong khi có tác dụng phụ của việc xuất ra thứ gì đó vào bảng điều khiển. Tuy nhiên, để hiểu các nhà trang trí, nó đủ để suy nghĩ về các chức năng như một cái gì đó biến các lập luận được đưa ra thành một giá trị.

Đối tượng hạng nhất

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined

Trong Python, các chức năng là các đối tượng hạng nhất. Điều này có nghĩa là các chức năng 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.). Xem xét ba chức năng sau:

Ở đây, def my_decorator(func): def wrapper(): print("Something is happening before the function is called.") func() print("Something is happening after the function is called.") return wrapper def say_whee(): print("Whee!") say_whee = my_decorator(say_whee) 9 và def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 00 là các chức năng thường xuyên mong đợi một tên được đặt dưới dạng chuỗi. Tuy nhiên, hàm def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 01 mong đợi một chức năng như đối số của nó. Ví dụ, chúng ta có thể chuyển nó cho chức năng def my_decorator(func): def wrapper(): print("Something is happening before the function is called.") func() print("Something is happening after the function is called.") return wrapper def say_whee(): print("Whee!") say_whee = my_decorator(say_whee) 9 hoặc def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 00:

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'

def parent(num):
    def first_child():
        return "Hi, I am Emma"

    def second_child():
        return "Call me Liam"

    if num == 1:
        return first_child
    else:
        return second_child

Lưu ý rằng

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
04 đề cập đến hai chức năng, nhưng theo những cách khác nhau:
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
01 và
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
06. Hàm
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
06 được đặt tên mà không có dấu ngoặc đơn. Điều này có nghĩa là chỉ có một tham chiếu đến hàm được thông qua. Hàm không được thực thi. Hàm
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
01, mặt khác, được viết bằng dấu ngoặc đơn, vì vậy nó sẽ được gọi như bình thường.returning a reference to the function
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
18
. In contrast
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
12 with parentheses refers to the result of evaluating the function. This can be seen in the following example:

>>>

>>> first = parent(1)
>>> second = parent(2)

>>> first
.first_child at 0x7f599f1e2e18>

>>> second
.second_child at 0x7f599dad5268>

Nói chung, các chức năng trong Python cũng có thể có tác dụng phụ thay vì chỉ biến đầu vào thành đầu ra. Hàm

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
7 là một ví dụ cơ bản về điều này: nó trả về
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
8 trong khi có tác dụng phụ của việc xuất ra thứ gì đó vào bảng điều khiển. Tuy nhiên, để hiểu các nhà trang trí, nó đủ để suy nghĩ về các chức năng như một cái gì đó biến các lập luận được đưa ra thành một giá trị.

Đối tượng hạng nhất

>>>

>>> first()
'Hi, I am Emma'

>>> second()
'Call me Liam'

Nói chung, các chức năng trong Python cũng có thể có tác dụng phụ thay vì chỉ biến đầu vào thành đầu ra. Hàm

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
7 là một ví dụ cơ bản về điều này: nó trả về
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
8 trong khi có tác dụng phụ của việc xuất ra thứ gì đó vào bảng điều khiển. Tuy nhiên, để hiểu các nhà trang trí, nó đủ để suy nghĩ về các chức năng như một cái gì đó biến các lập luận được đưa ra thành một giá trị.

Đối tượng hạng nhất

Trong Python, các chức năng là các đối tượng hạng nhất. Điều này có nghĩa là các chức năng 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.). Xem xét ba chức năng sau:

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)

Bạn có thể đoán điều gì xảy ra khi bạn gọi

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
30 không? Thử nó:

>>>

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
0

Để hiểu những gì diễn ra ở đây, hãy nhìn lại các ví dụ trước. Chúng tôi thực sự chỉ áp dụng mọi thứ bạn đã học cho đến nay.

Cái gọi là trang trí xảy ra ở dòng sau:

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
1

Trong thực tế, tên

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
31 hiện chỉ vào hàm bên trong
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
32. Hãy nhớ rằng bạn trả về
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
33 như một hàm khi bạn gọi
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
34:

>>>

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
2

Để hiểu những gì diễn ra ở đây, hãy nhìn lại các ví dụ trước. Chúng tôi thực sự chỉ áp dụng mọi thứ bạn đã học cho đến nay.

Cái gọi là trang trí xảy ra ở dòng sau:decorators wrap a function, modifying its behavior.

Trong thực tế, tên

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
31 hiện chỉ vào hàm bên trong
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
32. Hãy nhớ rằng bạn trả về
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
33 như một hàm khi bạn gọi
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
34:

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
3

Tuy nhiên,

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
32 có tham chiếu đến
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
30 gốc là
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
37 và các cuộc gọi chức năng đó giữa hai cuộc gọi đến
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
7.

Đặt đơn giản: Người trang trí bọc một chức năng, sửa đổi hành vi của nó.

Trước khi tiếp tục, hãy để một cái nhìn vào một ví dụ thứ hai. Bởi vì

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
32 là một hàm Python thông thường, cách một người trang trí sửa đổi một hàm có thể thay đổi một cách linh hoạt. Vì vậy, để không làm phiền hàng xóm của bạn, ví dụ sau đây sẽ chỉ chạy mã được trang trí trong ngày:

Nếu bạn cố gắng gọi

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
30 sau giờ đi ngủ, sẽ không có gì xảy ra:use decorators in a simpler way with the
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
43 symbol
, sometimes called the “pie” syntax. The following example does the exact same thing as the first decorator example:

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
4

Cú pháp đặc biệt!

Cách bạn trang trí def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 30 ở trên là một chút cồng kềnh. Trước hết, cuối cùng bạn gõ tên def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 31 ba lần. Ngoài ra, trang trí bị ẩn một chút bên dưới định nghĩa của hàm.

Thay vào đó, Python cho phép bạn sử dụng các bộ trang trí theo cách đơn giản hơn với biểu tượng

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
43, đôi khi được gọi là cú pháp của Pie Pie. Ví dụ sau đây thực hiện chính xác điều tương tự như ví dụ trang trí đầu tiên:

Vì vậy,

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
44 chỉ là một cách nói dễ dàng hơn
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
45. Nó cách bạn áp dụng một người trang trí vào một chức năng.

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
5

Tái sử dụng trang trí

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
6

Hãy nhớ lại rằng một người trang trí chỉ là một chức năng Python thông thường. Tất cả các công cụ thông thường để tái sử dụng dễ dàng có sẵn. Hãy để di chuyển bộ trang trí đến mô -đun riêng có thể được sử dụng trong nhiều chức năng khác.

>>>

Tạo một tệp được gọi là
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
46 với nội dung sau:

Bây giờ bạn có thể sử dụng trình trang trí mới này trong các tệp khác bằng cách nhập thông thường:

Khi bạn chạy ví dụ này, bạn sẽ thấy rằng

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
30 ban đầu được thực thi hai lần:

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
8

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
7

>>>

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
9

Chức năng trang trí với các đối số

Nói rằng bạn có một chức năng chấp nhận một số đối số. Bạn vẫn có thể trang trí nó? Hãy thử thử:

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
0

Thật không may, việc chạy mã này sẽ gây ra lỗi:

>>>

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
1

Vấn đề là hàm bên trong def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 48 không có bất kỳ đối số nào, nhưng def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 49 đã được truyền cho nó. Bạn có thể khắc phục điều này bằng cách để def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 48 chấp nhận một đối số, nhưng sau đó nó sẽ không hoạt động cho hàm def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 30 mà bạn đã tạo trước đó.

Giải pháp là sử dụng

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
52 và
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
53 trong hàm trình bao bọc bên trong. Sau đó, nó sẽ chấp nhận một số lượng tùy ý của các đối số vị trí và từ khóa. Viết lại
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
46 như sau:

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
2

Hàm bên trong

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
48 hiện chấp nhận bất kỳ số lượng đối số nào và truyền chúng vào chức năng mà nó trang trí. Bây giờ cả ví dụ
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
30 và
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
57 của bạn đều hoạt động:

>>>

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
3

Trả lại các giá trị từ các chức năng được trang trí

Điều gì xảy ra với giá trị trả lại của các chức năng được trang trí? Chà, đó là cách trang trí để quyết định. Hãy nói rằng bạn trang trí một chức năng đơn giản như sau:

Cố gắng sử dụng nó:make sure the wrapper function returns the return value of the decorated function. Change your

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
46 file:

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
4

Rất tiếc, người trang trí của bạn đã ăn giá trị trả lại từ hàm.

>>>

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
5

Bởi vì def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 58 không trả lại một cách rõ ràng một giá trị, cuộc gọi def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 59 đã kết thúc trở lại def my_decorator(func): def wrapper(): print("Something is happening before the function is called.") func() print("Something is happening after the function is called.") return wrapper def say_whee(): print("Whee!") say_whee = my_decorator(say_whee) 8.

Để khắc phục điều này, bạn cần đảm bảo hàm trình bao bọc trả về giá trị trả về của hàm được trang trí. Thay đổi tệp

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
46 của bạn:

>>>

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
6

Giá trị trả về từ lần thực hiện cuối cùng của hàm được trả về:

>>>

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
7

Bạn là ai, thực sự?

Một sự tiện lợi tuyệt vời khi làm việc với Python, đặc biệt là trong vỏ tương tác, là khả năng nội tâm mạnh mẽ của nó. Hướng nội là khả năng của một đối tượng để biết về các thuộc tính của chính nó trong thời gian chạy. Chẳng hạn, một hàm biết tên và tài liệu của chính nó:

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
8

Sự hướng nội cũng hoạt động cho các chức năng mà bạn cũng tự xác định:

>>>

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
9

Tuy nhiên, sau khi được trang trí,

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
30 đã rất bối rối về bản sắc của nó. Bây giờ nó báo cáo là hàm bên trong
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
48 bên trong trình trang trí
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
64. Mặc dù về mặt kỹ thuật, điều này không phải là thông tin hữu ích lắm.

Để khắc phục điều này, các nhà trang trí nên sử dụng bộ trang trí def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 65, sẽ lưu giữ thông tin về chức năng ban đầu. Cập nhật def say_hello(name): return f"Hello {name}" def be_awesome(name): return f"Yo {name}, together we are the awesomest!" def greet_bob(greeter_func): return greeter_func("Bob") 46 một lần nữa:

Bạn không cần phải thay đổi bất cứ điều gì về chức năng

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
30 được trang trí:

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
0

Công thức này là một mẫu nồi hơi tốt để xây dựng các nhà trang trí phức tạp hơn.

Chức năng thời gian

Hãy bắt đầu bằng cách tạo ra một nhà trang trí

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
69. Nó sẽ đo thời gian một hàm cần thực hiện và in thời lượng vào bảng điều khiển. Đây là mã:

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
1

Bộ trang trí này hoạt động bằng cách lưu trữ thời gian ngay trước khi hàm bắt đầu chạy (tại dòng được đánh dấu

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
70) và ngay sau khi chức năng kết thúc (tại
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
71). Thời gian hàm mất sau đó là sự khác biệt giữa hai (tại
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
72). Chúng tôi sử dụng hàm
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
73, công việc tốt là đo khoảng thời gian. Dưới đây là một số ví dụ về thời gian:

>>>

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
2

Tự mình điều hành. Làm việc thông qua dòng mã từng dòng. Hãy chắc chắn rằng bạn hiểu cách nó hoạt động. Mặc dù vậy, đừng lo lắng nếu bạn không nhận được nó. Trang trí là những sinh vật tiên tiến. Cố gắng ngủ trên nó hoặc tạo ra một bản vẽ của dòng chảy.

Mã gỡ lỗi

Trình trang trí

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
74 sau đây sẽ in các đối số Một hàm được gọi cũng như giá trị trả về của nó mỗi khi hàm được gọi:

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
3

Chữ ký được tạo bằng cách tham gia các biểu diễn chuỗi của tất cả các đối số. Các số trong danh sách sau đây tương ứng với các nhận xét được đánh số trong mã:

  1. Tạo một danh sách các đối số vị trí. Sử dụng
    def say_hello(name):
        return f"Hello {name}"
    
    def be_awesome(name):
        return f"Yo {name}, together we are the awesomest!"
    
    def greet_bob(greeter_func):
        return greeter_func("Bob")
    
    75 để có được một chuỗi đẹp đại diện cho mỗi đối số.
  2. Tạo một danh sách các đối số từ khóa. Các định dạng chuỗi F mỗi đối số là
    def say_hello(name):
        return f"Hello {name}"
    
    def be_awesome(name):
        return f"Yo {name}, together we are the awesomest!"
    
    def greet_bob(greeter_func):
        return greeter_func("Bob")
    
    76 trong đó trình xác định
    def say_hello(name):
        return f"Hello {name}"
    
    def be_awesome(name):
        return f"Yo {name}, together we are the awesomest!"
    
    def greet_bob(greeter_func):
        return greeter_func("Bob")
    
    77 có nghĩa là
    def say_hello(name):
        return f"Hello {name}"
    
    def be_awesome(name):
        return f"Yo {name}, together we are the awesomest!"
    
    def greet_bob(greeter_func):
        return greeter_func("Bob")
    
    75 được sử dụng để biểu thị giá trị.
  3. Danh sách các đối số từ khóa và vị trí được nối với nhau với một chuỗi chữ ký với mỗi đối số được phân tách bằng dấu phẩy.
  4. Giá trị trả về được in sau khi hàm được thực thi.

Hãy cùng xem cách thức trang trí hoạt động trong thực tế bằng cách áp dụng nó vào một chức năng đơn giản với một vị trí và một đối số từ khóa:

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
4

Lưu ý cách trình trang trí

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
74 in chữ ký và giá trị trả về của hàm
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
80:

>>>

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
5

Tự mình điều hành. Làm việc thông qua dòng mã từng dòng. Hãy chắc chắn rằng bạn hiểu cách nó hoạt động. Mặc dù vậy, đừng lo lắng nếu bạn không nhận được nó. Trang trí là những sinh vật tiên tiến. Cố gắng ngủ trên nó hoặc tạo ra một bản vẽ của dòng chảy.

Mã gỡ lỗi

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
6

Trình trang trí

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
74 sau đây sẽ in các đối số Một hàm được gọi cũng như giá trị trả về của nó mỗi khi hàm được gọi:

Hướng dẫn what is decorator in python class? - decorator trong lớp python là gì?

Chữ ký được tạo bằng cách tham gia các biểu diễn chuỗi của tất cả các đối số. Các số trong danh sách sau đây tương ứng với các nhận xét được đánh số trong mã:

>>>

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
7

Tự mình điều hành. Làm việc thông qua dòng mã từng dòng. Hãy chắc chắn rằng bạn hiểu cách nó hoạt động. Mặc dù vậy, đừng lo lắng nếu bạn không nhận được nó. Trang trí là những sinh vật tiên tiến. Cố gắng ngủ trên nó hoặc tạo ra một bản vẽ của dòng chảy.

Mã gỡ lỗi

Trình trang trí

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
74 sau đây sẽ in các đối số Một hàm được gọi cũng như giá trị trả về của nó mỗi khi hàm được gọi:

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
8

Chữ ký được tạo bằng cách tham gia các biểu diễn chuỗi của tất cả các đối số. Các số trong danh sách sau đây tương ứng với các nhận xét được đánh số trong mã:

>>>

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
9

Tự mình điều hành. Làm việc thông qua dòng mã từng dòng. Hãy chắc chắn rằng bạn hiểu cách nó hoạt động. Mặc dù vậy, đừng lo lắng nếu bạn không nhận được nó. Trang trí là những sinh vật tiên tiến. Cố gắng ngủ trên nó hoặc tạo ra một bản vẽ của dòng chảy.

Mã gỡ lỗi

Trình trang trí

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
74 sau đây sẽ in các đối số Một hàm được gọi cũng như giá trị trả về của nó mỗi khi hàm được gọi:

>>> parent()
Printing from the parent() function
Printing from the second_child() function
Printing from the first_child() function
0

Chữ ký được tạo bằng cách tham gia các biểu diễn chuỗi của tất cả các đối số. Các số trong danh sách sau đây tương ứng với các nhận xét được đánh số trong mã:

Tạo một danh sách các đối số vị trí. Sử dụng

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
75 để có được một chuỗi đẹp đại diện cho mỗi đối số.

>>>

>>> parent()
Printing from the parent() function
Printing from the second_child() function
Printing from the first_child() function
1

Tự mình điều hành. Làm việc thông qua dòng mã từng dòng. Hãy chắc chắn rằng bạn hiểu cách nó hoạt động. Mặc dù vậy, đừng lo lắng nếu bạn không nhận được nó. Trang trí là những sinh vật tiên tiến. Cố gắng ngủ trên nó hoặc tạo ra một bản vẽ của dòng chảy.

Mã gỡ lỗi

>>>

>>> parent()
Printing from the parent() function
Printing from the second_child() function
Printing from the first_child() function
2

Tự mình điều hành. Làm việc thông qua dòng mã từng dòng. Hãy chắc chắn rằng bạn hiểu cách nó hoạt động. Mặc dù vậy, đừng lo lắng nếu bạn không nhận được nó. Trang trí là những sinh vật tiên tiến. Cố gắng ngủ trên nó hoặc tạo ra một bản vẽ của dòng chảy.

Người dùng đã đăng nhập?

Ví dụ cuối cùng trước khi chuyển sang một số nhà trang trí fancier thường được sử dụng khi làm việc với khung web. Trong ví dụ này, chúng tôi đang sử dụng bình để thiết lập trang web

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
97 chỉ hiển thị cho người dùng đã đăng nhập hoặc xác thực khác:

>>> parent()
Printing from the parent() function
Printing from the second_child() function
Printing from the first_child() function
3

Mặc dù điều này đưa ra một ý tưởng về cách thêm xác thực vào khung web của bạn, nhưng bạn thường không nên tự viết các loại trang trí này. Đối với Flask, bạn có thể sử dụng tiện ích mở rộng Flask-Login, bổ sung thêm bảo mật và chức năng.

Trang trí lạ mắt

Cho đến nay, bạn đã thấy cách tạo ra các nhà trang trí đơn giản. Bạn đã có một sự hiểu biết khá tốt về những người trang trí là gì và cách họ làm việc. Hãy nghỉ ngơi từ bài viết này để thực hành mọi thứ bạn đã học được.

Trong phần thứ hai của hướng dẫn này, chúng tôi sẽ khám phá các tính năng nâng cao hơn, bao gồm cả cách sử dụng như sau:

  • Trang trí trên các lớp học
  • Một số người trang trí trên một chức năng
  • Trang trí với lập luận
  • Người trang trí có thể tùy chọn lấy các đối số
  • Trang trí trạng thái
  • Các lớp học như người trang trí

Lớp trang trí

Có hai cách khác nhau bạn có thể sử dụng trang trí trên các lớp học. Cái đầu tiên rất gần với những gì bạn đã thực hiện với các chức năng: bạn có thể trang trí các phương pháp của một lớp. Đây là một trong những động lực để giới thiệu các nhà trang trí trở lại trong ngày.decorate the methods of a class. This was one of the motivations for introducing decorators back in the day.

Một số nhà trang trí thường được sử dụng thậm chí còn được xây dựng trong Python là

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
98,
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
99 và
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
00. Các nhà trang trí
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
98 và
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
99 được sử dụng để xác định các phương thức bên trong một không gian tên lớp không được kết nối với một trường hợp cụ thể của lớp đó. Bộ trang trí
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
00 được sử dụng để tùy chỉnh getters và setters cho các thuộc tính lớp. Mở rộng hộp dưới đây cho một ví dụ sử dụng các trang trí này.

Định nghĩa sau đây của lớp

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
04 sử dụng các nhà trang trí
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
98,
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
99 và
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
00:

>>> parent()
Printing from the parent() function
Printing from the second_child() function
Printing from the first_child() function
4

Trong lớp học này:

  • >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    08 là một phương pháp thông thường.
  • >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    09 là một thuộc tính có thể thay đổi: Nó có thể được đặt thành một giá trị khác. Tuy nhiên, bằng cách xác định phương thức setter, chúng tôi có thể thực hiện một số thử nghiệm lỗi để đảm bảo rằng nó không được đặt thành số âm vô nghĩa. Thuộc tính được truy cập dưới dạng thuộc tính không có dấu ngoặc đơn.
  • >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    10 là một thuộc tính bất biến: các thuộc tính không có phương thức
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    11 có thể được thay đổi. Mặc dù nó được định nghĩa là một phương thức, nó có thể được truy xuất như một thuộc tính mà không có dấu ngoặc đơn.
  • >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    12 là một phương pháp lớp. Nó không bị ràng buộc với một trường hợp cụ thể của
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    04. Các phương thức lớp thường được sử dụng làm phương thức nhà máy có thể tạo ra các trường hợp cụ thể của lớp.
  • >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    14 là một phương pháp tĩnh. Nó không thực sự phụ thuộc vào lớp
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    04, ngoại trừ nó là một phần của không gian tên của nó. Các phương thức tĩnh có thể được gọi trên một thể hiện hoặc lớp.

Ví dụ, lớp

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
04 có thể được sử dụng như sau:

>>>

>>> parent()
Printing from the parent() function
Printing from the second_child() function
Printing from the first_child() function
5

Hãy để xác định một lớp trong đó chúng tôi trang trí một số phương pháp của nó bằng cách sử dụng các nhà trang trí

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
74 và
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
69 từ trước đó:

>>> parent()
Printing from the parent() function
Printing from the second_child() function
Printing from the first_child() function
6

Sử dụng lớp này, bạn có thể thấy hiệu ứng của các nhà trang trí:

>>>

>>> parent()
Printing from the parent() function
Printing from the second_child() function
Printing from the first_child() function
7

Hãy để xác định một lớp trong đó chúng tôi trang trí một số phương pháp của nó bằng cách sử dụng các nhà trang trí

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
74 và
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
69 từ trước đó:decorate the whole class. This is, for example, done in the new
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
19 module in Python 3.7:

>>> parent()
Printing from the parent() function
Printing from the second_child() function
Printing from the first_child() function
8

Sử dụng lớp này, bạn có thể thấy hiệu ứng của các nhà trang trí:

Cách khác để sử dụng các nhà trang trí trên các lớp học là trang trí cho cả lớp. Đây là, ví dụ, được thực hiện trong mô -đun

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
19 mới trong Python 3.7:

Ý nghĩa của cú pháp tương tự như các bộ trang trí chức năng. Trong ví dụ trên, bạn có thể đã thực hiện trang trí bằng cách viết

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
20.

>>> parent()
Printing from the parent() function
Printing from the second_child() function
Printing from the first_child() function
9

Một cách sử dụng phổ biến của các nhà trang trí lớp là là một sự thay thế đơn giản hơn cho một số trường hợp sử dụng của các metaclass. Trong cả hai trường hợp, bạn đang thay đổi định nghĩa của một lớp một cách linh hoạt.

Viết một người trang trí lớp học rất giống với việc viết một bộ trang trí chức năng. Sự khác biệt duy nhất là người trang trí sẽ nhận được một lớp và không phải là một chức năng như một đối số. Trong thực tế, tất cả các nhà trang trí bạn thấy ở trên sẽ hoạt động như những người trang trí lớp học. Khi bạn đang sử dụng chúng trên một lớp thay vì một hàm, hiệu ứng của chúng có thể không phải là thứ bạn muốn. Trong ví dụ sau, bộ trang trí

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
69 được áp dụng cho một lớp:

>>>

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined
0

Hãy để xác định một lớp trong đó chúng tôi trang trí một số phương pháp của nó bằng cách sử dụng các nhà trang trí

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
74 và
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
69 từ trước đó:

Sử dụng lớp này, bạn có thể thấy hiệu ứng của các nhà trang trí:

Cách khác để sử dụng các nhà trang trí trên các lớp học là trang trí cho cả lớp. Đây là, ví dụ, được thực hiện trong mô -đun

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
19 mới trong Python 3.7:apply several decorators to a function by stacking them on top of each other:

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined
1

Ý nghĩa của cú pháp tương tự như các bộ trang trí chức năng. Trong ví dụ trên, bạn có thể đã thực hiện trang trí bằng cách viết

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
20.

>>>

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined
2

Quan sát sự khác biệt nếu chúng ta thay đổi thứ tự

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
74 và
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
27:

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined
3

Trong trường hợp này,

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
27 cũng sẽ được áp dụng cho
def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
74:

>>>

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined
4

Trang trí với lập luận

Đôi khi, nó rất hữu ích để chuyển các đối số cho các nhà trang trí của bạn. Ví dụ,

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
27 có thể được mở rộng cho một công cụ trang trí
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
35. Số lần để thực hiện hàm được trang trí sau đó có thể được đưa ra như một đối số.pass arguments to your decorators. For instance,
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
27 could be extended to a
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
35 decorator. The number of times to execute the decorated function could then be given as an argument.

Điều này sẽ cho phép bạn làm một cái gì đó như thế này:

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined
5

>>>

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined
6

Hãy suy nghĩ về cách bạn có thể đạt được điều này.

Cho đến nay, tên được viết sau

def say_hello(name):
    return f"Hello {name}"

def be_awesome(name):
    return f"Yo {name}, together we are the awesomest!"

def greet_bob(greeter_func):
    return greeter_func("Bob")
43 đã đề cập đến một đối tượng hàm có thể được gọi với một hàm khác. Để nhất quán, sau đó bạn cần
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
37 để trả về một đối tượng chức năng có thể hoạt động như một người trang trí. May mắn thay, bạn đã biết cách trả lại các chức năng! Nói chung, bạn muốn một cái gì đó như sau:

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined
7

Thông thường, bộ trang trí tạo và trả về hàm trình bao bọc bên trong, vì vậy viết ví dụ đầy đủ sẽ cung cấp cho bạn một hàm bên trong trong một hàm bên trong. Mặc dù điều này nghe có vẻ giống như chương trình tương đương với bộ phim Inception, nhưng chúng tôi sẽ gỡ rối tất cả trong một khoảnh khắc:

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined
8

Trông có vẻ hơi lộn xộn, nhưng chúng tôi chỉ đặt cùng một mẫu trang trí mà bạn đã thấy nhiều lần bây giờ trong một

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
38 bổ sung xử lý các đối số cho người trang trí. Hãy bắt đầu với chức năng trong cùng:

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined
9

Hàm

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
39 này có các đối số tùy ý và trả về giá trị của hàm được trang trí,
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
40. Hàm trình bao bọc này cũng chứa vòng lặp gọi hàm được trang trí
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
41 lần. Điều này không khác với các hàm trình bao bọc trước đó mà bạn đã thấy, ngoại trừ việc nó đang sử dụng tham số
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
41 phải được cung cấp từ bên ngoài.

Một bước ra, bạn sẽ tìm thấy chức năng trang trí:

def parent(num):
    def first_child():
        return "Hi, I am Emma"

    def second_child():
        return "Call me Liam"

    if num == 1:
        return first_child
    else:
        return second_child
0

Một lần nữa,

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
43 trông giống hệt như các chức năng trang trí mà bạn đã viết trước đó, ngoại trừ việc nó có tên khác nhau. Điều đó bởi vì chúng tôi bảo lưu tên cơ sở.

Như bạn đã thấy, hàm ngoài cùng trả về một tham chiếu đến hàm trang trí:

def parent(num):
    def first_child():
        return "Hi, I am Emma"

    def second_child():
        return "Call me Liam"

    if num == 1:
        return first_child
    else:
        return second_child
1

Có một vài điều tinh tế xảy ra trong hàm

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
44:

  • Xác định
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    43 là một hàm bên trong có nghĩa là
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    44 sẽ đề cập đến một đối tượng hàm. Trước đó, chúng tôi đã sử dụng
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    49 mà không có dấu ngoặc đơn để chỉ đối tượng chức năng. Các dấu ngoặc đơn được thêm vào là cần thiết khi xác định các nhà trang trí có lập luận.
  • Đối số
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    41 dường như không được sử dụng trong chính
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    44. Nhưng bằng cách vượt qua
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    41, một đóng cửa được tạo ra trong đó giá trị của
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    41 được lưu trữ cho đến khi nó được sử dụng sau đó bởi
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    39.

Với mọi thứ được thiết lập, hãy để xem kết quả có phải là dự kiến ​​không:

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined
5

>>>

Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'first_child' is not defined
6

Chỉ là kết quả chúng tôi đã nhắm đến.

Cả hai làm ơn, nhưng đừng bận tâm đến bánh mì

Với một chút quan tâm, bạn cũng có thể xác định các nhà trang trí có thể được sử dụng cả có và không có tranh luận. Nhiều khả năng, bạn không cần điều này, nhưng thật tuyệt khi có sự linh hoạt.decorators that can be used both with and without arguments. Most likely, you don’t need this, but it is nice to have the flexibility.

Như bạn đã thấy trong phần trước, khi một người trang trí sử dụng các đối số, bạn cần thêm một hàm bên ngoài. Thách thức là mã của bạn để tìm ra nếu người trang trí đã được gọi có hoặc không có tranh luận.

Vì chức năng trang trí chỉ được truyền trực tiếp nếu người trang trí được gọi mà không có đối số, chức năng phải là một đối số tùy chọn. Điều này có nghĩa là tất cả các đối số trang trí phải được chỉ định bằng từ khóa. Bạn có thể thực thi điều này với cú pháp

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
55 đặc biệt, điều đó có nghĩa là tất cả các tham số sau đây chỉ dành cho từ khóa:

def parent(num):
    def first_child():
        return "Hi, I am Emma"

    def second_child():
        return "Call me Liam"

    if num == 1:
        return first_child
    else:
        return second_child
4

Ở đây, lập luận

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
56 hoạt động như một điểm đánh dấu, lưu ý liệu người trang trí có được gọi với các đối số hay không:

  1. Nếu
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    57 đã được gọi mà không có tranh luận, hàm được trang trí sẽ được truyền dưới dạng
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    56. Nếu nó đã được gọi với các đối số, thì
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    56 sẽ là
    def my_decorator(func):
        def wrapper():
            print("Something is happening before the function is called.")
            func()
            print("Something is happening after the function is called.")
        return wrapper
    
    def say_whee():
        print("Whee!")
    
    say_whee = my_decorator(say_whee)
    
    8 và một số đối số từ khóa có thể đã được thay đổi từ các giá trị mặc định của chúng.
    >>> greet_bob(say_hello)
    'Hello Bob'
    
    >>> greet_bob(be_awesome)
    'Yo Bob, together we are the awesomest!'
    
    55 trong danh sách đối số có nghĩa là các đối số còn lại có thể được gọi là đối số vị trí.
  2. Trong trường hợp này, người trang trí đã được gọi với các lập luận. Trả về một chức năng trang trí có thể đọc và trả lại một chức năng.
  3. Trong trường hợp này, người trang trí được gọi mà không có tranh luận. Áp dụng các chất trang trí cho chức năng ngay lập tức.

Sử dụng bảng hơi này trên trình trang trí

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
62 trong phần trước, bạn có thể viết như sau:

def parent(num):
    def first_child():
        return "Hi, I am Emma"

    def second_child():
        return "Call me Liam"

    if num == 1:
        return first_child
    else:
        return second_child
5

So sánh điều này với

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
62 ban đầu. Các thay đổi duy nhất là tham số
>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
56 được thêm vào và ________ 265 -____ ____ 266 ở cuối.

Công thức 9.6 của cuốn sách nấu ăn Python tuyệt vời cho thấy một giải pháp thay thế sử dụng

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
67.

Các ví dụ này cho thấy

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
62 hiện có thể được sử dụng có hoặc không có đối số:

def parent(num):
    def first_child():
        return "Hi, I am Emma"

    def second_child():
        return "Call me Liam"

    if num == 1:
        return first_child
    else:
        return second_child
6

Hãy nhớ lại rằng giá trị mặc định của

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
41 là 2:

>>>

def parent(num):
    def first_child():
        return "Hi, I am Emma"

    def second_child():
        return "Call me Liam"

    if num == 1:
        return first_child
    else:
        return second_child
7

Trang trí trạng thái

Đôi khi, nó rất hữu ích để có một người trang trí có thể theo dõi trạng thái. Ví dụ đơn giản, chúng tôi sẽ tạo một bộ trang trí đếm số lần một hàm được gọi là.a decorator that can keep track of state. As a simple example, we will create a decorator that counts the number of times a function is called.

Trong phần tiếp theo, bạn sẽ thấy cách sử dụng các lớp để giữ trạng thái. Nhưng trong các trường hợp đơn giản, bạn cũng có thể thoát khỏi việc sử dụng các thuộc tính chức năng:

def parent(num):
    def first_child():
        return "Hi, I am Emma"

    def second_child():
        return "Call me Liam"

    if num == 1:
        return first_child
    else:
        return second_child
8

Trạng thái, số lượng các cuộc gọi đến hàm, được lưu trữ trong thuộc tính hàm

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
70 trên hàm trình bao bọc. Đây là hiệu ứng của việc sử dụng nó:

>>>

def parent(num):
    def first_child():
        return "Hi, I am Emma"

    def second_child():
        return "Call me Liam"

    if num == 1:
        return first_child
    else:
        return second_child
9

Trang trí trạng thái

Đôi khi, nó rất hữu ích để có một người trang trí có thể theo dõi trạng thái. Ví dụ đơn giản, chúng tôi sẽ tạo một bộ trang trí đếm số lần một hàm được gọi là.using a class as a decorator.

Trong phần tiếp theo, bạn sẽ thấy cách sử dụng các lớp để giữ trạng thái. Nhưng trong các trường hợp đơn giản, bạn cũng có thể thoát khỏi việc sử dụng các thuộc tính chức năng:

Trạng thái, số lượng các cuộc gọi đến hàm, được lưu trữ trong thuộc tính hàm

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
70 trên hàm trình bao bọc. Đây là hiệu ứng của việc sử dụng nó:

>>> first = parent(1)
>>> second = parent(2)

>>> first
.first_child at 0x7f599f1e2e18>

>>> second
.second_child at 0x7f599dad5268>
0

Các lớp học như người trang trí

>>>

>>> first = parent(1)
>>> second = parent(2)

>>> first
.first_child at 0x7f599f1e2e18>

>>> second
.second_child at 0x7f599dad5268>
1

Trang trí trạng thái

>>> first = parent(1)
>>> second = parent(2)

>>> first
.first_child at 0x7f599f1e2e18>

>>> second
.second_child at 0x7f599dad5268>
2

Đôi khi, nó rất hữu ích để có một người trang trí có thể theo dõi trạng thái. Ví dụ đơn giản, chúng tôi sẽ tạo một bộ trang trí đếm số lần một hàm được gọi là.

Trong phần tiếp theo, bạn sẽ thấy cách sử dụng các lớp để giữ trạng thái. Nhưng trong các trường hợp đơn giản, bạn cũng có thể thoát khỏi việc sử dụng các thuộc tính chức năng:

>>>

def parent(num):
    def first_child():
        return "Hi, I am Emma"

    def second_child():
        return "Call me Liam"

    if num == 1:
        return first_child
    else:
        return second_child
9

Trang trí trạng thái

Đôi khi, nó rất hữu ích để có một người trang trí có thể theo dõi trạng thái. Ví dụ đơn giản, chúng tôi sẽ tạo một bộ trang trí đếm số lần một hàm được gọi là.

Trong phần tiếp theo, bạn sẽ thấy cách sử dụng các lớp để giữ trạng thái. Nhưng trong các trường hợp đơn giản, bạn cũng có thể thoát khỏi việc sử dụng các thuộc tính chức năng:

Trạng thái, số lượng các cuộc gọi đến hàm, được lưu trữ trong thuộc tính hàm

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
70 trên hàm trình bao bọc. Đây là hiệu ứng của việc sử dụng nó:

>>> first = parent(1)
>>> second = parent(2)

>>> first
.first_child at 0x7f599f1e2e18>

>>> second
.second_child at 0x7f599dad5268>
4

Các lớp học như người trang trí

>>> first = parent(1)
>>> second = parent(2)

>>> first
.first_child at 0x7f599f1e2e18>

>>> second
.second_child at 0x7f599dad5268>
5

Cách điển hình để duy trì trạng thái là bằng cách sử dụng các lớp. Trong phần này, bạn sẽ thấy cách viết lại ví dụ

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
71 từ phần trước bằng cách sử dụng một lớp làm người trang trí.

>>>

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
9

Trang trí trạng thái

Đôi khi, nó rất hữu ích để có một người trang trí có thể theo dõi trạng thái. Ví dụ đơn giản, chúng tôi sẽ tạo một bộ trang trí đếm số lần một hàm được gọi là.

>>> first = parent(1)
>>> second = parent(2)

>>> first
.first_child at 0x7f599f1e2e18>

>>> second
.second_child at 0x7f599dad5268>
7

Trong phần tiếp theo, bạn sẽ thấy cách sử dụng các lớp để giữ trạng thái. Nhưng trong các trường hợp đơn giản, bạn cũng có thể thoát khỏi việc sử dụng các thuộc tính chức năng:

>>> first = parent(1)
>>> second = parent(2)

>>> first
.first_child at 0x7f599f1e2e18>

>>> second
.second_child at 0x7f599dad5268>
8

Trạng thái, số lượng các cuộc gọi đến hàm, được lưu trữ trong thuộc tính hàm

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
70 trên hàm trình bao bọc. Đây là hiệu ứng của việc sử dụng nó:

Các lớp học như người trang trí

>>>

>>> first = parent(1)
>>> second = parent(2)

>>> first
.first_child at 0x7f599f1e2e18>

>>> second
.second_child at 0x7f599dad5268>
9

Trang trí trạng thái

Đôi khi, nó rất hữu ích để có một người trang trí có thể theo dõi trạng thái. Ví dụ đơn giản, chúng tôi sẽ tạo một bộ trang trí đếm số lần một hàm được gọi là.

Trong phần tiếp theo, bạn sẽ thấy cách sử dụng các lớp để giữ trạng thái. Nhưng trong các trường hợp đơn giản, bạn cũng có thể thoát khỏi việc sử dụng các thuộc tính chức năng:

>>> first()
'Hi, I am Emma'

>>> second()
'Call me Liam'
0

Trạng thái, số lượng các cuộc gọi đến hàm, được lưu trữ trong thuộc tính hàm

>>> greet_bob(say_hello)
'Hello Bob'

>>> greet_bob(be_awesome)
'Yo Bob, together we are the awesomest!'
70 trên hàm trình bao bọc. Đây là hiệu ứng của việc sử dụng nó:

>>>

>>> first()
'Hi, I am Emma'

>>> second()
'Call me Liam'
1

Các lớp học như người trang trí

Giải pháp thông thường là triển khai các số Fibonacci bằng cách sử dụng vòng lặp

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
06 và bảng tra cứu. Tuy nhiên, bộ đệm đơn giản của các tính toán cũng sẽ thực hiện thủ thuật:

>>> first()
'Hi, I am Emma'

>>> second()
'Call me Liam'
2

Bộ đệm hoạt động như một bảng tra cứu, vì vậy bây giờ

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
07 chỉ thực hiện các tính toán cần thiết một lần:

>>>

>>> first()
'Hi, I am Emma'

>>> second()
'Call me Liam'
3

Lưu ý rằng trong cuộc gọi cuối cùng tới

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
08, không cần tính toán mới, vì số Fibonacci thứ tám đã được tính toán cho
def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
09.

Trong thư viện tiêu chuẩn, bộ đệm được sử dụng gần đây nhất (LRU) có sẵn dưới dạng

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
10.

Trang trí này có nhiều tính năng hơn so với cái bạn thấy ở trên. Bạn nên sử dụng

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
10 thay vì viết bộ trang trí bộ nhớ cache của riêng mình:

>>> first()
'Hi, I am Emma'

>>> second()
'Call me Liam'
4

Tham số

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
12 chỉ định có bao nhiêu cuộc gọi gần đây được lưu trong bộ nhớ cache. Giá trị mặc định là 128, nhưng bạn có thể chỉ định
def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
13 để lưu trữ tất cả các cuộc gọi chức năng. Tuy nhiên, hãy lưu ý rằng điều này có thể gây ra sự cố bộ nhớ nếu bạn đang lưu trữ nhiều đối tượng lớn.

Bạn có thể sử dụng phương thức

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
14 để xem bộ đệm hoạt động như thế nào và bạn có thể điều chỉnh nó nếu cần. Trong ví dụ của chúng tôi, chúng tôi đã sử dụng một
def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
12 nhỏ nhân tạo để xem ảnh hưởng của các yếu tố bị xóa khỏi bộ đệm:

>>>

>>> first()
'Hi, I am Emma'

>>> second()
'Call me Liam'
5

Lưu ý rằng trong cuộc gọi cuối cùng tới def parent(): print("Printing from the parent() function") def first_child(): print("Printing from the first_child() function") def second_child(): print("Printing from the second_child() function") second_child() first_child() 08, không cần tính toán mới, vì số Fibonacci thứ tám đã được tính toán cho def parent(): print("Printing from the parent() function") def first_child(): print("Printing from the first_child() function") def second_child(): print("Printing from the second_child() function") second_child() first_child() 09.

Trong thư viện tiêu chuẩn, bộ đệm được sử dụng gần đây nhất (LRU) có sẵn dưới dạng

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
10.

>>> first()
'Hi, I am Emma'

>>> second()
'Call me Liam'
6

Trang trí này có nhiều tính năng hơn so với cái bạn thấy ở trên. Bạn nên sử dụng

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
10 thay vì viết bộ trang trí bộ nhớ cache của riêng mình:

>>> first()
'Hi, I am Emma'

>>> second()
'Call me Liam'
7

Tham số

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
12 chỉ định có bao nhiêu cuộc gọi gần đây được lưu trong bộ nhớ cache. Giá trị mặc định là 128, nhưng bạn có thể chỉ định
def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
13 để lưu trữ tất cả các cuộc gọi chức năng. Tuy nhiên, hãy lưu ý rằng điều này có thể gây ra sự cố bộ nhớ nếu bạn đang lưu trữ nhiều đối tượng lớn.

>>>

>>> first()
'Hi, I am Emma'

>>> second()
'Call me Liam'
8

Lưu ý rằng trong cuộc gọi cuối cùng tới

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
08, không cần tính toán mới, vì số Fibonacci thứ tám đã được tính toán cho
def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
09.

>>> first()
'Hi, I am Emma'

>>> second()
'Call me Liam'
9

Trong thư viện tiêu chuẩn, bộ đệm được sử dụng gần đây nhất (LRU) có sẵn dưới dạng

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
10.

Trang trí này có nhiều tính năng hơn so với cái bạn thấy ở trên. Bạn nên sử dụng

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
10 thay vì viết bộ trang trí bộ nhớ cache của riêng mình:

>>>

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
0

Lưu ý rằng trong cuộc gọi cuối cùng tới

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
08, không cần tính toán mới, vì số Fibonacci thứ tám đã được tính toán cho
def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
09.

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
1

Trong thư viện tiêu chuẩn, bộ đệm được sử dụng gần đây nhất (LRU) có sẵn dưới dạng

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
10.

>>>

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
2

Lưu ý rằng trong cuộc gọi cuối cùng tới def parent(): print("Printing from the parent() function") def first_child(): print("Printing from the first_child() function") def second_child(): print("Printing from the second_child() function") second_child() first_child() 08, không cần tính toán mới, vì số Fibonacci thứ tám đã được tính toán cho def parent(): print("Printing from the parent() function") def first_child(): print("Printing from the first_child() function") def second_child(): print("Printing from the second_child() function") second_child() first_child() 09.

Trong thư viện tiêu chuẩn, bộ đệm được sử dụng gần đây nhất (LRU) có sẵn dưới dạng

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
10.

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
3

Trang trí này có nhiều tính năng hơn so với cái bạn thấy ở trên. Bạn nên sử dụng

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
10 thay vì viết bộ trang trí bộ nhớ cache của riêng mình:

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
4

Tham số

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
12 chỉ định có bao nhiêu cuộc gọi gần đây được lưu trong bộ nhớ cache. Giá trị mặc định là 128, nhưng bạn có thể chỉ định
def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
13 để lưu trữ tất cả các cuộc gọi chức năng. Tuy nhiên, hãy lưu ý rằng điều này có thể gây ra sự cố bộ nhớ nếu bạn đang lưu trữ nhiều đối tượng lớn.

  1. Bạn có thể sử dụng phương thức
    def parent():
        print("Printing from the parent() function")
    
        def first_child():
            print("Printing from the first_child() function")
    
        def second_child():
            print("Printing from the second_child() function")
    
        second_child()
        first_child()
    
    14 để xem bộ đệm hoạt động như thế nào và bạn có thể điều chỉnh nó nếu cần. Trong ví dụ của chúng tôi, chúng tôi đã sử dụng một
    def parent():
        print("Printing from the parent() function")
    
        def first_child():
            print("Printing from the first_child() function")
    
        def second_child():
            print("Printing from the second_child() function")
    
        second_child()
        first_child()
    
    12 nhỏ nhân tạo để xem ảnh hưởng của các yếu tố bị xóa khỏi bộ đệm:
  2. Thêm thông tin về các đơn vị

Ví dụ sau đây có phần giống với ví dụ plugin đăng ký từ trước đó, ở chỗ nó không thực sự thay đổi hành vi của hàm được trang trí. Thay vào đó, nó chỉ đơn giản là thêm

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
16 làm thuộc tính hàm:

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_whee():
    print("Whee!")

say_whee = my_decorator(say_whee)
5

Ví dụ sau đây tính toán thể tích của một hình trụ dựa trên bán kính và chiều cao của nó tính bằng centimet:

Thuộc tính chức năng

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
17 này sau này có thể được truy cập khi cần:

  • Lưu ý rằng bạn có thể đã đạt được một cái gì đó tương tự bằng cách sử dụng các chú thích chức năng:
  • Tuy nhiên, vì các chú thích được sử dụng cho các gợi ý loại, nên rất khó để kết hợp các đơn vị như các chú thích với kiểm tra loại tĩnh.
  • Các đơn vị thậm chí còn trở nên mạnh mẽ và thú vị hơn khi được kết nối với một thư viện có thể chuyển đổi giữa các đơn vị. Một thư viện như vậy là
    def parent():
        print("Printing from the parent() function")
    
        def first_child():
            print("Printing from the first_child() function")
    
        def second_child():
            print("Printing from the second_child() function")
    
        second_child()
        first_child()
    
    18. Với
    def parent():
        print("Printing from the parent() function")
    
        def first_child():
            print("Printing from the first_child() function")
    
        def second_child():
            print("Printing from the second_child() function")
    
        second_child()
        first_child()
    
    18 được cài đặt (
    def parent():
        print("Printing from the parent() function")
    
        def first_child():
            print("Printing from the first_child() function")
    
        def second_child():
            print("Printing from the second_child() function")
    
        second_child()
        first_child()
    
    20), ví dụ bạn có thể chuyển đổi âm lượng thành inch hoặc gallon khối:

Bạn cũng có thể sửa đổi người trang trí để trả về trực tiếp

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
18
def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
22. Một
def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
22 như vậy được tạo bằng cách nhân giá trị với thiết bị. Trong
def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
18, các đơn vị phải được tra cứu trong
def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
25. Cơ quan đăng ký được lưu trữ như một thuộc tính hàm để tránh làm lộn xộn không gian tên:

  • Với
    def parent():
        print("Printing from the parent() function")
    
        def first_child():
            print("Printing from the first_child() function")
    
        def second_child():
            print("Printing from the second_child() function")
    
        second_child()
        first_child()
    
    26 trang trí, các đơn vị chuyển đổi thực tế là dễ dàng:
  • Xác thực JSON
  • Hãy cùng nhìn vào một trường hợp sử dụng cuối cùng. Hãy xem nhanh trình xử lý tuyến đường bằng bình sau:
  • Ở đây chúng tôi đảm bảo rằng khóa
    def parent():
        print("Printing from the parent() function")
    
        def first_child():
            print("Printing from the first_child() function")
    
        def second_child():
            print("Printing from the second_child() function")
    
        second_child()
        first_child()
    
    27 là một phần của yêu cầu. Mặc dù xác nhận này hoạt động, nhưng nó thực sự không thuộc về chức năng. Thêm vào đó, có lẽ có những tuyến đường khác sử dụng chính xác giống nhau. Vì vậy, hãy để cho nó giữ cho nó khô ráo và trừu tượng hóa bất kỳ logic không cần thiết nào với một người trang trí. Người trang trí
    def parent():
        print("Printing from the parent() function")
    
        def first_child():
            print("Printing from the first_child() function")
    
        def second_child():
            print("Printing from the second_child() function")
    
        second_child()
        first_child()
    
    28 sau đây sẽ thực hiện công việc:
  • Trong mã trên, Trình trang trí lấy một danh sách độ dài thay đổi làm đối số để chúng ta có thể truyền vào nhiều đối số chuỗi khi cần thiết, mỗi đối tượng đại diện cho một khóa được sử dụng để xác thực dữ liệu JSON:

Danh sách các khóa phải có trong JSON được đưa ra như là đối số cho người trang trí.

Hàm trình bao bọc xác nhận rằng mỗi khóa dự kiến ​​có trong dữ liệu JSON.

Trình xử lý tuyến đường sau đó có thể tập trung vào công việc thực sự của mình, các lớp công nghiệp, vì nó có thể giả định một cách an toàn rằng dữ liệu JSON là hợp lệ:

Nếu bạn vẫn đang tìm kiếm thêm, cuốn sách Python của chúng tôi có một phần về trang trí, cũng như cuốn sách nấu ăn Python của David Beazley và Brian K. Jones.

Để biết sâu sắc về cuộc thảo luận lịch sử về cách các nhà trang trí nên được thực hiện trong Python, xem PEP 318 cũng như Wiki trang trí Python. Nhiều ví dụ về trang trí có thể được tìm thấy trong thư viện trang trí Python. Mô -đun

def parent():
    print("Printing from the parent() function")

    def first_child():
        print("Printing from the first_child() function")

    def second_child():
        print("Printing from the second_child() function")

    second_child()
    first_child()
33 có thể đơn giản hóa việc tạo các nhà trang trí của riêng bạn và tài liệu của nó chứa các ví dụ trang trí thêm.

Ngoài ra, chúng tôi đã tập hợp một tờ Cheat Cheat Decorators ngắn và ngọt ngào cho bạn:

Xem bây giờ hướng dẫn này có một khóa học video liên quan được tạo bởi nhóm Python thực sự. Xem nó cùng với hướng dẫn bằng văn bản để làm sâu sắc thêm sự hiểu biết của bạn: Người trang trí Python 101 This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Python Decorators 101

Chúng ta có thể sử dụng người trang trí trên lớp trong Python không?

Trang trí là một công cụ rất mạnh mẽ và hữu ích trong Python vì nó cho phép các lập trình viên sửa đổi hành vi của chức năng hoặc lớp. Các nhà trang trí cho phép chúng ta 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 cần sửa đổi vĩnh viễn nó.. Decorators allow us to wrap another function in order to extend the behaviour of the wrapped function, without permanently modifying it.

Làm thế nào để bạn sử dụng các nhà trang trí trong lớp?

Để trang trí một phương thức trong một lớp, trước tiên hãy sử dụng biểu tượng '@' theo sau là tên của hàm trang trí.Một người trang trí chỉ đơn giản là một hàm có chức năng như một đối số và trả về một hàm khác.Ở đây, khi chúng ta trang trí, nhân lên với integer_check, hàm số nguyên được gọi.first use the '@' symbol followed by the name of the decorator function. A decorator is simply a function that takes a function as an argument and returns yet another function. Here, when we decorate, multiply_together with integer_check, the integer function gets called.

Tại sao chúng ta sử dụng các nhà trang trí trong Python?

Bạn sẽ sử dụng một bộ trang trí khi bạn cần thay đổi hành vi của một hàm mà không cần sửa đổi chức năng.Một vài ví dụ tốt là khi bạn muốn thêm ghi nhật ký, hiệu suất kiểm tra, thực hiện bộ nhớ đệm, xác minh quyền, v.v.Bạn cũng có thể sử dụng một khi bạn cần chạy cùng một mã trên nhiều chức năng.when you need to change the behavior of a function without modifying the function itself. A few good examples are when you want to add logging, test performance, perform caching, verify permissions, and so on. You can also use one when you need to run the same code on multiple functions.

Làm thế nào để các nhà trang trí làm việc trong Python?

Một người trang trí trong Python là một chức năng lấy một chức năng khác làm đối số của nó và trả về một chức năng khác.Các nhà trang trí có thể cực kỳ hữu ích vì chúng cho phép mở rộng chức năng hiện có, mà không có bất kỳ sửa đổi nào đối với mã nguồn chức năng ban đầu.