Weak reference trong Python là một cơ chế cho phép giữ một tham chiếu yếu tới một đối tượng mà không ngăn cản đối tượng đó bị thu hồi bộ nhớ khi không còn tham chiếu mạnh. Việc sử dụng tham chiếu yếu giúp quản lý bộ nhớ hiệu quả hơn trong các ứng dụng có yêu cầu tối ưu hóa việc thu hồi bộ nhớ. Trong bài viết này, chúng ta sẽ tìm hiểu cách thức hoạt động của weak reference, các tình huống sử dụng, và cách tạo và quản lý chúng thông qua các công cụ như module weakref
, callback functions, và các loại từ điển đặc biệt như WeakKeyDictionary và WeakValueDictionary.
Điểm chính cần nắm
- Weak reference trong Python là gì?: Giải thích khái niệm weak reference trong Python và sự khác biệt giữa weak reference và strong reference.
- Khi nào nên dùng weak reference?: Các trường hợp và tình huống phù hợp để sử dụng weak reference trong lập trình Python.
- Tạo weak reference với module weakref: Hướng dẫn sử dụng module
weakref
để tạo weak reference.- Tạo weak reference bằng weakref.ref(): Cách sử dụng
weakref.ref()
để tạo weak reference cho đối tượng. - Sử dụng weakref.proxy(): Cách tạo weak reference bằng
weakref.proxy()
để truy cập đối tượng một cách an toàn.
- Tạo weak reference bằng weakref.ref(): Cách sử dụng
- Sử dụng callback function với weak reference: Cách sử dụng callback function để thực hiện hành động khi weak reference bị thu hồi.
- Quản lý vòng đời object với weakref.finalize: Giới thiệu về
weakref.finalize
để tự động thực hiện hành động khi đối tượng không còn được tham chiếu. - WeakKeyDictionary và WeakValueDictionary trong Python: Giới thiệu về hai loại từ điển
WeakKeyDictionary
vàWeakValueDictionary
trong Python, giúp quản lý bộ nhớ hiệu quả.- WeakKeyDictionary: Mô tả cách sử dụng từ điển với các khóa tham chiếu yếu.
- WeakValueDictionary: Mô tả cách sử dụng từ điển với các giá trị tham chiếu yếu.
- Vietnix – Nhà cung cấp dịch vụ lưu trữ uy tín, tốc độ và bảo mật: Giới thiệu về dịch vụ lưu trữ và máy chủ của Vietnix, một đơn vị cung cấp dịch vụ uy tín tại Việt Nam.
Weak reference trong Python là gì?
Weak reference trong Python là một loại tham chiếu đặc biệt đến một object nhưng không làm tăng số lượng tham chiếu của object đó. Nghĩa là nếu không còn strong reference nào trỏ đến object, garbage collector có thể thu hồi bộ nhớ của object ngay cả khi vẫn còn weak reference trỏ đến.
Python sử dụng cơ chế đếm tham chiếu để quản lý bộ nhớ. Mỗi khi một object được tham chiếu, bộ đếm tham chiếu của nó sẽ tăng lên. Ngược lại, khi một tham chiếu bị loại bỏ, bộ đếm sẽ giảm đi. Nếu garbage collector phát hiện một object có bộ đếm tham chiếu bằng 0, object đó sẽ bị xóa và bộ nhớ được thu hồi.

