Trình trang trí python với các đối số tự

Làm cách nào để chuyển trường lớp tới trình trang trí trên phương thức lớp làm đối số?

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization["some_attr", self.url]
    def get[self]:
        do_work[]

Nó phàn nàn rằng self không tồn tại khi chuyển

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
46 cho người trang trí. Có cách nào để giái quyết vấn đề này không?

Giải pháp tốt nhất

Đúng. Thay vì chuyển thuộc tính thể hiện vào thời điểm định nghĩa lớp, hãy kiểm tra nó khi chạy

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get

Trình trang trí chặn các đối số của phương thức; . Bạn có thể chuyển tên thuộc tính dưới dạng chuỗi cho trình trang trí và sử dụng

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
47 nếu bạn không muốn mã hóa tên thuộc tính

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization

Giải pháp liên quan

Python – Tại sao bạn cần có đối số “self” một cách rõ ràng trong phương thức Python

Tôi thích trích dẫn Zen of Python của Peters. "Rõ ràng là tốt hơn ngầm. "

Trong Java và C++, '

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
48' có thể được suy ra, trừ khi bạn có các tên biến không thể suy ra được. Vì vậy, đôi khi bạn cần nó và đôi khi không

Python chọn làm những thứ như thế này rõ ràng hơn là dựa trên quy tắc

Ngoài ra, vì không có gì được ngụ ý hoặc giả định, nên các phần của quá trình triển khai sẽ bị lộ.

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
49,
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
0 và các cấu trúc "nội bộ" khác có sẵn một cách rõ ràng

Python – Các biến lớp tĩnh có thể có trong Python

Các biến được khai báo bên trong định nghĩa lớp, nhưng không bên trong một phương thức là các biến lớp hoặc biến tĩnh

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 

Như @ đã chỉ ra, điều này tạo ra một biến

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
1 cấp lớp, nhưng biến này khác với bất kỳ biến
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
1 cấp thể hiện nào, vì vậy bạn có thể có

>>> m = MyClass[]
>>> m.i = 4
>>> MyClass.i, m.i
>>> [3, 4]

Điều này khác với C++ và Java, nhưng không quá khác với C#, nơi không thể truy cập thành viên tĩnh bằng cách sử dụng tham chiếu đến một thể hiện

Nhìn thấy

@Steve Johnson đã trả lời về các phương pháp tĩnh, cũng được ghi lại dưới

________số 8

@beidy khuyến nghị s trên staticmethod, vì phương thức này sau đó nhận loại lớp làm đối số đầu tiên, nhưng tôi vẫn hơi mờ về những ưu điểm của phương pháp này so với staticmethod. Nếu bạn cũng vậy, thì có lẽ không thành vấn đề

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

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

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

Tiền thưởng miễn phí. Nhấp vào đây để truy cập vào hướng dẫn miễn phí "Sức mạnh của Trình trang trí Python" hiển thị cho bạn ba mẫu và kỹ thuật trang trí nâng cao mà bạn có thể sử dụng để viết các chương trình Pythonic rõ ràng hơn

Trang trí Cheat Sheet. Nhấp vào đây để có quyền truy cập vào bảng lừa đảo trang trí Python ba trang miễn phí tóm tắt các kỹ thuật được giải thích trong hướng dẫn này

Người trang trí Bảng điểm hỏi đáp. Nhấp vào đây để có quyền truy cập vào nhật ký trò chuyện dài 25 trang từ phiên Hỏi & Đáp về người trang trí Python của chúng tôi trong Slack Cộng đồng Python thực, nơi chúng tôi đã thảo luận về các câu hỏi phổ biến về người trang trí

cập nhật

  • 22/08/2018. Bản cập nhật lớn thêm nhiều ví dụ và trang trí cao cấp hơn
  • 01/12/2016. Các ví dụ được cập nhật lên Python 3 [v3. 5. 1] cú pháp và thêm một ví dụ mới
  • 01/11/2015. Đã thêm một lời giải thích ngắn gọn về 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]
    
    7

Chức năng

Trước khi bạn có thể hiểu về decorator, trước tiên bạn phải hiểu chức năng hoạt động như thế nào. Đố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

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
0

Nói chung, các hàm 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]
8 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]
9 trong khi có tác dụng phụ là xuất thứ gì đó ra bàn điều khiển. Tuy nhiên, để hiểu về decorator, chỉ cần nghĩ về hàm như một cái gì đó biến các đối số đã cho thành một giá trị là đủ.

Ghi chú. Trong lập trình chức năng, bạn [gần như] chỉ làm việc với các chức năng thuần túy mà không có tác dụng phụ. Mặc dù không phải là ngôn ngữ chức năng thuần túy, Python hỗ trợ nhiều khái niệm lập trình chức năng, bao gồm các hàm như đối tượng hạng nhất

Loại bỏ các quảng cáo

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

Trong Python, hàm là đối tượng hạng nhất. Điều này có nghĩa là các hàm có thể được truyền xung quanh và được sử dụng làm đối số, giống như bất kỳ đối tượng nào khác [chuỗi, int, float, danh sách, v.v.]. Hãy xem xét ba chức năng sau

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
3

Ở đây,

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
300 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
301 là các hàm thông thường yêu cầu tên được đặt dưới dạng chuỗi. Tuy nhiên, hàm
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
302 mong đợi một hàm làm đối số của nó. Ví dụ, chúng ta có thể truyền cho nó hàm
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
300 hoặc hàm
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
301

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
9

