Higher Order Functions trong Python

Higher Order Functions trong Python

Phan Nhật Chánh

Chánh24 tháng 05, 2021

10 min read
·
views
·
likes

Higher Order Functions (HOF) trong Python là các hàm có thể nhận các hàm khác làm đối số hoặc trả về một hàm khác như kết quả của nó. Trong Python, HOF được coi là một tính năng quan trọng của ngôn ngữ lập trình hướng đối tượng.

Các HOF cho phép các nhà phát triển viết mã linh hoạt hơn bằng cách tách biệt việc xử lý dữ liệu với việc thực thi mã. Chúng cho phép tái sử dụng mã, tăng tính khả chuyển và giảm thiểu các lỗi do lặp lại.

Một số HOF phổ biến trong Python bao gồm map(), filter(), và reduce(). Hàm map() cho phép áp dụng một hàm vào từng phần tử của một iterable (ví dụ: list hoặc tuple) và trả về một iterable mới. Hàm filter() cho phép lọc các phần tử trong iterable theo một tiêu chí nhất định và trả về một iterable mới. Hàm reduce() cho phép tính toán các phần tử của iterable để trả về một giá trị duy nhất.

Việc sử dụng HOF trong Python giúp tăng hiệu quả và tính tái sử dụng của mã. Nó cũng giúp người lập trình giảm thiểu các lỗi trong quá trình lập trình, vì chúng ta có thể sử dụng các hàm được xây dựng sẵn thay vì phải viết lại các mã có tính tương đương.

Tiếp tục ở phần trước, chúng ta đã tìm hiểu hàm và cách sử dụng hàm cơ bản trong python. Trong phần này chúng ta sẽ tìm hiểu xem higher order function là gì. Trong Python, các hàm được gọi là higher order function (hàm bậc cao) cho phép bạn thực hiện các thao tác sau trên các hàm:

  • Một hàm có thể nhận một hoặc nhiều hàm làm tham số.
  • Một hàm có thể được trả về do kết quả của một hàm khác.
  • Một hàm có thể được sửa đổi.
  • Một hàm có thể được gán cho một biến.

Trong phần này, chúng ta sẽ đề cập đến:

  1. Function là một tham số
  2. Return các hàm dưới dạng giá trị trả về từ các hàm khác
  3. Sử dụng python closurespython decorators

Function là một tham số

def sum_numbers(nums): return sum(nums) def higher_order_function(f, *args): summation = f(*args) return summation result = higher_order_function(sum_numbers, [1, 2, 3, 4, 5]) print(result) # 15
def sum_numbers(nums): return sum(nums) def higher_order_function(f, *args): summation = f(*args) return summation result = higher_order_function(sum_numbers, [1, 2, 3, 4, 5]) print(result) # 15

Return về một function

def square(x): # một hàm bình phương return x ** 2 def cube(x): # một hàm lập phương return x ** 3 def absolute(x): # một hàm giá trị tuyệt đối if x >= 0: return x else: return -(x) def higher_order_function(type): # một hàm bậc cao hơn trả về một hàm if type == 'square': return square elif type == 'cube': return cube elif type == 'absolute': return absolute result = higher_order_function('square') print(result(3)) # 9 result = higher_order_function('cube') print(result(3)) # 27 result = higher_order_function('absolute') print(result(-3)) # 3
def square(x): # một hàm bình phương return x ** 2 def cube(x): # một hàm lập phương return x ** 3 def absolute(x): # một hàm giá trị tuyệt đối if x >= 0: return x else: return -(x) def higher_order_function(type): # một hàm bậc cao hơn trả về một hàm if type == 'square': return square elif type == 'cube': return cube elif type == 'absolute': return absolute result = higher_order_function('square') print(result(3)) # 9 result = higher_order_function('cube') print(result(3)) # 27 result = higher_order_function('absolute') print(result(-3)) # 3

Bạn có thể thấy từ ví dụ trên, hàm bậc cao trả về các hàm khác nhau tùy thuộc vào tham số được truyền vào.

Python Closures

Python cho phép một Closures (hàm lồng nhau) truy cập vào phạm vi bên ngoài của hàm bao quanh. Điều này được gọi là Closure. Trong Python, Closure được tạo bằng cách lồng một hàm bên trong một hàm khác và sau đó trả về kết quả hàm bên trong. Hãy xem ví dụ bên dưới:

