Các hàm bậc cao hơn trong Python là gì?

Các hàm bậc cao hơn là một chủ đề quan trọng và tôi tin rằng bạn nên hiểu rõ về cách chúng hoạt động để hưởng lợi đầy đủ từ các khả năng của Python và tận dụng tốt nhất mã của bạn

Tôi sẽ minh họa các hàm bậc cao hơn bằng một ví dụ để bạn có thể có kiến ​​thức làm việc về chúng, sau đó chúng ta sẽ sử dụng kiến ​​thức này để triển khai một trình trang trí, một trong những trường hợp sử dụng điển hình nhất của các hàm bậc cao trong Python

Hãy bắt đầu nào

Bài đăng này chứa một phần sao chép nội dung từ cuốn sách của tôi. “Học sâu với PyTorch Từng bước. Hướng dẫn cho người mới bắt đầu”

Một loạt chức năng

Giả sử chúng ta muốn xây dựng một loạt hàm, mỗi hàm thực hiện phép lũy thừa cho một lũy thừa nhất định. Mã sẽ trông như thế này

Một loạt các chức năng thực hiện lũy thừa

Chà, rõ ràng là có một cấu trúc cao hơn cho điều này

  • mọi hàm nhận một đối số duy nhất x [màu đỏ], là số chúng ta muốn lũy thừa;
  • mọi hàm đều thực hiện cùng một phép toán, lũy thừa, nhưng mỗi hàm có một số mũ khác nhau [hộp màu cam]

Một cách để giải quyết vấn đề này là biến số mũ thành một đối số rõ ràng, giống như đoạn mã dưới đây

Một hàm điển hình với hai đối số thông thường

Điều đó hoàn toàn ổn, và nó hoạt động khá tốt. Nhưng nó cũng yêu cầu bạn chỉ định số mũ mỗi khi bạn gọi hàm. Phải có một cách khác. Tất nhiên, có; . -]

Trình tạo chức năng

Chúng ta cần xây dựng một hàm khác [bậc cao hơn] để xây dựng các hàm đó [vuông, khối, v.v. ] cho chúng tôi. Hàm [bậc cao hơn] chỉ là một trình tạo hàm. Nhưng chúng ta làm như thế nào?

Đầu tiên, hãy xây dựng “bộ khung” của các chức năng mà chúng ta đang cố gắng tạo ra;

Khỏe. Nó sẽ giống như thế này

Bộ khung của hàm có một biến không xác định [số mũ]

Nếu bạn thử gọi hàm này với bất kỳ x nào, chẳng hạn như skeleton_exponentiation[2], bạn sẽ gặp lỗi sau

skeleton_exponentiation[2]Output:
NameError: name ‘exponent’ is not defined

Điều này được mong đợi. Hàm “bộ xương” của bạn không biết số mũ của biến là gì. Và đó là những gì hàm bậc cao sẽ hoàn thành

Chúng tôi “bọc” chức năng "bộ xương" của mình bằng chức năng bậc cao hơn [màu xanh lam], chức năng này sẽ xây dựng các chức năng mong muốn. Hãy gọi nó, khá đơn giản, lũy thừa_builder[]

lập luận của nó là gì, nếu có?

Hàm bậc cao hơn, xác định số mũ cho hàm khung

Bây giờ tôi muốn bạn xem câu lệnh return [bên ngoài] [trong hàm màu xanh lam]. Nó không trả về một giá trị;

Rốt cuộc đây là một trình xây dựng chức năng. Nó sẽ xây dựng [và trả lại] các chức năng

Điều gì xảy ra nếu chúng ta gọi hàm bậc cao này với một số mũ đã cho, chẳng hạn như 2?

returned_function = exponentiation_builder[2]
returned_function
Output:

Kết quả là, như mong đợi, một chức năng

Chức năng này làm gì?

returned_function[5]Output:
25

Và Voila. Chúng tôi có một trình xây dựng chức năng. Chúng ta có thể sử dụng nó để tạo bao nhiêu hàm lũy thừa tùy thích

Một loạt các chức năng được xây dựng bởi một chức năng bậc cao hơn

Nó không quá tệ, phải không?

Chức năng khắp nơi

Bây giờ, hãy tiến thêm một bước nữa. điều gì sẽ xảy ra nếu thay vì một đối số thông thường [số mũ], hàm bậc cao của chúng ta lấy một hàm khác làm đối số thì sao?

"Chờ đã, cái gì?. Một hàm lấy một hàm khác làm đối số và trả về một hàm khác thứ ba?