Lưu ý rằng

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
305 đề cập đến hai chức năng, nhưng theo những cách khác nhau.
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
302 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
307. Hàm
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
307 được đặt tên không có dấu ngoặc đơn. Điều này có nghĩa là chỉ một tham chiếu đến hàm được truyền. Chức năng không được thực hiện. Ngược lại, hàm
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
302 được viết trong dấu ngoặc đơn nên sẽ được gọi như bình thường

chức năng bên trong

Có thể định nghĩa các chức năng bên trong các chức năng khác. Các chức năng như vậy được gọi là các chức năng bên trong. Đây là một ví dụ về hàm có hai hàm bên trong

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
5

Điều gì xảy ra khi bạn gọi hàm

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
310? . Đầu ra sẽ như sau

>>>

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
7

Lưu ý rằng thứ tự xác định các hàm bên trong không quan trọng. Giống như bất kỳ chức năng nào khác, quá trình in chỉ diễn ra khi các chức năng bên trong được thực thi

Hơn nữa, các hàm bên trong không được xác định cho đến khi hàm cha được gọi. Chúng nằm trong phạm vi cục bộ tới

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
310. chúng chỉ tồn tại bên trong hàm
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
310 dưới dạng biến cục bộ. Hãy thử gọi
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
313. Bạn sẽ nhận được một lỗi

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
1

Bất cứ khi nào bạn gọi

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
310, các hàm bên trong
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
313 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
316 cũng được gọi. Nhưng do phạm vi cục bộ của chúng, chúng không khả dụng bên ngoài chức năng
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
310

Hàm trả về từ hàm

Python cũng cho phép bạn sử dụng các hàm làm giá trị trả về. Ví dụ sau trả về một trong các hàm bên trong từ hàm bên ngoài

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
310

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
7

Lưu ý rằng bạn đang trả về

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
319 mà không có dấu ngoặc đơn. Nhớ lại rằng điều này có nghĩa là bạn đang trả về một tham chiếu đến hàm
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
319. Ngược lại
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
313 với dấu ngoặc đơn đề cập đến kết quả đánh giá chức năng. Điều này có thể được nhìn thấy trong ví dụ sau

>>>

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
1

Đầu ra hơi khó hiểu chỉ đơn giản có nghĩa là biến

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
322 đề cập đến hàm
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
313 cục bộ bên trong
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
310, trong khi
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
325 trỏ đến
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
316

Giờ đây, bạn có thể sử dụng

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
322 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
325 như thể chúng là các hàm thông thường, mặc dù không thể truy cập trực tiếp các hàm mà chúng trỏ tới

>>>

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
9

Cuối cùng, lưu ý rằng trong ví dụ trước, bạn đã thực thi các hàm bên trong hàm cha, chẳng hạn như

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
313. Tuy nhiên, trong ví dụ cuối cùng này, bạn đã không thêm dấu ngoặc đơn vào các hàm bên trong—
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
319—khi quay lại. Bằng cách đó, bạn có một tham chiếu đến từng chức năng mà bạn có thể gọi trong tương lai. Có lý?

Loại bỏ các quảng cáo

trang trí đơn giản

Bây giờ bạn đã thấy rằng các hàm cũng giống như bất kỳ đối tượng nào khác trong Python, bạn đã sẵn sàng để tiếp tục và xem con thú ma thuật đó là trình trang trí Python. Hãy bắt đầu với một ví dụ

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ó đoán được điều gì sẽ xảy ra khi bạn gọi cho

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
331 không?

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
30

Để hiểu điều gì đang xảy ra ở đây, hãy xem 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 được cho đến nay

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
31

Trên thực tế, tên

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
332 hiện trỏ đến hàm bên trong
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
333. Hãy nhớ rằng bạn trả về
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
334 như một hàm khi bạn gọi
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
335

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
32

Tuy nhiên,

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
333 có tham chiếu đến
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
331 ban đầu là
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
338 và gọi hàm đó giữa hai lệnh gọi tớ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

Đơn giản thôi. decorators bọc một chức năng, sửa đổi hành vi của nó

Trước khi tiếp tục, chúng ta hãy xem một ví dụ thứ hai. Vì

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
333 là một hàm Python thông thường nên cách trình trang trí sửa đổi một hàm có thể thay đổi linh hoạt. Để không làm phiền hàng xóm, ví dụ sau sẽ chỉ chạy mã trang trí vào ban ngày

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
33

Nếu bạn cố gọi cho

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
331 sau giờ đi ngủ, sẽ không có chuyện gì xảy ra

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
34

Cú pháp đặc biệt

Cách bạn trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
331 ở trên hơi rườm rà. Trước hết, bạn phải gõ tên
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
332 ba lần. Ngoài ra, phần trang trí bị ẩn một chút bên dưới định nghĩa của chức năng

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 ký hiệu

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
344, đôi khi được gọi là. 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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
35

Vì vậy,

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
345 chỉ là một cách dễ dàng hơn để nói
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
346. Đó là cách bạn áp dụng một trình trang trí cho một chức năng

Loại bỏ các quảng cáo

Tái sử dụng đồ trang trí

Nhớ lại rằng một trình trang trí chỉ là một hàm 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 đều có sẵn. Hãy di chuyển trình trang trí sang mô-đun riêng của nó có thể được sử dụng trong nhiều chức năng khác

Tạo một tệp tên là

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
347 với nội dung sau

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
36

Ghi chú. Bạn có thể đặt tên cho chức năng bên trong của mình bất cứ điều gì bạn muốn và một tên chung chung như

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
333 thường được chấp nhận. Bạn sẽ thấy rất nhiều người trang trí trong bài viết này. Để tách chúng ra, chúng ta sẽ đặt tên hàm bên trong cùng tên với hàm trang trí nhưng có tiền tố
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
349

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
37

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
331 được thực thi hai lần

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
38

