2.33. Introspection

Một số hàm built-in cho phép chương trình đang chạy tự kiểm tra bản thân -- các giá trị nó đang làm việc, các namespace mà những giá trị đó tồn tại, và mối quan hệ giữa các lớp. Hãy dùng chúng khi bạn cần đưa ra quyết định dựa trên những gì một đối tượng thực sự là, chứ không phải những gì caller của nó tuyên bố.

2.33.1. Định danh và băm

  • id() -- một số nguyên duy nhất xác định một đối tượng trong suốt thời gian nó còn sống. Hai tên gắn kết với cùng một đối tượng trả về cùng id; hai đối tượng bằng nhau nhưng khác nhau thì không.

>>> a = [1, 2, 3]
>>> b = a
>>> c = [1, 2, 3]
>>> id(a) == id(b)        # same list
True
>>> id(a) == id(c)        # equal but distinct
False

Id không thể di chuyển giữa các lần chạy và không có ý nghĩa gì ngoài "cùng đối tượng hay đối tượng khác".

  • hash() -- giá trị băm của một đối tượng, cùng số mà dictset sử dụng để tra cứu nó. Hai đối tượng bằng nhau băm ra cùng giá trị; chỉ các kiểu có thể băm (các giá trị bất biến, phần lớn) mới hoạt động.

>>> hash("abc")           # some integer, build-dependent
-1600925533
>>> hash([1, 2])
TypeError: unhashable type: 'list'

2.33.2. Truy vấn kiểu và khả năng gọi

  • type() -- lớp chính xác của một giá trị. type(x) is int hỏi "x có phải chính xác là int không" (không có lớp con); isinstance() thường là thứ bạn muốn thay thế.

  • isinstance() -- "x có phải là instance của lớp này, hoặc lớp con của nó không?" Công cụ tiêu chuẩn để dispatch dựa trên kiểu bên trong các hàm.

  • issubclass() -- đối tác ở cấp lớp. Nhận hai lớp thay vì một instance.

  • callable() -- True nếu đối số có thể được gọi với (). Hữu ích khi bạn nhận một đối số có thể là một hàm hoặc có thể là một giá trị đơn thuần.

>>> isinstance(3, int)
True
>>> isinstance(True, int)        # bool is a subclass of int
True
>>> issubclass(bool, int)
True
>>> callable(len)
True
>>> callable(10)
False

Một mẫu sử dụng callable:

def call_or_return(x):
    return x() if callable(x) else x

2.33.3. Xem xét các phạm vi

  • globals() -- namespace toàn cục của module dưới dạng dict. Đọc từ nó hoạt động; ghi vào nó là thật, nhưng làm vậy bên ngoài khám phá REPL khiến chương trình khó theo dõi.

  • locals() -- namespace cục bộ tại call site. Bên trong một hàm nó phản ánh các biến cục bộ; sửa đổi dict được trả về không được đảm bảo ghi lại vào locals thực tế (hành vi được định nghĩa bởi implementation).

name = "OpenMV"

def f():
    x = 10
    print(globals()["name"])    # OpenMV
    print(locals())             # {'x': 10}

Hai hàm này hữu ích để debug và cho các công cụ cần khám phá những gì được định nghĩa. Hãy dùng chúng một cách thận trọng trong code thông thường -- một hàm thay đổi globals() là một trong những thứ khó lý giải nhất trong Python.

2.33.4. Xem thêm

dir()help(), được đề cập trong debugging, là các công cụ introspection hàng ngày để khám phá bề mặt của một đối tượng không quen thuộc.