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

Weak References ใน Python (โมดูล weakref)

Weak Reference อ้างอิง Object แต่ ไม่เพิ่ม Reference Count Object ถูก Garbage Collect ได้ปกติ เหมาะสำหรับ Cache, Observer Pattern, Circular Reference Prevention

import weakref


คลาสและฟังก์ชันหลัก

Class/Functionคำอธิบาย
weakref.ref(obj[, callback])สร้าง Weak Reference เรียก ref() ได้ Object (หรือ None ถ้าถูก GC)
weakref.proxy(obj[, callback])สร้าง Proxy Object ใช้งานเหมือน Object จริง แต่อย่าง Weak
weakref.getweakrefcount(obj)นับ Weak References + Proxies
weakref.getweakrefs(obj)List ของ Weak References + Proxies
weakref.finalize(obj, func, *args, **kwargs)ลงทะเบียน Callback ตอน Object ถูก GC (3.4+)

โค้ดตัวอย่าง

import weakref

class MyList(list):
    pass

obj = MyList('String')  # ['S', 't', 'r', 'i', 'n', 'g']

# Weak Reference
weak_ref = weakref.ref(obj)
print(weak_ref())        # ['S', 't', 'r', 'i', 'n', 'g']

# Proxy
proxy = weakref.proxy(obj)
print(proxy)             # ['S', 't', 'r', 'i', 'n', 'g']

# Reference Count
print(weakref.getweakrefcount(obj))  # 2

# ลบ Original
del obj
print(weak_ref())        # None (Object ถูก GC แล้ว)

# Proxy หลัง GC -> ReferenceError
try:
    print(proxy)
except ReferenceError:
    print("Proxy: Object gone!")

ผลลัพธ์

['S', 't', 'r', 'i', 'n', 'g']
['S', 't', 'r', 'i', 'n', 'g']
2
None
Proxy: Object gone!

Callback on Deletion

import weakref

def cleanup(ref):
    print(f"Object {ref} has been garbage collected!")

obj = MyList('data')
ref = weakref.ref(obj, cleanup)
del obj
# Output: Object  has been garbage collected!

finalize() - ทันสมัยกว่า (Python 3.4+)

import weakref

class Resource:
    def __init__(self, name):
        self.name = name
    def close(self):
        print(f"Closing {self.name}")

res = Resource("DB Connection")
finalizer = weakref.finalize(res, res.close)

print(finalizer.alive)   # True
del res
print(finalizer.alive)   # False
# Output: Closing DB Connection

Objects ที่ไม่รองรับ Weak Reference

  • Built-in Types: int, float, str, tuple, bytes, frozenset
  • Built-in Functions/Methods
  • Classes ที่ Define __slots__ โดยไม่มี '__weakref__'

Use Cases จริง

1. Cache (ไม่ป้องกัน GC)

import weakref

class Cache:
    def __init__(self):
        self._cache = weakref.WeakValueDictionary()
    
    def get(self, key, factory):
        if key not in self._cache:
            self._cache[key] = factory(key)
        return self._cache[key]

# ใช้งาน
cache = Cache()
data = cache.get('user:1', lambda k: fetch_user(k))
# ถ้า data ไม่ถูกใช้ที่อื่น -> GC ได้อัตโนมัติ

2. Observer Pattern

class Subject:
    def __init__(self):
        self._observers = weakref.WeakSet()
    
    def register(self, observer):
        self._observers.add(observer)
    
    def notify(self, event):
        for obs in self._observers:
            obs.update(event)

3. Circular Reference Prevention

class Node:
    def __init__(self, value):
        self.value = value
        self.parent = None
        self.children = []
    
    def add_child(self, child):
        self.children.append(child)
        child.parent = weakref.ref(self)  # Weak Ref ป้องกัน Cycle

Weak Containers

  • WeakValueDictionary - Key=Strong, Value=Weak
  • WeakKeyDictionary - Key=Weak, Value=Strong
  • WeakSet - Elements=Weak
  • WeakMethod - Weak Reference to Bound Method (3.4+)