Weak reference không bảo vệ object khỏi việc bị thu gom rác. Điều này đặc biệt hữu ích khi cần triển khai cache cho các object lớn hoặc khi muốn giảm thiểu vấn đề tham chiếu vòng (circular reference) trong chương trình.
Khi nào nên dùng weak reference?
Weak reference hữu ích trong các trường hợp sau:
- Quản lý bộ nhớ hiệu quả: Giúp tránh giữ các object không cần thiết trong bộ nhớ.
- Giảm vấn đề circular reference: Trong một số trường hợp, các object có thể tham chiếu lẫn nhau, gây khó khăn cho garbage collector. Weak reference giúp hạn chế điều này.
- Tạo cache linh hoạt: Weak reference có thể được dùng để tạo bộ nhớ đệm (cache) cho các object lớn, đảm bảo chúng chỉ tồn tại khi có ít nhất một strong reference.
Tạo weak reference với module weakref
Để tạo các tham chiếu yếu trong Python, chúng ta sử dụng module weakref
. Lớp ref
trong module này quản lý tham chiếu yếu tới một đối tượng. Khi được gọi, nó sẽ truy xuất đối tượng gốc. Khi không còn strong reference nào trỏ đến đối tượng gốc, garbage collector sẽ thu hồi bộ nhớ và weak reference sẽ trở thành None
.
1. Tạo weak reference bằng weakref.ref()
Class ref
trong module weakref
giúp tạo một weak reference đến object. Để tạo một tham chiếu yếu:
weakref.ref(class())
Ví dụ:
import weakref
class MyClass:
def __del__(self):
print('(Deleting {})'.format(self))
# Tạo object và weak reference
obj = MyClass()
r = weakref.ref(obj)
# In ra object, weak reference và gọi weak reference
print('object:', obj)
print('reference:', r)
print('call r():', r())
# Xóa object gốc
print('deleting obj')
del obj
# Kiểm tra lại weak reference sau khi object bị xóa
print('r():', r())
Khi gọi đối tượng tham chiếu sau khi xóa đối tượng tham chiếu gốc (referent), kết quả trả về là None.
Kết quả:
object: <__main__.MyClass object at 0x7f33fa474310>
reference: <weakref at 0x7f33fa4c74c0; to ‘MyClass’ at 0x7f33fa474310>
call r(): <__main__.MyClass object at 0x7f33fa474310>
deleting obj
(Deleting <__main__.MyClass object at 0x7f33fa474310>)
r(): None
Giải thích:
- Trước khi xóa
obj
: Weak referencer()
trả về đối tượng gốc. - Sau khi xóa
obj
: Weak referencer()
trả vềNone
, vì đối tượng đã bị thu hồi bởi garbage collector.
2. Sử dụng weakref.proxy()
Nếu muốn sử dụng weak reference giống như một object bình thường, có thể dùng weakref.proxy()
.
Ví dụ:
import weakref
class MyClass:
def __init__(self, name):
self.name = name
def show(self):
print(f"Hello, tôi là {self.name}")
obj = MyClass("Python")
proxy_obj = weakref.proxy(obj) # Tạo proxy object
proxy_obj.show() # Gọi method thông qua proxy
del obj # Xóa strong reference
# proxy_obj.show() # Nếu gọi sau khi obj bị xóa, sẽ báo lỗi ReferenceError
Lưu ý:
weakref.proxy()
giúp truy cập object như bình thường, nhưng khi object bị xóa, việc gọi proxy sẽ gây lỗi ReferenceError
.
Kết quả:
Hello, tôi là Python
Traceback (most recent call last):
File “<stdin>”, line 12, in <module>
ReferenceError: weakly-referred object no longer exists
Giải thích:
- Trước khi xóa
obj
: Khi gọiproxy_obj.show()
, đối tượngobj
vẫn tồn tại vàproxy_obj
hoạt động như một proxy, giúp gọi phương thứcshow
của đối tượng gốc. - Sau khi xóa
obj
: Khi gọiproxy_obj.show()
sau khiobj
đã bị xóa, một lỗiReferenceError
sẽ xảy ra, vì đối tượng gốc đã không còn tồn tại, vàproxy_obj
không thể tham chiếu đến một đối tượng đã bị thu hồi bộ nhớ.
Sử dụng callback function với weak reference
Python cung cấp khả năng sử dụng callback function với weak reference để thực hiện một hành động khi đối tượng mà weak reference trỏ tới bị xóa. Điều này rất hữu ích trong các trường hợp bạn muốn thực hiện một hành động bổ sung (như ghi log, thông báo, v.v.) khi một đối tượng bị thu hồi bộ nhớ.
Khi tạo weak reference, ta có thể truyền một hàm callback vào tham số callback
trong constructor của lớp weakref.ref()
. Hàm callback này sẽ được gọi khi đối tượng gốc bị xóa.
Ví dụ:
import weakref
class MyClass:
def __init__(self, name):
self.name = name
def __del__(self):
print(f"(Deleting {self.name})")
# Hàm callback được gọi khi đối tượng bị xóa
def my_callback(weak_ref):
print(f"Object {weak_ref} has been garbage collected.")
# Tạo object và weak reference với callback
obj = MyClass("Python")
weak_obj = weakref.ref(obj, my_callback)
# Kiểm tra weak reference và gọi đối tượng
print(f"Object: {obj}")
print(f"Reference: {weak_obj}")
print(f"Calling weakref: {weak_obj()}")
# Xóa object gốc
del obj
# Kiểm tra lại weak reference sau khi object bị xóa
print(f"After deletion, weakref: {weak_obj()}")
Kết quả:
Object: <__main__.MyClass object at 0x7f33fa474310>
Reference: <weakref at 0x7f33fa4c74c0; to ‘MyClass’ at 0x7f33fa474310>
Calling weakref: <__main__.MyClass object at 0x7f33fa474310>
(Deleting Python)
Object <__main__.MyClass object at 0x7f33fa474310> has been garbage collected.
After deletion, weakref: None
Giải thích:
- Trong ví dụ này,
my_callback
là một hàm callback được gọi khi đối tượngobj
bị xóa. - Hàm callback nhận vào tham số là weak reference (
weak_ref
), và khi đối tượng mà weak reference trỏ tới bị xóa, hàm callback sẽ được gọi. - Sau khi
del obj
được gọi, đối tượng bị xóa và callback function in ra thông báo rằng đối tượng đã bị thu hồi bộ nhớ.
Lưu ý
Callback function chỉ được gọi khi đối tượng thực sự bị garbage collected. Vì vậy, khi weak reference trỏ đến một đối tượng và không còn strong reference nào, callback sẽ được kích hoạt khi bộ thu gom rác chạy và đối tượng bị xóa khỏi bộ nhớ.
Quản lý vòng đời object với weakref.finalize
Python cung cấp weakref.finalize()
để giúp bạn quản lý vòng đời của đối tượng. weakref.finalize()
cho phép bạn chỉ định một hàm sẽ được gọi khi đối tượng mà bạn đang theo dõi bị thu hồi bộ nhớ. Đây là một cách hữu ích để thực hiện các hành động dọn dẹp hoặc làm sạch khi đối tượng bị hủy.
Lớp finalize
cho phép bạn đăng ký một hàm “finalizer” (hàm xử lý dọn dẹp) mà sẽ được gọi ngay khi đối tượng bị garbage collected (tức là bị thu hồi bộ nhớ). Bạn có thể truyền bất kỳ tham số nào cho hàm finalizer, và nó sẽ được gọi khi đối tượng không còn được tham chiếu nữa.
Cách sử dụng weakref.finalize
- Tạo một object và đăng ký finalizer để thực hiện các hành động dọn dẹp khi đối tượng bị hủy.
- Hàm finalizer sẽ được gọi khi đối tượng bị xóa khỏi bộ nhớ (do garbage collector).
Ví dụ:
import weakref
class MyClass:
def __init__(self, name):
self.name = name
def __del__(self):
print(f"(Deleting {self.name})")
# Hàm finalizer được gọi khi đối tượng bị hủy
def my_finalizer(*args):
print(f"Finalizer called with arguments: {args}")
# Tạo đối tượng và sử dụng weakref.finalize
obj = MyClass("Python")
finalizer = weakref.finalize(obj, my_finalizer, "Object is being garbage collected")
# Kiểm tra trạng thái đối tượng
print(f"Object: {obj}")
print(f"Finalizer: {finalizer}")
# Xóa đối tượng và kiểm tra lại
del obj
# Sau khi xóa đối tượng, finalizer sẽ được gọi
Kết quả:
Object: <__main__.MyClass object at 0x7f33fa474310>
Finalizer: <finalize object at 0x7f33fa4c74c0; for ‘MyClass’ at 0x7f33fa474310>
(Deleting Python)
Finalizer called with arguments: (‘Object is being garbage collected’,)
Giải thích:
weakref.finalize()
đăng ký một hàm finalizer để được gọi khi đối tượngobj
bị garbage collected (khi không còn strong references trỏ đến nó).- Trong ví dụ này,
my_finalizer
sẽ in ra thông báo khi đối tượng bị xóa và thu hồi bộ nhớ. - Sau khi
del obj
được gọi, đối tượngobj
bị hủy vàmy_finalizer
được gọi với tham số"Object is being garbage collected"
. - Khi đối tượng bị xóa, bạn sẽ thấy thông báo từ cả phương thức
__del__()
trong classMyClass
và từ hàm finalizer.
Lưu ý
weakref.finalize()
không đảm bảo rằng finalizer sẽ được gọi ngay lập tức sau khi đối tượng bị xóa. Nó sẽ được gọi khi garbage collector thu hồi bộ nhớ cho đối tượng đó.- Bạn có thể đăng ký nhiều finalizers cho một đối tượng, và các finalizers này sẽ được gọi khi đối tượng bị hủy.
WeakKeyDictionary và WeakValueDictionary trong Python
Trong Python, weakref
module cung cấp các lớp WeakKeyDictionary
và WeakValueDictionary
để quản lý từ điển mà các khóa hoặc giá trị trong đó đều được tham chiếu yếu. Điều này có nghĩa là, nếu không còn strong references trỏ đến các khóa hoặc giá trị, chúng sẽ tự động bị garbage collector thu hồi.
1. WeakKeyDictionary
WeakKeyDictionary
là một loại từ điển trong đó các khóa (keys) được tham chiếu yếu. Điều này có nghĩa là khi không còn strong reference nào trỏ đến một khóa trong dictionary, khóa đó và các giá trị tương ứng sẽ bị loại bỏ khỏi từ điển tự động.
- Ưu điểm: Giúp giảm thiểu việc giữ lại các đối tượng không cần thiết trong bộ nhớ, đặc biệt khi các đối tượng này có thể không được sử dụng trong thời gian dài.
- Khi nào sử dụng: Thường được sử dụng trong các ứng dụng cần cache với khóa là các đối tượng, và khi các khóa này có thể bị thu hồi bộ nhớ nếu không còn được sử dụng.
Ví dụ:
import weakref
class Person:
def __init__(self, person_id, name, age):
self.person_id = person_id
self.name = name
self.age = age
def __repr__(self):
return f"{self.person_id}: {self.name}, {self.age}"
# Tạo các đối tượng Person
person1 = Person(1, "Vientix", 30)
person2 = Person(2, "Jane", 25)
person3 = Person(3, "Jack", 35)
# Tạo WeakKeyDictionary với Person instances làm keys
weak_dict = weakref.WeakKeyDictionary({person1: person1.name, person2: person2.name, person3: person3.name})
# In ra nội dung của WeakKeyDictionary
print("WeakKeyDictionary:", weak_dict)
# Kiểm tra keys trong dictionary
print("Dictionary Keys:", [key().name for key in weak_dict.keyrefs()])
# Xóa một strong reference và kiểm tra lại keys
del person1
print("After deleting person1, Keys:", [key().name for key in weak_dict.keyrefs()])
Kết quả:
WeakKeyDictionary: {<weakref at 0x7f5b50d4e5e0; to ‘Person’ at 0x7f5b50d3b5e0>: ‘Vientix’, <weakref at 0x7f5b50d4e780; to ‘Person’ at 0x7f5b50d3b7c0>: ‘Jane’, <weakref at 0x7f5b50d4e9a0; to ‘Person’ at 0x7f5b50d3b9a0>: ‘Jack’}
Dictionary Keys: [‘Vientix’, ‘Jane’, ‘Jack’]
After deleting person1, Keys: [‘Jane’, ‘Jack’]
Giải thích:
- Weak Key Dictionary: Khi không còn strong reference nào trỏ đến khóa, như trong trường hợp của
Person1
, khóa này và giá trị tương ứng sẽ bị loại bỏ tự động khỏi dictionary. - keyrefs(): Trả về danh sách các tham chiếu yếu tới các khóa trong từ điển. Khi
Person1
bị xóa, khóa này không còn trong từ điển nữa.
2. WeakValueDictionary
WeakValueDictionary
là một loại từ điển trong đó các giá trị (values) được tham chiếu yếu. Điều này có nghĩa là khi không còn strong reference nào trỏ đến một giá trị trong từ điển, giá trị đó sẽ bị loại bỏ khỏi từ điển tự động.
- Ưu điểm: Giúp giảm thiểu việc giữ lại các đối tượng không cần thiết trong bộ nhớ, đặc biệt khi các giá trị có thể không còn được sử dụng sau khi chúng không còn trong các references khác.
- Khi nào sử dụng: Thường được sử dụng khi bạn muốn lưu trữ các giá trị mà không muốn các đối tượng này ngăn cản việc thu hồi bộ nhớ.
Ví dụ:
import weakref
class Vientix:
def __init__(self, person_id, name, age):
self.person_id = person_id
self.name = name
self.age = age
def __repr__(self):
return f"{self.person_id}: {self.name}, {self.age}"
# Tạo các đối tượng Vientix
vientix1 = Vientix(1, "John", 30)
vientix2 = Vientix(2, "Jane", 25)
vientix3 = Vientix(3, "Jack", 35)
# Tạo WeakValueDictionary với Vientix name làm key và Vientix object làm giá trị
weak_dict = weakref.WeakValueDictionary({vientix1.name: vientix1, vientix2.name: vientix2, vientix3.name: vientix3})
# In ra nội dung của WeakValueDictionary
print("WeakValueDictionary:", weak_dict)
# Kiểm tra các giá trị trong dictionary
print("Dictionary Values:", [value().name for value in weak_dict.valuerefs()])
# Xóa một strong reference và kiểm tra lại values
del vientix1
print("After deleting vientix1, Values:", [value().name for value in weak_dict.valuerefs()])
Kết quả:
WeakValueDictionary: {“John”: <weakref at 0x7f5b50d4e680; to “Vientix” at 0x7f5b50d3b640>, “Jane”: <weakref at 0x7f5b50d4e6a0; to “Vientix” at 0x7f5b50d3b700>, “Jack”: <weakref at 0x7f5b50d4e6c0; to “Vientix” at 0x7f5b50d3b7a0>}
Dictionary Values: [“John”, “Jane”, “Jack”]
After deleting vientix1, Values: [“Jane”, “Jack”]
Giải thích:
Weak Value Dictionary: Đây là loại từ điển lưu trữ các giá trị với tham chiếu yếu. Khi không còn strong reference nào trỏ đến một giá trị, giá trị đó sẽ tự động bị loại bỏ khỏi từ điển.
valuerefs(): Phương thức này trả về các tham chiếu yếu tới các giá trị trong từ điển. Sau khi xóa
vientix1
, giá trị “John” sẽ không còn trong từ điển nữa.Tạo mới và thêm đối tượng: Khi thêm
vientix4
, giá trị mới sẽ được thêm vào từ điển và có thể truy xuất thông quavaluerefs()
.
Vietnix – Nhà cung cấp dịch vụ lưu trữ uy tín, tốc độ và bảo mật
Vietnix hiện đang là một trong những nhà cung cấp hàng đầu tại Việt Nam về dịch vụ cho thuê máy chủ (server), hosting, VPS và tên miền. Với mục tiêu cung cấp giải pháp lưu trữ hiệu quả và bảo mật cao, Vietnix cam kết mang đến dịch vụ chất lượng vượt trội và đội ngũ hỗ trợ kỹ thuật chuyên nghiệp 24/7. Hơn 80.000 khách hàng đã tin tưởng lựa chọn Vietnix nhờ vào dịch vụ cho thuê máy chủ đáng tin cậy, giúp tối ưu hóa hiệu suất và bảo mật dữ liệu cho doanh nghiệp.
Thông tin liên hệ:
- Website: https://vietnix.vn/
- Hotline: 18001093
- Email: sales@vietnix.com.vn
- Địa chỉ: 265 Hồng Lạc, Phường 10, Quận Tân Bình, TP. Hồ Chí Minh.
Câu hỏi thường gặp
Weak reference có thể làm việc với các đối tượng không thể thay đổi (immutable objects) không?
Weak reference có thể hoạt động với các đối tượng không thể thay đổi như string hoặc tuple, nhưng cần lưu ý rằng các đối tượng này thường không được thay đổi sau khi tạo nên việc sử dụng weak reference sẽ ít hữu ích.
Các công cụ hoặc thư viện nào hỗ trợ tốt khi làm việc với weak reference trong Python?
Các thư viện như weakref
, collections
(với WeakValueDictionary
, WeakKeyDictionary
) là những công cụ hữu ích khi làm việc với weak reference trong Python.
Có thể sử dụng weak reference với các đối tượng thuộc các lớp kế thừa trong Python không?
Weak reference hoàn toàn có thể sử dụng với các đối tượng thuộc lớp kế thừa. Tuy nhiên, cần chú ý rằng các lớp kế thừa có thể gặp phải các vấn đề với các đối tượng được kế thừa mà không kiểm soát tốt.
weakref.finalize
có thể giúp gì trong việc quản lý vòng đời của các đối tượng?
weakref.finalize
giúp bạn đăng ký các hành động cần thực hiện khi đối tượng bị thu hồi bộ nhớ. Đây là công cụ mạnh mẽ để dọn dẹp bộ nhớ hoặc thực hiện các tác vụ dọn dẹp khi đối tượng không còn sử dụng nữa.
Lời kết
Qua bài viết, chúng ta đã khám phá cách thức hoạt động của weak reference và ứng dụng của nó trong Python. Từ việc tạo weak reference, sử dụng callback function cho đến việc quản lý vòng đời đối tượng, tất cả đều giúp tối ưu hóa việc sử dụng bộ nhớ và tài nguyên hệ thống. Hy vọng rằng những kiến thức này sẽ hỗ trợ bạn trong việc phát triển các ứng dụng Python hiệu quả hơn. Nếu bạn có bất kỳ thắc mắc nào, đừng ngần ngại để lại câu hỏi, mình sẽ hỗ trợ nhanh nhất. Cảm ơn bạn đã đọc!