Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Python

Python Closures: ฟังก์ชันที่จดจำสภาพแวดล้อมการสร้าง

Closure (คลอเจอร์) คือฟังก์ชันที่ "จดจำ" สภาพแวดล้อม (enclosing scope) ที่มันถูกสร้างขึ้น — สามารถเข้าถึงตัวแปรจาก outer function ได้แม้ outer function จบการทำงานแล้ว

Nested Functions (ฟังก์ชันซ้อน)

ฟังก์ชันที่定义อยู่ในฟังก์ชันอื่น เรียกว่า Nested Function เข้าถึงตัวแปรของ outer scope ได้

def func_out():
    print("This is outer function.")
    def func_in():
        print("This function is defined inside func_out.\nThis is a nested function.")
    print("We can call nested function here.")
    func_in()

print("Calling func_out.")
func_out()

ผลลัพธ์:

Calling func_out.
This is outer function.
We can call nested function here.
This function is defined inside func_out.
This is a nested function.

Closure: คืนค่า Nested Function

ถ้า outer function return nested function นested function นั้นจะกลายเป็น Closure

def closure_func(start):
    def increment_by(inc):
        return start + inc
    return increment_by

closure1 = closure_func(9)
closure2 = closure_func(90)

print(f'closure1(3) = {closure1(3)}')  # 12
print(f'closure2(3) = {closure2(3)}')  # 93

ผลลัพธ์:

closure1(3) = 12
closure2(3) = 93

แม้ closure1 และ closure2 จะอ้างอิงฟังก์ชัน increment_by เดียวกัน แต่แต่ละตัว "จดจำ" ค่า start ที่ต่างกัน (9 และ 90)

ตรวจสอบ Closure ด้วย __closure__

ทุก closure มี attribute __closure__ เป็น tuple ของ cell objects ที่เก็บค่าตัวแปรที่ capture ไว้

def closure_func(start):
    def increment_by(inc):
        return start + inc
    return increment_by

a = closure_func(9)
b = closure_func(90)

print(f'type(a) = {type(a)}')
print(f'a.__closure__ = {a.__closure__}')
print(f'type(a.__closure__[0]) = {type(a.__closure__[0])}')
print(f'a.__closure__[0].cell_contents = {a.__closure__[0].cell_contents}')

print(f'type(b) = {type(b)}')
print(f'b.__closure__ = {b.__closure__}')
print(f'b.__closure__[0].cell_contents = {b.__closure__[0].cell_contents}')

ผลลัพธ์:

type(a) = 
a.__closure__ = (,)
type(a.__closure__[0]) = 
a.__closure__[0].cell_contents = 9
type(b) = 
b.__closure__ = (,)
b.__closure__[0].cell_contents = 90

Closure vs Class

Closure Class
Syntax เรียบง่าย สำหรับ state 简单เหมาะสำหรับ state ซับซ้อน หลายเมธอด
Implicit state (เก็บใน __closure__)Explicit state (self.attribute)
Immutable captured variables (Python 3)Mutable attributes
ใช้ nonlocal เพื่อแก้ไข captured varแก้ไข self.attr ได้โดยตรง

การแก้ไข Captured Variable: nonlocal

Python 3 ใช้ nonlocal เพื่อบอกว่า variable ไมใช่ local แต่เป็นของ enclosing scope

def counter():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

c = counter()
print(c())  # 1
print(c())  # 2
print(c())  # 3

Use Cases ของ Closure

  1. Function Factories: สร้างฟังก์ชันเฉพาะงาน (เช่น multiplier, validator)
  2. Decorators: Decorator พื้นฐานคือ closure
  3. Callbacks/Event Handlers: เก็บ context ไว้
  4. Memoization/Caching: จดจำผลลัพธ์ (เช่น fibonacci)
  5. Partial Application: คงค่าบางอาร์กิวเมนต์ไว้

ตัวอย่าง: Function Factory

def make_multiplier(factor):
    def multiply(x):
        return x * factor
    return multiply

double = make_multiplier(2)
triple = make_multiplier(3)

print(double(5))  # 10
print(triple(5))  # 15

ตัวอย่าง: Memoization Decorator

def memoize(func):
    cache = {}
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrapper

@memoize
def fib(n):
    if n < 2:
        return 1
    return fib(n-1) + fib(n-2)

print(fib(30))  # เร็วมากเพราะ cache

สรุป

  • Closure = Nested function ที่ถูก return และจดจำ enclosing scope
  • ตรวจสอบได้ด้วย func.__closure__ และ cell_contents
  • ใช้ nonlocal เพื่อ modify captured variable
  • ประยุกต์ใช้กับ Decorators, Factories, Callbacks, Caching