def add_ten(): ten = 10 def add(num): return num + ten return add closure_result = add_ten() print(closure_result(5)) # 15 print(closure_result(10)) # 20
def add_ten(): ten = 10 def add(num): return num + ten return add closure_result = add_ten() print(closure_result(5)) # 15 print(closure_result(10)) # 20

Python Decorators

Decorator (hàm trang trí) được thiết kế trong Python cho phép người dùng thêm function mới vào một đối tượng hiện có mà không cần sửa đổi cấu trúc của nó. Decorators thường được gọi trước định nghĩa của một hàm mà bạn muốn decorate.

Tạo Decorators

Để tạo một hàm decorator, chúng ta cần một hàm bên ngoài với một hàm bên trong.

# Normal Function def greeting(): return 'Welcome to Python' def uppercase_decorator(function): def wrapper(): func = function() make_uppercase = func.upper() return make_uppercase return wrapper g = uppercase_decorator(greeting) print(g()) # WELCOME TO PYTHON ## Ví dụ trên với một decorator '''Function decorator này là một function bậc cao hơn nhận một hàm làm tham số''' def uppercase_decorator(function): def wrapper(): func = function() make_uppercase = func.upper() return make_uppercase return wrapper @uppercase_decorator def greeting(): return 'Welcome to Python' print(greeting()) # WELCOME TO PYTHON
# Normal Function def greeting(): return 'Welcome to Python' def uppercase_decorator(function): def wrapper(): func = function() make_uppercase = func.upper() return make_uppercase return wrapper g = uppercase_decorator(greeting) print(g()) # WELCOME TO PYTHON ## Ví dụ trên với một decorator '''Function decorator này là một function bậc cao hơn nhận một hàm làm tham số''' def uppercase_decorator(function): def wrapper(): func = function() make_uppercase = func.upper() return make_uppercase return wrapper @uppercase_decorator def greeting(): return 'Welcome to Python' print(greeting()) # WELCOME TO PYTHON

Áp dụng nhiều Decorators cho một Function

'''Các hàm decorator này là các hàm bậc cao hơn lấy các functions làm tham số''' # Decorator thứ nhất def uppercase_decorator(function): def wrapper(): func = function() make_uppercase = func.upper() return make_uppercase return wrapper # Decorator thứ hai def split_string_decorator(function): def wrapper(): func = function() splitted_string = func.split() return splitted_string return wrapper @split_string_decorator @uppercase_decorator # trong trường hợp này thứ tự với decorators là quan trọng - Hàm .upper() không hoạt động với list def greeting(): return 'Welcome to Python' print(greeting()) # ['WELCOME', 'TO', 'PYTHON']
'''Các hàm decorator này là các hàm bậc cao hơn lấy các functions làm tham số''' # Decorator thứ nhất def uppercase_decorator(function): def wrapper(): func = function() make_uppercase = func.upper() return make_uppercase return wrapper # Decorator thứ hai def split_string_decorator(function): def wrapper(): func = function() splitted_string = func.split() return splitted_string return wrapper @split_string_decorator @uppercase_decorator # trong trường hợp này thứ tự với decorators là quan trọng - Hàm .upper() không hoạt động với list def greeting(): return 'Welcome to Python' print(greeting()) # ['WELCOME', 'TO', 'PYTHON']

Chấp nhận các tham số trong các Functions của Decorator

Hầu hết thời gian chúng ta cần các hàm của mình để nhận các tham số, vì vậy chúng ta có thể cần phải xác định một decorator chấp nhận các tham số.

def decorator_with_parameters(function): def wrapper_accepting_parameters(para1, para2, para3): function(para1, para2, para3) print("I live in {}".format(para3)) return wrapper_accepting_parameters @decorator_with_parameters def print_full_name(first_name, last_name, country): print("I am {} {}. I love to teach.".format(first_name, last_name, country)) print_full_name("Chanh", "Phan-Nhat","Viet Nam")
def decorator_with_parameters(function): def wrapper_accepting_parameters(para1, para2, para3): function(para1, para2, para3) print("I live in {}".format(para3)) return wrapper_accepting_parameters @decorator_with_parameters def print_full_name(first_name, last_name, country): print("I am {} {}. I love to teach.".format(first_name, last_name, country)) print_full_name("Chanh", "Phan-Nhat","Viet Nam")

Higher Order Functions được tích hợp sẵn