Vâng, điều đó chính xác. Tâm trí-thổi, phải không?. -]

Chức năng tâm thổi

"Tại sao tôi muốn làm điều đó?"

Bởi vì nó mát mẻ. Không, thực sự, hàm [bậc cao hơn] có thể hoạt động như một công cụ trang trí và có thể được sử dụng để sửa đổi đầu ra của bất kỳ hàm hoặc phương thức nào mà nó được gắn vào

Sẳn sàng?

Giả sử bạn đã viết RẤT NHIỀU hàm và tất cả chúng đều trả về giá trị theo một đơn vị nhất định [ví dụ: inch nếu bạn ở Hoa Kỳ hoặc milimét ở nơi khác]

RẤT NHIỀU hàm trả về giá trị tính bằng inch

Bây giờ, nếu bạn được yêu cầu gửi mã của mình đến một nơi khác trên thế giới, sẽ rất khó để sửa đổi từng hàm bạn đã viết để bao gồm một hệ số nhân để điều chỉnh cho một đơn vị khác, phải không?

Sửa đổi đầu ra, cách rườm rà

"Thành thật mà nói, điều này trông giống như kỹ thuật phần mềm tồi..."

Vâng, rất có thể đó là kỹ thuật phần mềm tồi - lý tưởng nhất là người ta có thể thấy trước nhu cầu tạo đầu ra ở các đơn vị khác nhau và coi đơn vị [inch hoặc milimét] là một đối số hoặc đại loại như vậy, nhưng điều đó nằm ngoài vấn đề ở đây

Vì vậy, vui lòng tiếp tục với câu chuyện bịa đặt này và hãy xem cách chúng tôi có thể vá đoạn mã bịa đặt đó mà không tốn nhiều công sức. -]

Chúng tôi biết rằng hàm f2[] của chúng tôi nhận hai đối số, a và b [màu đỏ], thực hiện một số thao tác [bất kể đó là gì, chúng tôi không quan tâm đến chính thao tác đó] và tạo ra kết quả mà chúng tôi muốn chuyển đổi từ . Vì vậy, có lẽ chúng ta có thể xây dựng một chức năng khác "xung quanh" f2[] để thực hiện chuyển đổi?

Sửa đổi đầu ra bằng chức năng bên ngoài

Nhưng điều đó sẽ chỉ hoạt động với hàm f2[] và chúng ta muốn có một giải pháp tổng quát hơn, vì vậy, hãy thay thế f2[] bằng một hàm chung, func[]

Một hàm chung, có một biến không xác định [func]

“Cái này trông quen lạ lùng…”

Điều đó hợp lý vì nó khá giống với hàm "bộ xương" trong phần "Trình tạo hàm". Các đối số có màu đỏ như trước đây và hộp màu cam là hàm cơ bản, chung, sẽ được thực thi

Vì vậy, bạn có đoán được điều gì sẽ xảy ra nếu chúng ta gọi hàm apply[] với bất kỳ đối số nào không?

"Một lỗi?"

Bạn hiểu đúng — cùng một lỗi như trước, một NameError, bởi vì hàm apply[] không biết hàm bên dưới — func — là gì

apply[1, 4]Output:
NameError: name ‘func’ is not defined

Cùng một lỗi gọi cho cùng một giải pháp. hãy “bọc” hàm apply[] của chúng ta bằng một hàm bậc cao hơn, màu xanh lam. Vì chúng ta đang cố nói cho hàm apply[] của mình biết hàm bên dưới [func] phải là gì [hộp màu cam], hãy sử dụng nó làm đối số của hàm "trình bao bọc"

Hàm bậc cao hơn, xác định hàm cơ bản [func] cho hàm áp dụng

Nó hoàn toàn giống như trước đây. câu lệnh return [bên ngoài] [trong hàm màu xanh] đang trả về một hàm. Sự khác biệt là hộp màu cam, đối số của hàm "trình bao bọc" cũng là một hàm

"Chức năng, chức năng, shmuntion. "

Tôi hiểu rồi, có quá nhiều chức năng để theo dõi… vì vậy, hãy nhanh chóng tóm tắt lại bốn chức năng [. ] các hàm chúng ta có trong năm dòng mã ở trên

  • chức năng cơ bản. func[], nó thực thi một số mã, bất kể đó là gì, và đưa ra kết quả, được báo cáo bằng inch;
  • hàm nhân. inches_to_mm[], chuyển đổi kết quả từ inch sang milimét;
  • chức năng "áp dụng" chung. apply[], lấy đối số [màu đỏ], thực thi hàm cơ bản và sửa đổi kết quả [chuyển đổi thành milimét];
  • chức năng "trình bao bọc" bậc cao hơn. convert_to_milimet[], lấy chức năng cơ bản mà chúng tôi đang cố gắng thực hiện làm đối số

