Khái Niệm và Ví Dụ về Closure và Decorator trong Python

Closure

1. Tham chiếu hàm

def test1():
    print("--- Trong hàm test1 ---")

# Gọi hàm
test1()

# Tham chiếu hàm
ret = test1

print(id(ret))
print(id(test1))

# Gọi hàm thông qua tham chiếu
ret()
Kết quả chạy:
--- Trong hàm test1 ---
140212571149040
140212571149040
--- Trong hàm test1 ---

2. Định nghĩa Closure

# Định nghĩa một hàm
def test(number):
    # Hàm bên trong sử dụng biến từ hàm bên ngoài, tạo thành closure
    def test_in(number_in):
        print("Trong hàm test_in, number_in là %d" % number_in)
        return number + number_in
    # Trả về kết quả của closure
    return test_in

# Gán giá trị 20 cho tham số number
ret = test(20)

# Gọi hàm với tham số 100
print(ret(100))

# Gọi hàm với tham số 200
print(ret(200))
Kết quả chạy:
Trong hàm test_in, number_in là 100
120

Trong hàm test_in, number_in là 200
220

3. Ví dụ thực tế về closure

def line_conf(a, b):
    def line(x):
        return a * x + b
    return line

line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5))
print(line2(5))
Trong ví dụ này, hàm `line` và các biến `a`, `b` tạo thành closure. Khi tạo closure, chúng ta xác định giá trị của `a` và `b` thông qua tham số của `line_conf`. Điều này giúp chúng ta có thể tạo ra các hàm đường thẳng khác nhau chỉ bằng cách thay đổi `a` và `b`. Nếu không có closure, chúng ta cần phải truyền nhiều tham số hơn mỗi khi tạo hàm mới, làm giảm tính di động của mã. Lưu ý: Do closure tham chiếu đến biến cục bộ của hàm bên ngoài, nên các biến này không được giải phóng ngay lập tức, dẫn đến tiêu tốn bộ nhớ.

4. Sửa đổi biến trong hàm bên ngoài

Phương pháp Python 3

def counter(start=0):
    def incr():
        nonlocal start
        start += 1
        return start
    return incr

c1 = counter(5)
print(c1())
print(c1())

c2 = counter(50)
print(c2())
print(c2())

print(c1())
print(c1())

print(c2())
print(c2())

Phương pháp Python 2

def counter(start=0):
    count = [start]
    def incr():
        count[0] += 1
        return count[0]
    return incr

c1 = counter(5)
print(c1())  # 6
print(c1())  # 7
c2 = counter(100)
print(c2())  # 101
print(c2())  # 102

Decorator

1. Hiểu rõ đoạn mã sau

#### Vòng 1 ####
def foo():
    print('foo')

foo  # Đang biểu thị cho hàm
foo()  # Gọi hàm foo

#### Vòng 2 ####
def foo():
    print('foo')

foo = lambda x: x + 1

foo()  # Gọi hàm lambda, không còn là hàm foo ban đầu
Tên hàm chỉ là một biến, trỏ đến hàm đã định nghĩa. Nếu tên hàm bị gán lại, thì gọi hàm sẽ thực hiện hàm mới.

2. Yêu cầu

Công ty có nhiều bộ phận kinh doanh, và bộ phận nền tảng cung cấp các chức năng cơ bản. Các bộ phận kinh doanh sử dụng các chức năng này. Ví dụ:
############### Chức năng nền tảng ###############

def f1():
    print('f1')

def f2():
    print('f2')

def f3():
    print('f3')

def f4():
    print('f4')

############### Bộ phận A sử dụng chức năng nền tảng ###############

f1()
f2()
f3()
f4()

############### Bộ phận B sử dụng chức năng nền tảng ###############

f1()
f2()
f3()
f4()
Hiện tại, cần thêm cơ chế xác thực vào tất cả các chức năng nền tảng.

3. Sử dụng decorator

def w1(func):
    def inner():
        # Xác thực
        func()
    return inner

@w1
def f1():
    print('f1')
@w1
def f2():
    print('f2')
@w1
def f3():
    print('f3')
@w1
def f4():
    print('f4')
Decorator `w1` sẽ bọc hàm `f1`, `f2`, `f3`, `f4` và thực hiện xác thực trước khi gọi hàm gốc.

4. Ví dụ về decorator

from time import ctime, sleep

def timefun(func):
    def wrapped_func():
        print("%s called at %s" % (func.__name__, ctime()))
        func()
    return wrapped_func

@timefun
def foo():
    print("I am foo")

foo()
sleep(2)
foo()
Kết quả chạy:
foo called at Fri Nov  4 21:55:35 2016
I am foo
foo called at Fri Nov  4 21:55:37 2016
I am foo

5. Decorator với tham số

def timefun_arg(pre="hello"):
    def timefun(func):
        def wrapped_func():
            print("%s called at %s %s" % (func.__name__, ctime(), pre))
            return func()
        return wrapped_func
    return timefun

@timefun_arg("itcast")
def foo():
    print("I am foo")

@timefun_arg("python")
def too():
    print("I am too")

foo()
sleep(2)
foo()

too()
sleep(2)
too()

6. Decorator lớp

class Test(object):
    def __init__(self, func):
        self.__func = func
    def __call__(self):
        print("--- Chức năng decorator ---")
        self.__func()

@Test
def test():
    print("----test---")

test()
Kết quả chạy:
--- Chức năng decorator ---
----test---

Thẻ: python closure decorator functional programming code reusability

Đăng vào ngày 17 tháng 5 lúc 17:48