Tiền thưởng miễn phí. Nhấp vào đây để truy cập vào hướng dẫn miễn phí "Sức mạnh của Trình trang trí Python" hiển thị cho bạn ba mẫu và kỹ thuật trang trí nâng cao mà bạn có thể sử dụng để viết các chương trình Pythonic rõ ràng hơn

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

Giả sử rằng bạn có một hàm chấp nhận một số đối số. Bạn vẫn có thể trang trí nó?

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
39

Thật không may, chạy mã này gây ra lỗi

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
90

Vấn đề là hàm bên trong

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
351 không nhận bất kỳ đối số nào, nhưng
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
352 đã được truyền cho nó. Bạn có thể khắc phục điều này bằng cách cho phép
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
351 chấp nhận một đối số, nhưng sau đó nó sẽ không hoạt động đối với hàm
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
331 mà bạn đã tạo trước đó

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
355 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
356 trong hàm bao bọc bên trong. Sau đó, nó sẽ chấp nhận một số đối số vị trí và từ khóa tùy ý. Viết lại
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
347 như sau

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
91

Hàm bên trong

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
351 hiện chấp nhận bất kỳ số lượng đối số nào và chuyển chúng vào hàm mà nó trang trí. Bây giờ cả hai ví dụ về
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
331 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
360 của bạn đều hoạt động

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
92

Loại bỏ các quảng cáo

Trả về 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ả về của các chức năng được trang trí? . Giả sử bạn trang trí một chức năng đơn giản như sau

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
93

Cố gắng sử dụng nó

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
94

Rất tiếc, trình trang trí của bạn đã ăn giá trị trả về từ hàm

Bởi vì

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
361 không trả về giá trị một cách rõ ràng, cuộc gọi
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
362 đã kết thúc 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]
9

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
347 của bạn

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
95

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

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
96

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

Một tiện lợi lớn khi làm việc với Python, đặc biệt là trong shell tương tác, là khả năng xem xét nội tâm mạnh mẽ của nó. Nội quan 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ó

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
97

Việc xem xét nội tâm cũng hoạt động đối với các chức năng mà bạn tự xác định

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
98

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
331 đã rất bối rối về danh tính của mình. Bây giờ nó báo cáo là hàm bên trong
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
351 bên trong trình trang trí
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
367. Mặc dù đúng về mặt kỹ thuật, đây không phải là thông tin hữu ích lắm

Để khắc phục điều này, người trang trí nên sử dụng bộ trang trí, bộ trang trí này sẽ lưu giữ thông tin về chức năng ban đầu. Cập nhật lại

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
347

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
99

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
331 được trang trí

>>>

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
50

Tốt hơn nhiều. Bây giờ

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
331 vẫn là chính nó sau khi trang trí

Chi tiết kỹ thuật. Trình trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
368 hàm
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
373 để cập nhật các thuộc tính đặc biệt như
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
374 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
375 được sử dụng trong phần nội quan

Loại bỏ các quảng cáo

Một vài ví dụ trong thế giới thực

Hãy xem xét một vài ví dụ hữu ích hơn về trang trí. Bạn sẽ nhận thấy rằng chúng sẽ chủ yếu tuân theo cùng một khuôn mẫu mà bạn đã học cho đến nay

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
51

Công thức này là một mẫu soạn sẵn tốt để xây dựng các công cụ trang trí phức tạp hơn

Ghi chú. Trong các ví dụ sau, chúng tôi sẽ giả định rằng các bộ trang trí này cũng được lưu trong tệp

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
347 của bạn. Nhắc lại rằng bạn có thể tải xuống tất cả các ví dụ trong hướng dẫn này

chức năng thời gian

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
377. Nó sẽ đo thời gian một chức năng cần để thực thi và in thời lượng ra bàn điều khiển. Đây là mã

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
52

Trình trang trí này hoạt động bằng cách lưu trữ thời gian ngay trước khi chức năng bắt đầu chạy [tại dòng được đánh dấu ____1378] và ngay sau khi chức năng kết thúc [tại ____1379]. Thời gian mà chức năng cần sau đó là sự khác biệt giữa hai [tại

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
380]. Chúng tôi sử dụng chức năng này thực hiện tốt công việc đo khoảng thời gian. Dưới đây là một số ví dụ về thời gian

>>>

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
53

Chạy nó cho mình. Làm việc thông qua từng dòng mã. Hãy chắc chắn rằng bạn hiểu nó hoạt động như thế nào. Tuy nhiên, đừng lo lắng nếu bạn không hiểu. Trang trí là những sinh vật tiên tiến. Cố gắng ngủ trên đó hoặc tạo một bản vẽ của chương trình

Ghi chú. Trình trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
377 rất tuyệt nếu bạn chỉ muốn biết về thời gian chạy các chức năng của mình. Nếu bạn muốn thực hiện các phép đo mã chính xác hơn, thay vào đó, bạn nên xem xét mô-đun
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
383 trong thư viện chuẩn. Nó tạm thời vô hiệu hóa và chạy nhiều thử nghiệm để loại bỏ tiếng ồn khỏi các cuộc gọi chức năng nhanh

Mã gỡ lỗi

Trình trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
384 sau đây sẽ in các đối số mà một hàm được gọi cùng với giá trị trả về của nó mỗi khi hàm được gọi

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
54

