PHP
Python

Trang chủ

Tìm hiểu về weak reference trong Python: Cách sử dụng và ứng dụng

Ngôn ngữ Python là một ngôn ngữ lập trình đa mục đích, nổi tiếng với cú pháp dễ đọc, dễ học và tính ứng dụng cao. Trong lĩnh vực phát triển web, Python thường được sử dụng thông qua các framework như Django và Flask để xây dựng các ứng dụng web mạnh mẽ, bảo mật và dễ mở rộng. Trong chuyên mục này, Vietnix không chỉ cung cấp kiến thức nền tảng về ngôn ngữ Python mà còn hướng dẫn chi tiết cách xây dựng các ứng dụng web thực tế, sử dụng các framework phổ biến và áp dụng các kỹ thuật tiên tiến. Vietnix cam kết liên tục cập nhật những bài viết mới nhất về các tính năng mới của Python, các thư viện hỗ trợ hữu ích và những phương pháp tốt nhất, giúp bạn khai thác tối đa sức mạnh của Python và hoàn thiện kỹ năng lập trình web của mình.
html
CSS
javascript
sql
python
php
c
c++
bootstrap
react
mysql
reactjs
vuejs
Javascript Tutorials
21/03/2025
18 phút đọc
Theo dõi Vietnix trên

Tìm hiểu về weak reference trong Python: Cách sử dụng và ứng dụng

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.
  • 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 WeakKeyDictionaryWeakValueDictionary 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 trong Python
Weak reference trong Python

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 reference r() trả về đối tượng gốc.
  • Sau khi xóa obj: Weak reference r() 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ọi proxy_obj.show(), đối tượng obj vẫn tồn tại và proxy_obj hoạt động như một proxy, giúp gọi phương thức show của đối tượng gốc.
  • Sau khi xóa obj: Khi gọi proxy_obj.show() sau khi obj đã bị xóa, một lỗi ReferenceError 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ượng obj 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ớ.

iconLư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

  1. Tạo một objectđăng ký finalizer để thực hiện các hành động dọn dẹp khi đối tượng bị hủy.
  2. 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ượng obj 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ượng obj 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 class MyClass và từ hàm finalizer.

iconLư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 WeakKeyDictionaryWeakValueDictionary để 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 qua valuerefs().

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, VPStê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!

Cao Lê Viết Tiến

PHP Leader
tại
Vietnix

Kết nối với mình qua

Icon Quote
Icon Quote

Học lập trình online cùng vietnix

Học lập trình online cùng Vietnix

PHPXem thêmThu gọn