Bạn vẫn còn với tôi?

Bây giờ, cuối cùng chúng ta hãy sử dụng hàm "trình bao bọc" bậc cao hơn để chuyển đổi đầu ra của hàm f2[] ban đầu

Hàm f2[] ban đầu

Hãy nhớ rằng, hàm f2[] sẽ đóng vai trò của hàm bên dưới, nghĩa là, nó được truyền dưới dạng đối số cho hàm "trình bao bọc", convert_to_milimet[]

f2_in_millimeters = convert_to_millimeters[f2]
f2_in_millimeters
Output:

Một chức năng đi vào, một chức năng khác xuất hiện

Hãy gọi hàm kết quả cho a=1 và b=4

f2_millimeters[1, 4]Output:
101.6

Và chúng tôi đã có nó. 101. 6 mm, tương ứng với đầu ra ban đầu là 4 inch

Nhưng xin chờ chút nữa

Trang trí một chức năng

Hóa ra, bạn thậm chí không cần phải tạo một chức năng khác, bạn có thể chỉ cần đặt chức năng “trình bao bọc”, convert_to_milimet[], bên trên chức năng bên dưới, f2[], như một công cụ trang trí

Trang trí hàm f2[]

Và bây giờ bạn có thể gọi trực tiếp hàm f2[], và decorator sẽ tự động thực thi hàm bên dưới [đó là hàm f2[]] và sửa đổi kết quả, vậy là bạn sẽ nhận được kết quả tính bằng milimét rồi


f2[1, 4]
Output:
101.6

Mát mẻ, phải không?

"OK, tuyệt, nhưng nếu tôi cũng muốn chuyển đổi đầu ra của f3[] thành milimét thì sao? Nó không hoạt động, vì f3[] có ba đối số

Nắm bắt tốt. Để làm cho công cụ trang trí convert_to_milimet[] của chúng tôi thực sự chung chung, chúng tôi cần sửa đổi hàm apply[] nội bộ để nhận bất kỳ đối số nào

Hàm bậc cao thực sự chung chung, xác định hàm cơ bản [func] cho hàm áp dụng

Bây giờ bạn có thể sử dụng chức năng "trình bao bọc" này để trang trí cho BẤT KỲ chức năng nào bạn muốn, f1[], f2[], f3[], v.v...

Và đó là một bọc. -]

Cảm ơn bạn đã đọc bài đăng này - Tôi tin rằng việc học phải dễ dàng, thú vị và vui vẻ, vì vậy tôi hy vọng bạn thích nó. -]

Đọc thêm

Trình trang trí là một chủ đề LỚN và tôi chỉ muốn cho bạn thấy ý tưởng chính đằng sau chúng, nghĩa là sửa đổi đầu ra/hành vi của một chức năng cơ bản. Nếu bạn muốn tìm hiểu sâu hơn về chủ đề này, vui lòng xem "Primer on Python Decorators" của Real Python

Nếu bạn có bất kỳ suy nghĩ, nhận xét hoặc câu hỏi nào, vui lòng để lại nhận xét bên dưới hoặc liên hệ qua tiểu sử của tôi. trang liên kết

cái gì cao hơn

hàm bản đồ , được tìm thấy trong nhiều ngôn ngữ lập trình hàm, là một ví dụ về hàm bậc cao. Nó nhận đối số là một hàm f và một tập hợp các phần tử, và kết quả là, trả về một tập hợp mới với f được áp dụng cho từng phần tử từ tập hợp.

cao hơn là gì

Hàm bậc cao hơn là hàm nhận một hàm làm đối số hoặc trả về một hàm . Hàm bậc cao trái ngược với hàm bậc nhất, không lấy hàm làm đối số hoặc trả về hàm làm đầu ra.

Bộ lọc có cao hơn không

Hàm bậc cao . Reduce[], map[] và filter[] là ba hàm bậc cao hữu ích nhất của Python .

cao hơn là gì

Điều đó đơn giản có nghĩa là các hàm cũng giống như các đối tượng Python khác [e. g. , số nguyên, chuỗi, danh sách và thể hiện của lớp tùy chỉnh] . Liên quan đến điều này là các hàm có thể được truyền cho các hàm khác làm đối số đầu vào và chúng tôi gọi những hàm có thể nhận các hàm khác là hàm bậc cao hơn.

Chủ Đề