Chữ ký được tạo bằng cách nối 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 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 check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    385 để 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. Chuỗi f định dạng mỗi đối số là
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    386 trong đó chỉ định
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    387 có nghĩa là
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    385 được sử dụng để biểu thị giá trị
  3. Danh sách các đối số vị trí và từ khóa được nối với nhau thành 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 xem cách trình trang trí hoạt động trong thực tế bằng cách áp dụng nó cho một hàm đơn giản với một vị trí và một đối số từ khóa

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
55

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
384 in chữ ký và giá trị trả về của hàm
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
390

>>>

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
56

Ví dụ này có vẻ không hữu ích ngay lập tức vì trình trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
384 chỉ lặp lại những gì bạn vừa viết. Nó mạnh hơn khi áp dụng cho các chức năng tiện lợi nhỏ mà bạn không tự gọi trực tiếp

Ví dụ sau đây tính toán một giá trị gần đúng với hằng số toán học e

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
57

Ví dụ này cũng cho thấy cách bạn có thể áp dụng một trình trang trí cho một chức năng đã được xác định. Phép tính gần đúng của e dựa trên khai triển chuỗi sau

Khi gọi hàm

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
392, bạn có thể thấy trình trang trí
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
384 đang hoạt động

>>>

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
58

Trong ví dụ này, bạn nhận được một giá trị gần đúng với giá trị thực e = 2. 718281828, chỉ thêm 5 số hạng

Loại bỏ các quảng cáo

Làm chậm mã

Ví dụ tiếp theo này có vẻ không hữu ích lắm. Tại sao bạn muốn làm chậm mã Python của mình? . Trình trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
394 sẽ ngủ một giây trước khi nó gọi chức năng trang trí

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
59

Để xem tác dụng của trình trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
394, bạn thực sự cần phải tự mình chạy ví dụ

>>>

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
70

Ghi chú. Hàm

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
396 là một hàm đệ quy. Nói cách khác, đó là một chức năng gọi chính nó. Để tìm hiểu thêm về các hàm đệ quy trong Python, hãy xem hướng dẫn của chúng tôi về Tư duy đệ quy trong Python

Trình trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
394 luôn ngủ trong một giây. , bạn sẽ thấy cách kiểm soát tốc độ bằng cách chuyển đối số cho trình trang trí

Đăng ký plugin

Người trang trí không cần phải bao bọc chức năng mà họ đang trang trí. Họ cũng có thể chỉ cần đăng ký rằng một chức năng tồn tại và trả lại nó khi chưa mở gói. Điều này có thể được sử dụng, ví dụ, để tạo ra một kiến ​​trúc plug-in trọng lượng nhẹ

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
71

Trình trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
398 chỉ đơn giản là lưu trữ một tham chiếu đến chức năng được trang trí trong lệnh chính tả
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
399 toàn cầu. Lưu ý rằng bạn không cần phải viết một hàm bên trong hoặc sử dụng
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
368 trong ví dụ này vì bạn đang trả về hàm ban đầu chưa sửa đổi

Hàm

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
901 chọn ngẫu nhiên một trong các hàm đã đăng ký để sử dụng. Lưu ý rằng từ điển
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
399 đã chứa các tham chiếu đến từng đối tượng chức năng được đăng ký làm plugin

>>>

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
72

Lợi ích chính của kiến ​​trúc plugin đơn giản này là bạn không cần duy trì danh sách các plugin tồn tại. Danh sách đó được tạo khi các plugin tự đăng ký. Điều này làm cho việc thêm một plugin mới trở nên tầm thường. chỉ cần xác định chức năng và trang trí nó bằng

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
398

Nếu bạn đã quen thuộc với

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
904 trong Python, bạn có thể thấy một số điểm tương đồng về cách thức hoạt động của kiến ​​trúc plugin.
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
904 cấp quyền truy cập vào tất cả các biến toàn cục trong phạm vi hiện tại, bao gồm cả plugin của bạn

>>>

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
73

Sử dụng trình trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
398, bạn có thể tạo danh sách các biến thú vị được quản lý của riêng mình, chọn thủ công một số hàm từ
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
904 một cách hiệu quả

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

Ví dụ cuối cùng trước khi chuyển sang một số trình trang trí đẹp hơn 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 Flask để thiết lập trang web

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
908 chỉ hiển thị với người dùng đã đăng nhập hoặc được xác thực

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
74

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

Loại bỏ các quảng cáo

trang trí ưa thích

Cho đến giờ, bạn đã biết cách tạo các bộ trang trí đơn giản. Bạn đã hiểu khá rõ về decorator là gì và cách chúng hoạt động. Vui lòng tạm dừng bài viết này để thực hành mọi thứ bạn đã học

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

trang trí lớp học

Có hai cách khác nhau để bạn có thể sử dụng các công cụ trang trí trên các lớp. Cái đầu tiên rất gần với những gì bạn đã làm với các hàm. bạn có thể trang trí các phương thức của một lớp. Điều này là để giới thiệu những người trang trí trở lại trong ngày

Một số trình trang trí thường được sử dụng thậm chí được tích hợp sẵn trong Python là

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
909,
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
910 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
911. Các trình trang trí
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
909 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
910 đượ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 thể hiện cụ thể của lớp đó. Trình trang trí
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
911 đượ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 bên dưới để biết ví dụ sử dụng các công cụ trang trí này

Ví dụ sử dụng trình trang trí lớp tích hợp sẵnHiển thị/Ẩn

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
915 sử dụng các bộ trang trí
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
909,
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
910 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
911

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
75

