Bạn đã từng gặp loại cú pháp đặc biệt
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']3,
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']4,
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']5khi xây dựng lớp học. Trong Python, cú pháp ngược này là một cách sử dụng của decorator. Trình trang trí là một hàm nhận hàm khác làm tham số để mở rộng khả năng của tham số hàm [nhưng không cần điều chỉnh thân hàm tham số]. Bài học này sẽ trình bày chi tiết các vấn đề liên quan đến việc xây dựng và sử dụng trình trang trí trong Python
ĐỘI DUNG CỦA BẢN DỊCH Ẩn
1. Decorator là gì?
2. Hàm bậc cao
3. Hàm lồng nhau và đóng
4. Xây dựng trình trang trí hàm trong Python
5. Một số vấn đề khác với người trang trí
6. Kết luận
Decorator là gì?
Trình trang trí là một mẫu thiết kế [mẫu thiết kế] cho phép điều chỉnh chức năng mở rộng của một đối tượng mà không cần thiết có thể điều chỉnh mã của nó. Đây là một số trong các mẫu thiết kế cổ điển
Trong Python mẫu thiết bị trang trí được hỗ trợ và sử dụng rộng rãi
Khi học về phương thức [method] và thuộc tính [property] trong lớp Python, bạn đã gặp một số cách viết lạ như
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']3,
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']4,
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']5. Họ được gọi là những người trang trí [hàm trang trí]
Trình trang trí trong Python là các hàm nhận hàm khác làm tham số để mở rộng khả năng của hàm tham số [nhưng không cần điều chỉnh thân hàm tham số]
Hàm trang trí trong Python chính là một vận dụng của mẫu thiết kế trang trí
Vì sao lại cần trang trí trong Python?
Trong quá trình xây dựng hàm, bạn có thể gặp các yêu cầu chung khi lặp lại vòng lặp. Lấy ví dụ, trong một số trường hợp bạn sẽ muốn ghi chú [log] lại quá trình thực hiện của một hàm để theo dõi và gỡ lỗi. You could have to start a số tài nguyên trước khi chức năng có thể hoạt động. Bạn có thể muốn hủy đối tượng Dẹp sau khi một hàm kết thúc. Bạn có thể muốn đo thời gian thực hiện của một hàm bằng cách tính khoảng thời gian từ lúc bắt đầu đến lúc kết thúc thực hiện hàm
Tất nhiên, bạn có thể viết tất cả các logic trên trong hàm. Tuy nhiên, hãy nghĩ đến vấn đề giải quyết của bạn có rất nhiều chức năng phải xử lý tương tự nhau. Liệu bạn có muốn sao chép đoạn mã tới tất cả các hàm cần xử lý?
Khi đó, decorator sẽ giúp bạn bổ sung các tính năng cần thiết vào một hàm mà không cần viết thêm code cho hàm đó. Bạn có thể giữ nguyên hàm với các tính năng cơ bản của nó
Về kỹ thuật, decorator trong Python thực chất là một hàm nhận một hàm khác làm tham số và trả lại kết quả cũng là một hàm. Python has a number of supports giúp đơn giản hóa công việc sử dụng hàm trang trí
Các vấn đề như “hàm làm tham số” và “hàm làm kết quả” có thể hơi khó hiểu. Chúng ta sẽ thích giải thích từng vấn đề qua các phần tiếp theo
high level
Trong Python, bạn có thể truyền một hàm làm tham số của một hàm khác
Lưu ý. truyền hàm làm tham số không giống như truyền lời gọi hàm. Khi truyền hàm làm tham số, bạn chỉ truyền tên hàm. Trong thân hàm chính có thể gọi hàm tham số như một hàm thông thường
Vui lòng xem ví dụ sau đây
def hello[name]: print[f'Hello, {name}. Welcome to heaven!'] def hi[name]: print[f'Hi, {name}. Welcome to hell!'] def greeting[name, func]: print['Inside high order function:'] func[name] print['---'] greeting['Donald Trump', hello] greeting['Vladimir Putin', hi]
Trong ví dụ trên, hi và hello là hai hàm bình thường. Các chức năng này nhận một chuỗi tên người và trong lời chào
Trong khi đó,
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']9 lại là một hàm bậc cao. nó nhận hai tham số [
def welcome[greeting: 'lời chào']: def hello[name: 'tên người']: print[f'{greeting}, {name}. Welcome to heaven!'] return hello hi = welcome['Hello'] hi['Putin']0 và
def welcome[greeting: 'lời chào']: def hello[name: 'tên người']: print[f'{greeting}, {name}. Welcome to heaven!'] return hello hi = welcome['Hello'] hi['Putin']1]. Qua hình thức tiêu đề, hello[] không khác gì so với hi[] hay hello[]. Tuy nhiên, khi nhìn vào hàm thân, bạn phải đặt câu lệnh cho dòng lệnh
def welcome[greeting: 'lời chào']: def hello[name: 'tên người']: print[f'{greeting}, {name}. Welcome to heaven!'] return hello hi = welcome['Hello'] hi['Putin']2. Đây là lời gọi hàm chứ không phải là lệnh truy xuất giá trị
Như vậy, tham số
def welcome[greeting: 'lời chào']: def hello[name: 'tên người']: print[f'{greeting}, {name}. Welcome to heaven!'] return hello hi = welcome['Hello'] hi['Putin']1 của
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']9 không phải là một giá trị mà là một hàm. Hàm tham số này có thể được sử dụng bình thường bên trong thân hàm chính
Một hàm nhận một hàm khác làm tham số được gọi là hàm bậc cao
Hàm lồng nhau và đóng
Trong Python, một hàm có thể trả kết quả là một hàm khác. Trả lại một hàm làm kết quả có nghĩa là bạn có thể gọi hàm kết quả đó là một hàm khai báo theo kiểu bình thường thông thường
Please view ví dụ sau
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']
Trong ví dụ này, hello[] là một hàm thông thường trong lời chào
Tuy nhiên, welcome[] lại là một hàm đặc biệt. kết quả trả về của nó không phải là một giá trị mà là một hàm đã khai báo, hàm hello[]
Khi đó lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[]. Cũng có thể xem xxx như một tên gọi khác của hello[]. Bạn sử dụng hàm kết quả xxx[] giống như sử dụng hello[]
Trong Python, bạn có thể khai báo một hàm bên trong hàm khác. Hàm khai báo trong một hàm khác được gọi là hàm lồng nhau [hàm lồng nhau]
Hãy cùng xem một ví dụ khác
________số 8Lần này thay vì sử dụng một hàm hello[] build trước, chúng ta tự định nghĩa một hàm hello[] mới nằm trong welcome[]. Hàm hello[] là hàm lồng [hàm con] của welcome[]
Lệnh khai báo hàm hello[] trong hàm welcome[] và trả về hàm hello[] làm kết quả của hàm welcome[] được gọi là đóng
Closure là một hàm khai báo bên trong một hàm khác nhưng sau đó được truyền ra bên ngoài hàm chứa nó [và có thể được sử dụng bởi mã bên ngoài hàm chứa]
Điểm đặc biệt của bao đóng là hàm lồng có thể sử dụng biến và tham số của hàm chứa nó. Trong ví dụ trên, hello[] sử dụng tham số của lời chào của welcome[]
Xây dựng trình trang trí hàm trong Python
Qua hai phần trên bạn đã hiểu các yếu tố cơ bản để tạo ra trình trang trí. Giờ chúng ta cùng vận tải để tự mình tạo ra một chức năng trang trí mới
Hãy cùng thực hiện một ví dụ
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']5
Trong ví dụ về bạn đã xây dựng hàm bậc cao display_decorator, nhận một hàm khác làm tham số. Yêu cầu của hàm tham số là nhận một chuỗi tham số
Trong hàm display_decorator, bạn tạo một hàm bao đóng[]. Trong trình bao bọc[], bạn thực hiện gọi hàm func[], thêm một số logic trước và sau khi chạy func. Điều đặc biệt là trình bao bọc[] cần có danh sách tham số chung với hàm func[]
def welcome[greeting: 'lời chào']: def hello[name: 'tên người']: print[f'{greeting}, {name}. Welcome to heaven!'] return hello hi = welcome['Hello'] hi['Putin']5 là thuộc tính chứa tên của đối tượng. Ở đây chúng ta sử dụng
def welcome[greeting: 'lời chào']: def hello[name: 'tên người']: print[f'{greeting}, {name}. Welcome to heaven!'] return hello hi = welcome['Hello'] hi['Putin']5 để lấy tên công thức chính của tham số hàm
Hàm display_decorator return wrapper[] to results
Trong decorator mẫu, trình bao bọc[] chính là trục xoay vấn đề. to expand features of a function func[], you will instead func[] by wrapper[]. Điều này có thể được xác định theo cách sử dụng cơ bản của decorator
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']8
Để đơn giản hóa sử dụng hàm trang trí, Python cung cấp cú pháp @. Cú pháp này giúp khung lệnh gọi trang trí với lệnh khai báo hàm
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']9
Hai cách sử dụng decorator tương đương nhau
Kết quả chạy chương trình như sau
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']0
Để ý rằng chức năng chính của hàm display[] hay say_hello[] đều chỉ là trong một chuỗi văn bản. Khi được đánh dấu bằng trình trang trí, có thêm logic tự động thực hiện trước và sau khi thực thi hàm
A number of other problems with decorator
At on them ta said about function decorator. a function get a function doing tham số và trả về kết quả của một hàm
Trình trang trí Python còn mở rộng thành lớp trang trí. Nghĩa là bạn có thể xây dựng cả một lớp hoạt động với vai trò trang trí cho hàm. Please view ví dụ sau
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']1
Kết quả thực thi của hàm hello[‘Obama’] sẽ là
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']2
Trong ví dụ này, Python sẽ tạo đối tượng của decoclass và truyền hàm hello làm tham số khi khởi động. Phương thức ma thuật
def welcome[greeting: 'lời chào']: def hello[name: 'tên người']: print[f'{greeting}, {name}. Welcome to heaven!'] return hello hi = welcome['Hello'] hi['Putin']7 giúp lớp hoạt động [được gọi] như một hàm [chính xác hơn, một đối tượng có thể gọi được – loại đối tượng có thể được gọi giống như hàm]
Nếu logic của bạn quá phức tạp và không thể trình bày trong một hàm, bạn có thể cần đến lớp trang trí
Nếu function wrapper[] của bạn đơn giản, bạn có thể sử dụng lambda function
Hàm lambda là loại hàm không có tên và phần thân chỉ được chứa một lệnh duy nhất. Hàm lambda được khai báo với cú pháp như sau
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']4
Ví dụ
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']0
Bạn có cách sử dụng hàm lambda làm trình bao bọc cho trình trang trí như sau
def hello[name]: "đây là một hàm bình thường" print[f'Hello, {name}. Welcome to heaven!'] def welcome[]: "đây là một hàm bậc cao, kết quả trả về là một hàm khác" return hello # lời gọi hàm welcome[] sẽ tạo ra một hàm mới xxx tương đương với hàm hello[] xxx = welcome[] # xxx có thể xem như là một tên gọi khác của hello[] xxx['Obama']1
Bạn cũng có thể ghép các decorator lại với nhau thành chuỗi, được gọi là chaining decorators. Please view ví dụ sau