Closures
Nested function
หัวข้อที่มีชื่อว่า “Nested function”Python อนุญาตให้เรานิยาม function ไว้ภายในอีก function หนึ่งได้ function ตัวในสามารถเข้าถึงตัวแปรใน scope ของ function ตัวนอก (enclosing) ได้
def outer(): message = "Hello from outer"
def inner(): print(message) # accesses the enclosing scope
inner()
outer() # Hello from outerFree variable และ closure
หัวข้อที่มีชื่อว่า “Free variable และ closure”เมื่อ function ตัวใน อ้างถึงตัวแปรจาก enclosing scope แล้วถูก return ออกไปสู่โลกภายนอก
Python จะสร้าง closure ขึ้นมา function ตัวในนั้น “ปิดครอบ” (close over) ตัวแปรไว้ และทำให้ตัวแปรนั้นยังมีชีวิตอยู่แม้ outer จะทำงานเสร็จไปแล้ว
def make_greeter(greeting: str): def greet(name: str) -> str: return f"{greeting}, {name}!" # greeting is a free variable return greet
hello = make_greeter("Hello")hi = make_greeter("Hi")
print(hello("Alice")) # Hello, Alice!print(hi("Bob")) # Hi, Bob!greeting เป็น free variable ใน greet ไม่ได้ถูกนิยามภายใน greet และก็ไม่ใช่ global แต่อาศัยอยู่ใน local scope ของ make_greeter
closure จะรักษาค่าของ greeting ให้มีชีวิตอยู่ตราบเท่าที่ hello หรือ hi ยังคงอยู่
เราสามารถตรวจสอบตัวแปรที่ closure จับไว้ได้ผ่าน __closure__:
print(hello.__closure__[0].cell_contents) # Hellokeyword nonlocal
หัวข้อที่มีชื่อว่า “keyword nonlocal”ภายใน nested function เราสามารถ อ่าน free variable ได้โดยไม่ต้องใช้ keyword พิเศษใด ๆ
แต่ถ้าจะ กำหนดค่าใหม่ (reassign) ให้ตัวแปรนั้น เราต้องใช้ nonlocal มิฉะนั้น Python จะมองว่าชื่อนั้นเป็นตัวแปร local ตัวใหม่
def make_counter(start: int = 0): count = start
def increment(step: int = 1) -> int: nonlocal count # tells Python: reuse the enclosing 'count' count += step return count
def reset() -> None: nonlocal count count = start
return increment, reset
inc, rst = make_counter()print(inc()) # 1print(inc()) # 2print(inc(5)) # 7rst()print(inc()) # 1ถ้าไม่มี nonlocal count บรรทัด count += step จะทำให้เกิด UnboundLocalError เพราะ Python เห็นการ assign แล้วมองว่า count เป็นตัวแปร local ที่ยังไม่ได้ถูกกำหนดค่า
Factory function — closure ที่ใช้งานจริง
หัวข้อที่มีชื่อว่า “Factory function — closure ที่ใช้งานจริง”def make_validator(min_val: int, max_val: int): """Return a validator function for the given range.""" def validate(value: int) -> bool: return min_val <= value <= max_val
validate.__doc__ = f"Return True if value is in [{min_val}, {max_val}]." return validate
is_valid_age = make_validator(0, 120)is_valid_score = make_validator(0, 100)is_valid_port = make_validator(1, 65535)
tests = [ ("age 25", is_valid_age(25)), ("age 200", is_valid_age(200)), ("score 95", is_valid_score(95)), ("score 101", is_valid_score(101)), ("port 8080", is_valid_port(8080)), ("port 0", is_valid_port(0)),]for label, result in tests: print(f"{label}: {result}")Loading Python runtime (first run only)…