Trong lớp học này

  • def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    919 là một phương pháp thông thường
  • def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    920 là một tài sản 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 một phương thức setter, chúng ta có thể thực hiện một số kiểm tra lỗi để đảm bảo rằng nó không được đặt thành một 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
  • def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    921 là một tài sản bất biến. không thể thay đổi các thuộc tính không có phương thức
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    922. Mặc dù nó được định nghĩa là một phương thức, nhưng nó có thể được truy xuất dưới dạng một thuộc tính mà không cần dấu ngoặc đơn
  • def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    923 là một phương thức lớp. Nó không bị ràng buộc với một phiên bản cụ thể của
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    915. Các phương thức lớp thường được sử dụng làm phương thức xuất xưởng có thể tạo các thể hiện cụ thể của lớp
  • def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    925 là một phương thức tĩnh. Nó không thực sự phụ thuộc vào lớp
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    915, ngoại trừ việc 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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
915 có thể được sử dụng như sau

>>>

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
76

Hãy định nghĩa một lớp nơi chúng ta trang trí một số phương thức của nó bằng cách sử dụng và trang trí từ

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
77

Sử dụng lớp này, bạn có thể thấy tác dụng của các trang trí

>>>

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
78

Một cách khác để sử dụng các công cụ trang trí trong lớp học là trang trí cho cả lớp. Ví dụ, điều này được thực hiện trong mô-đun

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
930 mới trong Python 3. 7

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
79

Ý 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ể đã trang trí bằng cách viết

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
931

A là một giải pháp thay thế đơn giản hơn cho một số trường hợp sử dụng siêu dữ liệu. 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 trình trang trí lớp rất giống với viết một trình trang trí chức năng. Sự khác biệt duy nhất là trình trang trí sẽ nhận một lớp chứ không phải một hàm làm đối số. Trên thực tế, tất cả những người trang trí sẽ hoạt động như những người trang trí lớp. Khi bạn đang sử dụng chúng trên một lớp thay vì một chức năng, tác dụng của chúng có thể không như bạn muốn. Trong ví dụ sau, trình trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
377 được áp dụng cho một lớp

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
10

Trang trí một lớp học không trang trí các phương thức của nó. Nhớ lại rằng

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
377 chỉ là viết tắt của
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
934

Ở đây,

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
377 chỉ đo thời gian cần thiết để khởi tạo lớp

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
11

, bạn sẽ thấy một ví dụ định nghĩa một trình trang trí lớp phù hợp, cụ thể là

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
936, đảm bảo rằng chỉ có một thể hiện của một lớp

Loại bỏ các quảng cáo

Đồ trang trí làm tổ

Bạn có thể áp dụng một số trình trang trí cho một chức năng bằng cách xếp chồng chúng lên nhau

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
12

Hãy nghĩ về điều này khi các trình trang trí được thực hiện theo thứ tự chúng được liệt kê. Nói cách khác,

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
384 gọi
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
938, gọi
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
360 hoặc
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
940

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
13

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
384 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
938

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
14

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
938 cũng sẽ được áp dụng cho
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
384

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
15

Trang trí với các đối số

Đôi khi, thật hữu ích khi chuyển đối số cho người trang trí của bạn. Chẳng hạn,

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
938 có thể được mở rộng thành một trang trí
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
946. Số lần để thực hiện chức năng trang trí sau đó có thể được đưa ra như một đối số

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
16

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
17

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 check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
344 đã đề cập đến một đối tượng chức năng có thể được gọi bằng một chức năng khác. Để nhất quán, sau đó bạn cần
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
948 để trả về một đối tượng hàm có thể hoạt động như một công cụ trang trí. May mắn thay, bạn. Nói chung, bạn muốn một cái gì đó như sau

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
18

Thông thường, trình trang trí tạo và trả về một hàm bao bọc bên trong, do đó, viết đầy đủ ví dụ ra sẽ cung cấp cho bạn một hàm bên trong bên 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 giây lát

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
19

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 vào bên trong một

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
949 bổ sung để xử lý các đối số cho trình trang trí. Hãy bắt đầu với chức năng trong cùng

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
70

Hàm

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
950 này nhận các đối số tùy ý và trả về giá trị của hàm được trang trí,
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
951. Hàm bao bọc này cũng chứa vòng lặp gọi hàm được trang trí
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
952 lần. Điều này không khác với các chức năng bao bọc trước đó mà bạn đã thấy, ngoại trừ việc nó đang sử dụng tham số
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
952 phải được cung cấp từ bên ngoài

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
71

Một lần nữa,

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
954 trông giống hệt các hàm trang trí mà bạn đã viết trước đó, ngoại trừ việc nó được đặt tên khác. Đó là bởi vì chúng tôi đặt tên cơ sở—
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
955—cho chức năng ngoài cùng, là chức năng mà người dùng sẽ gọi

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
72

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
955

  • Xác định
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    954 là một hàm bên trong có nghĩa là
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    955 sẽ tham chiếu đến một đối tượng hàm—
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    959. Trước đó, chúng tôi đã sử dụng
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    960 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 trình trang trí lấy đối số
  • Đối số
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    952 dường như không được sử dụng trong chính
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    955. Nhưng bằng cách chuyển
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    952, một bao đóng được tạo trong đó giá trị của
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    952 được lưu trữ cho đến khi nó được sử dụng sau này bởi
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    950

Với mọi thứ đã được thiết lập, hãy xem kết quả có như mong đợi không

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
16

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
17

Chỉ là kết quả mà chúng tôi đang hướng tới

Loại bỏ các quảng cáo

Làm ơn cho cả hai, nhưng đừng bận tâm đến bánh mì

Với một chút cẩn thận, bạn cũng có thể xác định các trình trang trí có thể được sử dụng cả khi có và không có đối số. Rất có thể, bạn không cần điều này, nhưng thật tuyệt khi có sự linh hoạt