Một số hàm bậc cao trong python được tích hợp sẵn mà chúng ta đề cập trong phần này là map()map(), filter()filter()reduce()reduce(). Hàm lambda (hàm vô danh) có thể được truyền dưới dạng tham số và trường hợp sử dụng tốt nhất của hàm lambda là trong các hàm như map()map(), filter()filter()reduce()reduce().

Map() Function

Hàm map(function, iterable) là một hàm được xây dựng sẵn có một hàm và có thể lặp lại để làm tham số.

  • Ví dụ 1:

    numbers = [1, 2, 3, 4, 5] # iterable def square(x): return x ** 2 numbers_squared = map(square, numbers) print(list(numbers_squared)) # [1, 4, 9, 16, 25] # Áp dụng nó với một hàm lambda numbers_squared = map(lambda x : x ** 2, numbers) print(list(numbers_squared)) # [1, 4, 9, 16, 25]
    numbers = [1, 2, 3, 4, 5] # iterable def square(x): return x ** 2 numbers_squared = map(square, numbers) print(list(numbers_squared)) # [1, 4, 9, 16, 25] # Áp dụng nó với một hàm lambda numbers_squared = map(lambda x : x ** 2, numbers) print(list(numbers_squared)) # [1, 4, 9, 16, 25]
  • Ví dụ 2:

    numbers_str = ['1', '2', '3', '4', '5'] # iterable numbers_int = map(int, numbers_str) print(list(numbers_int)) # [1, 2, 3, 4, 5]
    numbers_str = ['1', '2', '3', '4', '5'] # iterable numbers_int = map(int, numbers_str) print(list(numbers_int)) # [1, 2, 3, 4, 5]
  • Ví dụ 3:

    names = ['Alex', 'Piter', 'Maria', 'Kenny'] # iterable def change_to_upper(name): return name.upper() names_upper_cased = map(change_to_upper, names) print(list(names_upper_cased)) # ['ALEX', 'PITER', 'MARIA', 'KENNY'] # Áp dụng nó với một hàm lambda names_upper_cased = map(lambda name: name.upper(), names) print(list(names_upper_cased)) # ['ALEX', 'PITER', 'MARIA', 'KENNY']
    names = ['Alex', 'Piter', 'Maria', 'Kenny'] # iterable def change_to_upper(name): return name.upper() names_upper_cased = map(change_to_upper, names) print(list(names_upper_cased)) # ['ALEX', 'PITER', 'MARIA', 'KENNY'] # Áp dụng nó với một hàm lambda names_upper_cased = map(lambda name: name.upper(), names) print(list(names_upper_cased)) # ['ALEX', 'PITER', 'MARIA', 'KENNY']

Như vậy, hàm map() có tác dụng duyệt tất cả các phần tử của một iterable (list, tuple, dictionary,...) qua một hàm cho trước và trả về một list kết quả sau khi thực thi. Ví dụ, nó thay đổi tên thành chữ hoa và trả về một list mới.

Filter() Function

Hàm filter(function, iterable) gọi hàm được chỉ định trả về kết quả kiểu boolean (true hoặc false) cho từng phần tử của list có thể lặp được chỉ định. Nó lọc ra các phần tử theo điều kiện.

  • Vú dụ 1: Lọc ra các phần tử là số chẵn

    numbers = [1, 2, 3, 4, 5] # iterable def is_even(num): if num % 2 == 0: return True return False even_numbers = filter(is_even, numbers) print(list(even_numbers)) # [2, 4]
    numbers = [1, 2, 3, 4, 5] # iterable def is_even(num): if num % 2 == 0: return True return False even_numbers = filter(is_even, numbers) print(list(even_numbers)) # [2, 4]
  • Ví dụ 2: Lọc ra các phần tử là số lẻ

    numbers = [1, 2, 3, 4, 5] # iterable def is_odd(num): if num % 2 != 0: return True return False odd_numbers = filter(is_odd, numbers) print(list(odd_numbers)) # [1, 3, 5]
    numbers = [1, 2, 3, 4, 5] # iterable def is_odd(num): if num % 2 != 0: return True return False odd_numbers = filter(is_odd, numbers) print(list(odd_numbers)) # [1, 3, 5]
  • Ví dụ 3: Lọc ra tên có độ dài (ký tự) lớn hơn 4

    names = ['Alex', 'Piter', 'Maria', 'Kenny'] # iterable def is_name_long(name): if len(name) > 4: return True return False long_names = filter(is_name_long, names) print(list(long_names)) # ['Piter', 'Maria', 'Kenny']
    names = ['Alex', 'Piter', 'Maria', 'Kenny'] # iterable def is_name_long(name): if len(name) > 4: return True return False long_names = filter(is_name_long, names) print(list(long_names)) # ['Piter', 'Maria', 'Kenny']