Như bạn đã thấy trong phần trước, khi một trình trang trí sử dụng các đối số, bạn cần thêm một hàm bên ngoài bổ sung. Thử thách dành cho mã của bạn là tìm hiểu xem trình trang trí đã được gọi có hay không có đối số

Vì hàm để trang trí chỉ được truyền trực tiếp nếu trình trang trí được gọi mà không có đối số, nên hàm 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ởi từ khóa. Bạn có thể thực thi điều này bằng cú pháp

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
966 đặc biệt, có nghĩa là tất cả các tham số sau đây chỉ dành cho từ khóa

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
75

Ở đây, đối số

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
967 đóng vai trò là điểm đánh dấu, lưu ý liệu trình trang trí có được gọi với đối số hay không

  1. Nếu
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    968 đã được gọi mà không có đối số, chức năng được trang trí sẽ được chuyển vào dưới dạng
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    967. Nếu nó đã được gọi với các đối số, thì
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    967 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]
    
    9 và một số đối số từ khóa có thể đã bị thay đổi so với giá trị mặc định của chúng.
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    966 trong danh sách đối số có nghĩa là các đối số còn lại không thể được gọi là đối số vị trí
  2. Trong trường hợp này, trình trang trí được gọi với các đối số. Trả về hàm trang trí có thể đọc và trả về hàm
  3. Trong trường hợp này, trình trang trí được gọi mà không có đối số. Áp dụng trình trang trí cho chức năng ngay lập tức

Sử dụng bản tóm tắt này trên trình trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
973 trong phần trước, bạn có thể viết như sau

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
76

So sánh điều này với bản gốc

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
973. Những thay đổi duy nhất là tham số
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
967 được thêm vào và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
976-
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
977 ở cuối

Công thức 9. 6 của Sách dạy nấu ăn Python xuất sắc cho thấy một giải pháp thay thế bằng cách sử dụng

Những ví dụ này cho thấy rằng

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
973 hiện có thể được sử dụng có hoặc không có đối số

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
77

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
952 là 2

>>>

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
78

trang trí nhà nước

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

Ghi chú. Trong , chúng ta đã nói về các hàm thuần túy trả về một giá trị dựa trên các đối số đã cho. Trình trang trí trạng thái hoàn toàn ngược lại, trong đó giá trị trả về sẽ phụ thuộc vào trạng thái hiện tại, cũng như các đối số đã cho

Trong phần này, bạn sẽ thấy cách sử dụng các lớp để giữ trạng thái. Nhưng trong những trường hợp đơn giản, bạn cũng có thể sử dụng thuộc tính hàm

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
79

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

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
981 trên hàm bao bọc. Đây là tác dụng của việc sử dụng nó

>>>

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
10

Loại bỏ các quảng cáo

Các lớp học với tư cách là người trang trí

Cách điển hình để duy trì trạng thái là 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ụ

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
982 từ phần trước bằng cách sử dụng một lớp làm công cụ trang trí

Nhớ lại rằng cú pháp trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
345 chỉ là một cách dễ dàng hơn để nói
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
984. Do đó, nếu
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
985 là một lớp, thì nó cần lấy
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
338 làm đối số trong phương thức
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
987 của nó. Hơn nữa, thể hiện của lớp cần phải sao cho nó có thể thay thế cho chức năng được trang trí

Để một thể hiện của lớp có thể gọi được, bạn triển khai phương thức đặc biệt

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
988

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
11

Phương thức

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
988 được thực thi mỗi khi bạn cố gắng gọi một thể hiện của lớp

>>>

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
12

Do đó, một triển khai điển hình của lớp trang trí cần triển khai

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
987 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
988

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
13

Phương thức

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
987 phải lưu trữ tham chiếu đến hàm và có thể thực hiện bất kỳ khởi tạo cần thiết nào khác. Phương thức
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
988 sẽ được gọi thay vì hàm được trang trí. Về cơ bản, nó thực hiện giống như hàm
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
333 trong các ví dụ trước đây của chúng tôi. Lưu ý rằng bạn cần sử dụng chức năng thay vì
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
368

Công cụ trang trí

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
997 này hoạt động giống như công cụ trang trí trong phần trước

>>>

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
10

Nhiều ví dụ trong thế giới thực hơn

Bây giờ chúng tôi đã đi một chặng đường dài, đã tìm ra cách tạo ra tất cả các loại trang trí. Hãy kết thúc nó, đưa kiến ​​thức mới tìm được của chúng ta vào việc tạo thêm một vài ví dụ có thể thực sự hữu ích trong thế giới thực

Làm chậm mã, xem lại

Như đã lưu ý trước đó, chúng tôi luôn ngủ trong một giây. Bây giờ bạn đã biết cách thêm tham số vào trình trang trí, vì vậy hãy viết lại

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
394 bằng cách sử dụng đối số
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
500 tùy chọn để kiểm soát thời gian ngủ của nó

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
15

Chúng tôi đang sử dụng bản soạn sẵn được giới thiệu trong phần này để làm cho

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
394 có thể gọi được cả khi có và không có đối số. Hàm đệ quy tương tự
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
396 hiện ngủ hai giây giữa mỗi lần đếm

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
16

Như trước đây, bạn phải tự chạy ví dụ để xem tác dụng của trình trang trí

>>>

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
70

Tạo Singleton

Một singleton là một lớp chỉ có một thể hiện. Có một số singletons trong Python mà bạn sử dụng thường xuyên, bao gồ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]
9,
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
504 và
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
505. Thực tế 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]
9 là một đơn vị cho phép bạn so sánh vớ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]
9 bằng cách sử dụng từ khóa
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
508, như bạn đã thấy trong phần

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
18

Sử dụng

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
508 chỉ trả về
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
504 cho các đối tượng giống hệt nhau. Trình trang trí
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
936 sau đây biến một lớp thành một singleton bằng cách lưu trữ phiên bản đầu tiên của lớp dưới dạng một thuộc tính. Những lần thử tạo phiên bản sau này chỉ cần trả lại phiên bản đã lưu trữ

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
19

Như bạn thấy, trình trang trí lớp này theo cùng một khuôn mẫu như trình trang trí chức năng của chúng tôi. Sự khác biệt duy nhất là chúng tôi đang sử dụng

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
512 thay vì
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
338 làm tên tham số để chỉ ra rằng nó có nghĩa là trang trí lớp

Hãy xem nếu nó hoạt động

>>>

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
90

Có vẻ như rõ ràng rằng

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
514 thực sự là cùng một ví dụ với
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
515

Ghi chú. Các lớp Singleton không thực sự được sử dụng thường xuyên trong Python như trong các ngôn ngữ khác. Hiệu ứng của một singleton thường được triển khai tốt hơn dưới dạng một biến toàn cục trong một mô-đun

Giá trị trả về bộ đệm

Trình trang trí có thể cung cấp một cơ chế tốt để lưu vào bộ nhớ đệm và ghi nhớ. Ví dụ, hãy xem định nghĩa đệ quy của dãy Fibonacci

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
91

Mặc dù việc triển khai đơn giản nhưng hiệu suất thời gian chạy của nó rất tệ

>>>

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
92

Để tính số Fibonacci thứ mười, bạn thực sự chỉ cần tính các số Fibonacci trước đó, nhưng việc triển khai này bằng cách nào đó cần đến 177 phép tính. Nó trở nên tồi tệ hơn một cách nhanh chóng. Cần tính toán 21891 cho

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
516 và gần 2. 7 triệu phép tính cho số thứ 30. Điều này là do mã tiếp tục tính toán lại các số Fibonacci đã biết

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

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
517 và bảng tra cứu. Tuy nhiên, bộ nhớ đệm đơn giản của các tính toán cũng sẽ thực hiện thủ thuật

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
93

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

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
518 chỉ thực hiện các phép tính cần thiết một lần

>>>

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
94

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

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
519, không cần tính toán mới, vì số Fibonacci thứ tám đã được tính toán cho
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
520

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

Trình trang trí này có nhiều tính năng hơn tính năng bạn đã thấy ở trên. Bạn nên sử dụng

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
521 thay vì viết trình trang trí bộ đệm của riêng bạn

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
95

Tham số

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
523 ​​chỉ định số lượng cuộc gọi gần đây được lưu vào bộ đệm. Giá trị mặc định là 128, nhưng bạn có thể chỉ định
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
524 để lưu trữ tất cả các lệnh gọi hàm. Tuy nhiên, hãy lưu ý rằng điều này có thể gây ra các vấn đề về bộ nhớ nếu bạn đang lưu vào bộ nhớ đệm nhiều đối tượng lớn

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

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
525 để 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 check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
523 ​​nhỏ giả tạo để xem tác động của việc xóa các phần tử khỏi bộ đệm

>>>

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
96

Thêm thông tin về đơn vị

Ví dụ sau hơi giống với ví dụ 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ỉ cần thêm

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
527 làm thuộc tính chức năng

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
97

Ví dụ sau 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

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
98

Thuộc tính hàm

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
528 này sau này có thể được truy cập khi cần

>>>

>>> class MyClass:
..     i = 3
...
>>> MyClass.i
3 
99

Lưu ý rằng bạn có thể đã đạt được điều gì đó tương tự bằng cách sử dụng chú thích 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]
0

Tuy nhiên, vì các chú thích được sử dụng cho các gợi ý loại, sẽ khó kết hợp các đơn vị như chú thích với

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 thư viện có thể chuyển đổi giữa các đơn vị. Một thư viện như vậy là

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
529. Ví dụ, với
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
529 đã cài đặt [
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
531], bạn có thể chuyển đổi âm lượng thành inch khối hoặc gallon

>>>

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

Bạn cũng có thể sửa đổi trình trang trí để trả lại trực tiếp một

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
529
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
533. Một
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
533 như vậy được tạo bằng cách nhân một giá trị với đơn vị. Trong
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
529, các đơn vị phải được tra cứu trong một
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
536. Sổ đăng ký được lưu trữ dưới dạng thuộc tính chức năng để tránh làm lộn xộn không gian tê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]
2

Với trình trang trí

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
537, việc chuyển đổi các đơn vị thực tế rất dễ dà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]
3

Xác thực JSON

Hãy xem xét một trường hợp sử dụng cuối cùng. Hãy xem nhanh trình xử lý tuyến đường Flask 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]
4

Ở đây chúng tôi đảm bảo rằng khóa

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
538 là một phần của yêu cầu. Mặc dù xác thực này hoạt động, nhưng nó thực sự không thuộc về chức năng đó. Ngoài ra, có lẽ có những tuyến đường khác sử dụng xác thực chính xác như vậy. Vì vậy, hãy để nó KHÔ và trừu tượng hóa mọi logic không cần thiết bằng một trình trang trí. Người trang trí
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
539 sau đây sẽ thực hiện công việc

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

Trong đoạn mã trên, trình trang trí lấy một danh sách có độ dài thay đổi làm đối số để chúng ta có thể chuyển bao nhiêu đối số chuỗi nếu cần, mỗi đối số đại diện cho một khóa được sử dụng để xác thực dữ liệu JSON

  1. Danh sách các khóa phải có trong JSON được đưa ra làm đối số cho trình trang trí
  2. Hàm bao bọc xác thực rằng mỗi khóa được mong đợi đều có trong dữ liệu JSON