Reduce() Function

Hàm reduce() là một hàm thực hiện một kỹ thuật toán học được gọi là folding hoặc reduction (rút gọn) được định nghĩa trong mô-đun functools và chúng ta nên import nó từ mô-đun này. Giống như map() và filter(), nó có hai tham số, một functionmột iterable. Tuy nhiên, nó không trả về một giá trị được lặp lại, thay vào đó nó trả về một giá trị là duy nhất.

from functools import reduce numbers_str = ['1', '2', '3', '4', '5'] # iterable def add_two_nums(x, y): return int(x) + int(y) # tổng các phần tử trong list total = reduce(add_two_nums, numbers_str) print(total) # 15
from functools import reduce numbers_str = ['1', '2', '3', '4', '5'] # iterable def add_two_nums(x, y): return int(x) + int(y) # tổng các phần tử trong list total = reduce(add_two_nums, numbers_str) print(total) # 15

Bài tập

countries = ['Germany', 'Iceland', 'England', 'Argentina', 'Brazil', 'Portugal'] names = ['Messi', 'Ronaldo', 'Beckham', 'Ronaldinho'] numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
countries = ['Germany', 'Iceland', 'England', 'Argentina', 'Brazil', 'Portugal'] names = ['Messi', 'Ronaldo', 'Beckham', 'Ronaldinho'] numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  1. Giải thích sự khác nhau giữa map()map(), filter()filter()reduce()reduce().
  2. Giải thích sự khác nhau giữa Higher Order Functions (hàm bậc cao), Closures (hàm lồng nhau) và Decorators (hàm trang trí).
  3. Xác định một hàm gọi trước map()map(), filter()filter() hoặc reduce()reduce(), xem lại các ví dụ.
  4. Sử dụng vòng lặp for để in từng quốc gia trong list countries.
  5. Sử dụng for để in từng tên trong list name.
  6. Sử dụng for để in từng giá trị trong list numbers.
  7. Sử dụng map()map() để tạo list mới bằng cách thay đổi từng quốc gia thành chữ hoa trong list countries.
  8. Sử dụng map()map() để tạo list mới bằng cách bình phương từng giá trị trong list numbers.
  9. Sử dụng map()map() để thay đổi tên thành chữ hoa trong list name.
  10. Sử dụng filter()filter() để lọc ra các quốc gia có chứa 'land'.
  11. Sử dụng filter()filter() để lọc ra các quốc gia có chính xác sáu ký tự.
  12. Sử dụng filter()filter() để lọc ra các quốc gia có sáu chữ cái trở lên trong list countries.
  13. Sử dụng filter()filter() để lọc ra các quốc gia bắt đầu bằng ký tự 'E'.
  14. Khai báo một hàm có tên get_string_listsget_string_lists lấy một danh sách làm tham số và sau đó trả về một danh sách chỉ chứa phần tử là chuỗi (string items).
  15. Sử dụng *reduce()reduce() để tính tổng tất cả các phần tử trong list *numbers*.
  16. Sử dụng *reduce()reduce() nối lại tất cả các quốc gia để được câu này: "*Germany, Iceland, England, Argentina, Brazil và Portugal là các quốc gia có nền bóng đá phát triển mạnh.*"
  17. Khai báo một hàm có tên là categorize_countriescategorize_countries trả về list các quốc gia với một số mẫu phổ biến (danh sách các quốc gia country.js (ví dụ: 'land', 'ia', 'island', 'stan')).
  18. Tạo một hàm trả về một dictionary, trong đó các key là chữ cái đầu tiên của quốc gia đó và values là tên quốc gia đó.
  19. Khai báo một hàm get_first_ten_countriesget_first_ten_countries - nó trả về danh sách mười quốc gia đầu tiên từ file country.js
  20. Khai báo một hàm get_last_ten_countriesget_last_ten_countries trả về mười quốc gia cuối cùng trong file country.js.
  21. Sử dụng tệp countries-data.py và làm theo các tác vụ bên dưới:
    a) Sắp xếp các quốc gia theo tên, theo thủ đô, theo dân số.
    b) Sắp xếp mười ngôn ngữ được nói nhiều nhất theo vị trí từ cao đến thấp.
    c) Sắp xếp mười quốc gia đông dân nhất.