Sau đó, trình xử lý định tuyến có thể tập trung vào công việc thực sự của nó—cập nhật điểm—vì nó có thể cho rằng dữ liệu JSON là hợp lệ một cách an toà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]
6

Phần kết luận

Đây là một hành trình khá. Bạn đã bắt đầu hướng dẫn này bằng cách xem xét kỹ hơn một chút về các hàm, đặc biệt là cách chúng có thể được định nghĩa bên trong các hàm khác và được truyền xung quanh giống như bất kỳ đối tượng Python nào khác. Sau đó, bạn đã học về các bộ trang trí và cách viết chúng sao cho

  • Chúng có thể được tái sử dụng
  • Họ có thể trang trí các chức năng với các đối số và giá trị trả về
  • Họ có thể sử dụng
    def check_authorization[f]:
        def wrapper[*args]:
            print args[0].url
            return f[*args]
        return wrapper
    
    class Client[object]:
        def __init__[self, url]:
            self.url = url
    
        @check_authorization
        def get[self]:
            print 'get'
    
    >>> Client['//www.google.com'].get[]
    //www.google.com
    get
    
    368 để trông giống chức năng được trang trí hơn

Trong phần thứ hai của hướng dẫn, bạn đã thấy các trình trang trí nâng cao hơn và học cách

  • Trang trí lớp học
  • Trang trí tổ
  • Thêm đối số vào trang trí
  • Giữ trạng thái trong trang trí
  • Sử dụng các lớp làm trang trí

Bạn đã thấy rằng, để xác định một trình trang trí, bạn thường xác định một hàm trả về một hàm bao bọc. Hàm bao bọc sử dụng

def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
355 và
def check_authorization[f]:
    def wrapper[*args]:
        print args[0].url
        return f[*args]
    return wrapper

class Client[object]:
    def __init__[self, url]:
        self.url = url

    @check_authorization
    def get[self]:
        print 'get'

>>> Client['//www.google.com'].get[]
//www.google.com
get
356 để truyền đối số cho hàm được trang trí. Nếu bạn muốn trình trang trí của mình cũng nhận các đối số, bạn cần lồng hàm bao bọc bên trong một hàm khác. Trong trường hợp này, bạn thường kết thúc bằng ba câu lệnh
def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
543

Bạn có thể tìm mã từ hướng dẫn này trực tuyến

Đọc thêm

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

Để tìm hiểu sâu về cuộc thảo luận lịch sử về cách triển khai trình trang trí trong Python, hãy xem PEP 318 cũng như Wiki trang trí Python. Có thể tìm thấy nhiều ví dụ hơn về trình trang trí trong Thư viện trình trang trí Python. Mô-đun

def check_authorization[attribute]:
    def _check_authorization[f]:
        def wrapper[self, *args]:
            print getattr[self, attribute]
            return f[self, *args]
        return wrapper
    return _check_authorization
544 có thể đơn giản hóa việc tạo trình trang trí của riêng bạn và mô-đun này chứa các ví dụ về trình trang trí khác

Ngoài ra, chúng tôi đã tập hợp một bảng lừa đảo trang trí Python ngắn và hấp dẫn dành cho bạn

Trang trí Cheat Sheet. Nhấp vào đây để có quyền truy cập vào bảng lừa đảo trang trí Python ba trang miễn phí tóm tắt các kỹ thuật được giải thích trong hướng dẫn này

Đánh dấu là đã hoàn thành

Xem ngay Hướng dẫn này có một khóa học video liên quan do nhóm Real Python tạo. Xem nó cùng với hướng dẫn bằng văn bản để hiểu sâu hơn. Trang trí Python 101

🐍 Thủ thuật Python 💌

Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python

Gửi cho tôi thủ thuật Python »

Giới thiệu về Geir Arne Hjelle

Geir Arne là một Pythonista cuồng nhiệt và là thành viên của nhóm hướng dẫn Real Python

» Thông tin thêm về Geir Arne

Mỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là

Aldren

Brad

Đan

Joanna

Michael

Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Bậc thầy Kỹ năng Python trong thế giới thực
Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Bạn nghĩ sao?

Đánh giá bài viết này

Tweet Chia sẻ Chia sẻ Email

Bài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?

Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi

Trình trang trí Python có thể lấy đối số không?

Các đối số của trình trang trí có thể truy cập được đối với trình trang trí bên trong thông qua một bao đóng , chính xác như cách hàm bên trong wrap[] có thể truy cập f. Và vì các bao đóng mở rộng đến tất cả các cấp độ của các hàm bên trong, nên arg cũng có thể truy cập được từ bên trong wrap[] nếu cần.

Người trang trí có thể tự truy cập không?

Nếu bạn muốn truy cập self [ví dụ nơi trình trang trí được gọi từ đó] bạn có thể sử dụng args[0] bên trong trình trang trí .

Trình trang trí @classmethod trong Python là gì?

Trong Python, trình trang trí @classmethod được dùng để khai báo một phương thức trong lớp dưới dạng một phương thức lớp có thể được gọi bằng Tên lớp. Tên phương thức[] . Phương thức lớp cũng có thể được gọi bằng cách sử dụng một đối tượng của lớp. @classmethod là một thay thế của hàm classmethod[].

Công cụ trang trí Staticmethod trong Python là gì?

@staticmethod là trình trang trí tích hợp xác định một phương thức tĩnh trong lớp trong Python . Một phương thức tĩnh không nhận bất kỳ đối số tham chiếu nào cho dù nó được gọi bởi một thể hiện của một lớp hay bởi chính lớp đó.

Chủ Đề