#33. Tra cứu thuộc tính

Tra cứu thuộc tính là quá trình chạy được sử dụng để đánh giá các biểu thức như:```python id="5ob0m9" obj.name


Mt biu thc thuc tính đơn gin có th kích hot mt lượng ln máy móc:```text id="b2zmcv"
find the object's type
search the type and its base classes
handle descriptors
check the instance dictionary
call custom attribute hooks
return a value or raise AttributeError
```Tra cứu thuộc tính là động. Kết quả có thể phụ thuộc vào đối tượng thời gian chạy, lớp của nó, các lớp cơ sở, từ điển cá thể, bộ mô tả, siêu dữ liệu và các hook do người dùng định nghĩa.

## 33.1 Truy cập thuộc tính cơ bản

Biểu thức:```python id="67bubm"
obj.x
```yêu cầu CPython tra cứu thuộc tính có tên`"x"`TRÊN`obj`.

Nếu tìm thấy, việc tra cứu sẽ trả về một đối tượng Python.

Nếu thiếu, nó sẽ tăng lên`AttributeError`.

Ví dụ:```python id="l53g0p"
class C:
    pass

obj = C()
obj.x = 10

print(obj.x)
```Cửa hàng nhiệm vụ`x`trong từ điển ví dụ:```text id="kz7fxs"
obj.__dict__["x"] = 10
```Việc truy cập tìm thấy nó ở đó.

## 33.2 Tra cứu thuộc tính không phải chỉ tra cứu từ điển

Đối với các đối tượng đơn giản, việc truy cập thuộc tính có thể giống như tra cứu từ điển:```python id="m2qolp"
obj.__dict__["x"]
```Nhưng việc tra cứu thuộc tính đầy đủ thì phức tạp hơn.

Biểu thức này:```python id="1v72yi"
obj.x
```có thể liên quan đến:```text id="h2b2fw"
data descriptors
instance dictionary
non-data descriptors
class attributes
base classes
__getattribute__
__getattr__
slots
properties
metaclass behavior
```Vì vậy, sự tương đương này là không đầy đủ:```python id="ue4afg"
obj.x == obj.__dict__["x"]
```Nó chỉ đúng trong những trường hợp đơn giản.

## 33.3 Từ điển sơ thẩm

Hầu hết các đối tượng Python bình thường đều có một từ điển mẫu.```python id="m08lyl"
class User:
    pass

u = User()
u.name = "Ada"
u.age = 37

print(u.__dict__)
```Đầu ra:```text id="7fbd65"
{'name': 'Ada', 'age': 37}
```Thuộc tính phiên bản được lưu trữ trong từ điển này trừ khi lớp sử dụng vị trí hoặc bố cục tùy chỉnh.

Vì:```python id="v04kyu"
u.name
```CPython có thể tìm thấy`"name"`TRONG`u.__dict__`.

Nhưng từ điển mẫu không phải lúc nào cũng được kiểm tra đầu tiên. Bộ mô tả dữ liệu trên lớp được ưu tiên.

## 33.4 Thuộc tính lớp

Các thuộc tính có thể tồn tại trên lớp.```python id="f16lwf"
class User:
    kind = "human"

u = User()
print(u.kind)
```Đây,`kind`không có trong`u.__dict__`. Nó ở trong`User.__dict__`.

Về mặt khái niệm:```text id="lpc7u3"
u.__dict__ does not contain "kind"
User.__dict__ contains "kind"
return "human"
```Thuộc tính lớp được chia sẻ thông qua lớp:```python id="qoumbj"
a = User()
b = User()

print(a.kind)
print(b.kind)
```Cả hai phiên bản đều nhìn thấy thuộc tính lớp giống nhau trừ khi một phiên bản che khuất nó.

## 33.5 Đánh bóng thuộc tính sơ thẩm

Một thuộc tính thể hiện có thể che khuất một thuộc tính lớp khi thuộc tính lớp không phải là bộ mô tả dữ liệu.```python id="g0f5q9"
class User:
    kind = "human"

u = User()
u.kind = "admin"

print(u.kind)
print(User.kind)
```Đầu ra:```text id="la6r0l"
admin
human
```Hiện nay:```text id="hoyjwm"
u.__dict__["kind"] = "admin"
User.__dict__["kind"] = "human"
```Thuộc tính instance thắng cho`u.kind`.

Đây là lý do tại sao các thuộc tính lớp nên được sử dụng cẩn thận cho các giá trị có thể thay đổi:```python id="bfuqvu"
class Bag:
    items = []

a = Bag()
b = Bag()

a.items.append("x")
print(b.items)
```Cả hai trường hợp đều thấy cùng một danh sách trừ khi`items`được ghi đè trên ví dụ.

## 33.6 Thứ tự tra cứu thuộc tính

Để truy cập thuộc tính phiên bản thông thường, thứ tự tra cứu đại khái là:```text id="vtge5s"
1. Call type(obj).__getattribute__(obj, name)
2. Search the class and base classes for name
3. If a data descriptor is found, call descriptor.__get__
4. Otherwise, check obj.__dict__
5. If found in obj.__dict__, return that value
6. Otherwise, if a non-data descriptor was found, call descriptor.__get__
7. Otherwise, if a class attribute was found, return it
8. Otherwise, call __getattr__ if defined
9. Otherwise, raise AttributeError
```Nguyên tắc ưu tiên quan trọng nhất là:```text id="rkgfxz"
data descriptor
    before instance dictionary

instance dictionary
    before non-data descriptor

non-data descriptor or class attribute
    after instance dictionary
```Thứ tự này giải thích các thuộc tính, phương thức, vị trí và tạo bóng.

## 33.7 Bộ mô tả

Bộ mô tả là một đối tượng kiểm soát quyền truy cập thuộc tính thông qua một hoặc nhiều phương thức đặc biệt:```text id="hh6upi"
__get__
__set__
__delete__
```Mô tả được lưu trữ trên các lớp.

Ví dụ:```python id="wgub37"
class Descriptor:
    def __get__(self, obj, cls):
        return "computed"

class C:
    x = Descriptor()

obj = C()
print(obj.x)
```Truy cập`obj.x`cuộc gọi:```python id="tbvfo8"
C.__dict__["x"].__get__(obj, C)
```Bộ mô tả cho phép các lớp tùy chỉnh ý nghĩa của việc truy cập thuộc tính.

Họ quyền lực:```text id="z7v9od"
methods
staticmethod
classmethod
property
slots
many built-in attributes
ORM fields
validation systems
lazy attributes
```## 33.8 Bộ mô tả dữ liệu

Bộ mô tả dữ liệu xác định`__set__`hoặc`__delete__`, thường với`__get__`.

```python id="lyqqpq"
class DataDescriptor:
    def __get__(self, obj, cls):
        return "from descriptor"

    def __set__(self, obj, value):
        print("set", value)

class C:
    x = DataDescriptor()

obj = C()
obj.__dict__["x"] = "from dict"

print(obj.x)
```Đầu ra:```text id="gvfbh3"
from descriptor
```Bộ mô tả chiếm ưu thế hơn từ điển cá thể vì nó là bộ mô tả dữ liệu.

Đây là cách`property`hoạt động.```python id="aqv8hu"
class C:
    @property
    def x(self):
        return 10

obj = C()
print(obj.x)
```Đối tượng thuộc tính là một bộ mô tả dữ liệu.

## 33.9 Bộ mô tả phi dữ liệu

Một bộ mô tả phi dữ liệu xác định`__get__`nhưng không`__set__`hoặc`__delete__`.

Các hàm Python thông thường được lưu trữ trên các lớp là các bộ mô tả phi dữ liệu.```python id="sz0xpl"
class C:
    def f(self):
        return "method"

obj = C()
print(obj.f())
```Bộ mô tả chức năng liên kết`obj`BẰNG`self`.

Nhưng vì nó không phải là dữ liệu nên một thuộc tính thể hiện có thể che khuất nó:```python id="o5g3nx"
obj.f = lambda: "instance function"
print(obj.f())
```Bây giờ từ điển cá thể sẽ thắng.

Đây là lý do tại sao các phương thức có thể được thay thế cho mỗi phiên bản.

## 33.10 Thuộc tính

Thuộc tính là một bộ mô tả gọi các hàm trong quá trình truy cập thuộc tính.```python id="78465u"
class Circle:
    def __init__(self, radius):
        self.radius = radius

    @property
    def area(self):
        return 3.14159 * self.radius * self.radius

c = Circle(10)
print(c.area)
```Biểu thức:```python id="vxxcx9"
c.area
```gọi trình thu thập tài sản.

Không có rõ ràng`()`trong nguồn vì lệnh gọi bị ẩn bên trong quyền truy cập của bộ mô tả.

Trình thiết lập thêm hành vi gán:```python id="b245cc"
class User:
    def __init__(self):
        self._name = ""

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value.strip()
```Phân công:```python id="acg7af"
u.name = " Ada "
```gọi trình thiết lập thuộc tính.

## 33.11 Các phương thức làm bộ mô tả

Các hàm được lưu trữ trên các lớp là các bộ mô tả.```python id="3l3xgm"
class C:
    def f(self):
        return 1

obj = C()
m = obj.f
```Việc tra cứu:```python id="fp1ymr"
obj.f
```gọi logic mô tả của đối tượng hàm và tạo ra một phương thức bị ràng buộc.

Về mặt khái niệm:```text id="1e8hzy"
C.__dict__["f"].__get__(obj, C)
    -> bound method
```Phương thức ràng buộc lưu trữ:```text id="257g0u"
function = C.f
self = obj
```Sau đó:```python id="jh0x78"
obj.f()
```gọi hàm với`self`tự động chèn vào.

## 33,12`staticmethod`Và`classmethod`

`staticmethod`Và`classmethod`là các trình bao bọc mô tả.

Một phương thức tĩnh vô hiệu hóa ràng buộc:```python id="hmwv5c"
class Math:
    @staticmethod
    def add(a, b):
        return a + b

Math.add(1, 2)
Math().add(1, 2)
```KHÔNG`self`hoặc`cls`được chèn vào.

Một phương thức lớp liên kết lớp:```python id="0p2qg1"
class User:
    @classmethod
    def make(cls):
        return cls()
```Gọi:```python id="jpqkoq"
User.make()
```vượt qua`User`như đối số đầu tiên.

Việc gọi thông qua một thể hiện cũng vượt qua lớp:```python id="x77e2w"
User().make()
```## 33,13 Máy đánh bạc`__slots__`thay đổi lưu trữ thuộc tính cá thể.```python id="q0q88q"
class Point:
    __slots__ = ("x", "y")

    def __init__(self, x, y):
        self.x = x
        self.y = y
```Trường hợp của`Point`thường không có bình thường`__dict__`trừ khi được yêu cầu rõ ràng.```python id="jmosbt"
p = Point(1, 2)
print(p.x)
```Các thuộc tính vị trí được triển khai bằng các bộ mô tả được lưu trữ trên lớp.

Về mặt khái niệm:```text id="cq58r6"
Point.__dict__["x"] = slot descriptor
Point.__dict__["y"] = slot descriptor
```Truy cập`p.x`gọi bộ mô tả vị trí, đọc từ một vị trí cố định trong bố cục đối tượng.

Các khe có thể giảm mức sử dụng bộ nhớ và tăng tốc một số kiểu truy cập thuộc tính, nhưng chúng cũng hạn chế các thuộc tính phiên bản động.

## 33.14 Thiếu thuộc tính

Nếu tra cứu thông thường không thành công, Python có thể gọi`__getattr__`.

```python id="r0ezoa"
class Dynamic:
    def __getattr__(self, name):
        if name == "answer":
            return 42
        raise AttributeError(name)

d = Dynamic()
print(d.answer)

__getattr__chỉ được gọi sau khi đường dẫn tra cứu thông thường không thành công.

Điều này hữu ích cho:text id="16oz5d" lazy loading proxy objects RPC clients compatibility layers dynamic APIs mock objects Nếu như__getattr__cũng thất bại, nó sẽ tăngAttributeError.

33,15__getattribute__

__getattribute__chặn tất cả quyền truy cập thuộc tính thông thường.```python id="k4hcdi" class Traced: def getattribute(self, name): print("lookup", name) return super().getattribute(name)

def f(self):
    return 1

obj = Traced() obj.f() ```Mọi truy cập đều đi qua__getattribute__, bao gồm cả tra cứu phương thức.

Việc triển khai tùy chỉnh phải tránh đệ quy vô hạn:python id="6fn49h" class Bad: def __getattribute__(self, name): return self.__dict__[name] Truy cậpself.__dict__cuộc gọi__getattribute__lại.

Sử dụngobject.__getattribute__hoặcsuper().__getattribute__:

class Good:
    def __getattribute__(self, name):
        return object.__getattribute__(self, name)
```## 33.16 Gán thuộc tính

Bài tập:```python id="in3koz"
obj.x = value
```sử dụng logic thiết lập thuộc tính.

Thứ tự đại khái :```text id="mya0tv"
1. Call type(obj).__setattr__(obj, name, value)
2. If a data descriptor with __set__ exists, use it
3. Otherwise, store into obj.__dict__ if available
4. Otherwise, use slot storage if applicable
5. Otherwise, raise AttributeError
```một phong tục`__setattr__` thể chặn bài tập:```python id="x89t2s"
class C:
    def __setattr__(self, name, value):
        print("set", name, value)
        super().__setattr__(name, value)

obj = C()
obj.x = 10
```Như với`__getattribute__`,  bất cẩn  thể tái diễn.

## 33.17 Xóa thuộc tính

Xóa:```python id="annac7"
del obj.x
```sử dụng logic xóa.

  thể gọi:```text id="wvs69o"
type(obj).__delattr__
descriptor.__delete__
remove from instance dictionary
clear slot value
``` tả  dụ:```python id="05vatk"
class D:
    def __delete__(self, obj):
        print("delete")

class C:
    x = D()

obj = C()
del obj.x
```Việc xóa  một phần của cùng một họ giao thức  tả  thuộc tính.

## 33.18 Tra cứu thuộc tính lớp

Các lớp cũng  đối tượng.```python id="n3g515"
class C:
    x = 10

print(C.x)
```Nhìn lên`C.x` quyền truy cập thuộc tính trên một đối tượng lớp.

Loại`C`thường `type`, do đó việc tra cứu thuộc tính lớp được kiểm soát bởi hành vi siêu dữ liệu.

Về mặt khái niệm:```text id="qro2hh"
object = C
type(object) = type
lookup attribute "x"
```Đây   do tại sao siêu dữ liệu  thể tùy chỉnh quyền truy cập thuộc tính cấp lớp.

## 33.19 Tra cứu thuộc tính siêu lớp

Siêu dữ liệu  thể xác định các thuộc tính hiển thị trên các lớp.```python id="2pzc6p"
class Meta(type):
    def meta_method(cls):
        return "meta"

class C(metaclass=Meta):
    pass

print(C.meta_method())
```Phương thức này được tìm thấy trên siêu dữ liệu  được liên kết với đối tượng lớp.

Tra cứu thuộc tính lớp bao gồm:```text id="3rcosr"
attributes on the class itself
descriptors in the metaclass
metaclass MRO
```Tra cứu siêu dữ liệu tách biệt với tra cứu  thể, nhưng  sử dụng cùng một  hình đối tượng chung.

## 33.20 Tra cứu thuộc tính mô-đun

Các -đun  từ điển thuộc tính.```python id="16mk8q"
import math
print(math.pi)
```Đại khái  thế này:```text id="iw6moh"
math.__dict__["pi"]
```Các -đun cũng  thể định nghĩa`__getattr__`đối với các thuộc tính bị thiếu.```python id="a4cpwz"
# module.py
def __getattr__(name):
    if name == "lazy":
        return load_lazy()
    raise AttributeError(name)
```Sau đó:```python id="pme0mb"
module.lazy
``` thể được tính toán một cách linh hoạt.

Tính năng này thường được sử dụng để nhập từng phần  các miếng chêm tương thích.

## 33.21 Tra cứu và kế thừa thuộc tính

Đối với các trường hợp, việc tra cứu lớp tuân theo thứ tự phân giải phương thức.```python id="nri7kz"
class A:
    x = "A"

class B(A):
    pass

obj = B()
print(obj.x)
```Tra cứu tìm kiếm:```text id="3gw1ky"
B
A
object
```Lệnh được lưu trữ trong:```python id="il7bpl"
print(B.__mro__)
```Đa kế thừa sử dụng tuyến tính hóa C3 để tính toán MRO nhất quán.```python id="iob9c0"
class A: pass
class B: pass
class C(A, B): pass

print(C.__mro__)
```Tra cứu thuộc tính dựa vào thứ tự này.

## 33.22 Tra cứu thuộc tính và`super`

`super()`thay đổi nơi bắt đầu tra cứu.```python id="plcgfy"
class Base:
    def f(self):
        return "base"

class Child(Base):
    def f(self):
        return super().f()
```Bên trong`Child.f`, `super().f`tìm kiếm sau`Child`trong MRO, sau đó liên kết phương thức tìm thấy với phiên bản gốc.

Về mặt khái niệm:```text id="zj3hcg"
MRO: Child, Base, object
super from Child
search Base, then object
bind result to self

super()không phải là truy cập lớp cha đơn giản. Đó là tra cứu mô tả tương đối MRO.

33.23 Tra cứu phương pháp đặc biệt

Các phương thức đặc biệt thường được tra cứu theo kiểu chứ không phải tra cứu thuộc tính thể hiện thông thường.

Ví dụ:python id="2r7t8j" len(obj) sử dụng khe độ dài của loại. Nó không chỉ đơn giản thực hiện:python id="5oiizr" obj.__len__() Sự khác biệt này quan trọng:```python id="76o4mf" class C: def len(self): return 10

obj = C() obj.len = lambda: 20

print(obj.len()) print(len(obj)) ```Cuộc gọi rõ ràng có thể tìm thấy thuộc tính instance. cáclen()hoạt động sử dụng phương pháp tra cứu đặc biệt thông qua kiểu.

Tra cứu phương pháp đặc biệt được thiết kế cho tốc độ và tính nhất quán của giao thức đối tượng.

33.24 Tra cứu thuộc tính trong Bytecode

Quyền truy cập thuộc tính biên dịch theo hướng dẫn mã byte, chẳng hạn như:text id="wifw5q" LOAD_ATTR STORE_ATTR DELETE_ATTR LOAD_METHOD Vì:python id="it1gq1" value = obj.x mã byte khái niệm:text id="gp7253" LOAD_FAST obj LOAD_ATTR x STORE_FAST value Vì:python id="6xdbsd" obj.x = value mã byte khái niệm:text id="id6s81" LOAD_FAST value LOAD_FAST obj STORE_ATTR x Đối với các cuộc gọi phương thức:```python id="qou4id" obj.f(arg)


## 33.25 Tra cứu thuộc tính có thể thực thi mã

Tra cu thuc tính không phi lúc nào cũng th động.

Biu thc này:```python id="i49h4b"
obj.x
```có th gi mã người dùng thông qua:```text id="tqt8ka"
__getattribute__
descriptor __get__
property getter
__getattr__
metaclass hooks
module __getattr__
```Do đó, quyn truy cp thuc tính có th:```text id="gq9mxu"
raise exceptions
mutate state
perform I/O
allocate objects
return different values each time
call arbitrary Python code
```Ví d:```python id="lqpgto"
class C:
    @property
    def x(self):
        print("computed")
        return 10

obj = C()
obj.x
obj.x
```Getter chy mi ln.

## 33.26 Tra cứu thuộc tính và ngoại lệ

Nếu thiếu mt thuc tính, Python s tăng`AttributeError`.

```python id="u5hs78"
obj.missing
```Nhưng vic tra cu thuc tính cũng có th đưa ra các ngoi l khác.

Ví d:```python id="yxnfz8"
class C:
    @property
    def x(self):
        raise RuntimeError("failed")

obj = C()
obj.x
```Điu này làm tăng`RuntimeError`, không`AttributeError`.

Ch nhng thuc tính còn thiếu mi nên nâng cao`AttributeError`. Các công c như`hasattr`ph thuc vào quy ước này.```python id="glsscx"
hasattr(obj, "x")
```hot động bng cách c gng tra cu và bt`AttributeError`.

## 33.27 Tra cứu thuộc tính và`hasattr`

`hasattr(obj, name)`tra cu thuc tính cuc gi.```python id="sf1vip"
hasattr(obj, "x")
```đại khái là:```python id="d7n5ls"
try:
    getattr(obj, "x")
except AttributeError:
    return False
else:
    return True
```Điu này có nghĩa`hasattr`có th thc thi mã người dùng.

Nếu mt người nhn tài sn tăng`RuntimeError`, `hasattr`không coi đó là thuc tính còn thiếu.```python id="6ci9p0"
class C:
    @property
    def x(self):
        raise RuntimeError("boom")

hasattr(C(), "x")
```các`RuntimeError`truyn bá.

## 33.28 Tra cứu thuộc tính và`getattr`

`getattr`thc hin tra cu thuc tính động.```python id="uk5dyw"
getattr(obj, "name")
```tương đương vi:```python id="qatskj"
obj.name
```khi tên thuc tính được biết đến mt cách tĩnh.

Nó cũng h tr mc định:```python id="l96rs7"
getattr(obj, "missing", default)
```Điu này tr v`default`ch khi tra cu tăng lên`AttributeError`.

Nó không loi b các ngoi l tùy ý t các b mô t hoc móc tra cu tùy chnh.

## 33.29 Tra cứu thuộc tính và`setattr`

`setattr`thc hin gán thuc tính động.```python id="j47b3p"
setattr(obj, "x", 10)
```tương đương vi:```python id="1q0s4t"
obj.x = 10
```cho mt tên tĩnh.

Nó vn tôn trng:```text id="amsxsl"
__setattr__
data descriptors
slots
read-only attributes
```Vì thế`setattr`không phi là mt t đin thô viết.

## 33.30 Tra cứu thuộc tính và`delattr`

`delattr`thc hin xóa thuc tính động.```python id="xe7qva"
delattr(obj, "x")
```tương đương vi:```python id="mbgk3j"
del obj.x
```Nó vn tôn trng:```text id="gnvxp9"
__delattr__
descriptor __delete__
slot deletion
instance dictionary deletion
```## 33.31 Tra cứu thuộc tính và bộ đệm nội tuyến

Vic tra cu thuc tính din ra thường xuyên nên CPython ti ưu hóa nó.

Truy cp lp li:```python id="xtr2dq"
for obj in objects:
    total += obj.value
```có th nhn cùng mt b cc thuc tính nhiu ln.

CPython có th đính kèm d liu b nh đệm ni tuyến vào lnh mã byte. B đệm có th lưu tr các s kin như:```text id="ooumb4"
expected receiver type
type version tag
dictionary version
descriptor result
slot offset
instance dictionary offset
```Trong các ln thc thi sau này:```text id="ylpgjg"
if guards still hold:
    use fast path
else:
    fall back to generic lookup
```Điu này bo tn ng nghĩa động trong khi tăng tc các trường hp n định.

## 33.32 Vô hiệu hóa bộ đệm

Python cho phép đột biến lp.```python id="uqb4tq"
class C:
    x = 1

obj = C()
print(obj.x)

C.x = 2
print(obj.x)
```Tra cu th hai phi xem`2`.

Do đó, b đệm thuc tính không th s dng li các kết qu cũ mt cách mù quáng. Nó phi đề phòng nhng thay đổi.

Nhng người bo v đin hình có th bao gm:```text id="1kbbj7"
type identity
type version
dictionary version
descriptor kind
instance layout
```Khi gi định không thành công, CPython s quay li tra cu chung và có th cp nht b đệm.

## 33.33 Độ ổn định của bố cục sơ thẩm

B đệm thuc tính hot động tt nht khi b cc đối tượng n định.

Ví d:```python id="cf08rl"
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

points = [Point(i, i + 1) for i in range(1000)]

for p in points:
    p.x
```Mi`p`có cùng loi và có th b trí thuc tính tương t. Đây là mt trường hp tt cho chuyên môn hóa.

Nhng thay đổi động có th làm gim hiu qu ca b đệm:```python id="nb80hw"
p.z = 10
del p.x
Point.x = property(...)
```Người phiên dch phi bo toàn tính chính xác trước tiên.

## 33.34 Tra cứu thuộc tính và từ điển

T đin phiên bn được ti ưu hóa cao.

T đin CPython là trung tâm ca không gian tên đối tượng:```text id="hr03df"
module namespace
class namespace
instance namespace
globals
builtins
```Đối vi nhiu đối tượng, vic tra cu thuc tính cui cùng tr thành vic tra cu t đin cng vi vic x lý b mô t.

B nh đệm thuc tính thường ph thuc vào phiên bn t đin để trình thông dch có th biết liu vùng tên có thay đổi hay không.

## 33.35 Tra cứu thuộc tính và mô-đun

Mô-đun toàn cu cũng da trên t đin.```python id="z6frja"
import math
math.sqrt
```Đối tượng mô-đun lưu tr các thuc tính trong t đin ca nó.

Vic tra cu mô-đun đơn gin hơn vic tra cu b mô t cá th trong nhiu trường hp, nhưng các mô-đun có th tùy chnh hành vi thuc tính b thiếu thông qua`__getattr__`.

Vic nhp cũng liên kết các thuc tính mô-đun:```python id="3y1uib"
import package.submodule
```Sau khi nhp, gói có th có`submodule`thuc tính.

## 33.36 Tra cứu thuộc tính và nội dung

Các loi tích hp thường s dng các mô t và b cc ni b chuyên bit.

Ví d:```python id="pswgfz"
list.append
dict.get
str.upper
int.bit_length
```Các thuc tính này thường là các b mô t phương thc được trin khai trong C.

Truy cp thông qua mt th hin:```python id="c2qhto"
[].append
```tr v mt đối tượng phương thc tích hp sn.

Các cuc gi ngay lp tc có th s dng đường dn cuc gi phương thc được ti ưu hóa.

## 33.37 Tra cứu thuộc tính và quản lý bộ nhớ

Tra cu thuc tính thao tác tham chiếu.

Khi mt thuc tính được tr v, CPython phi đảm bo kết qu vn tn ti.

Nếu vic tra cu to ra mt phương thc liên kết, kết qu thuc tính hoc kết qu mô t thì quyn s hu tham chiếu phi được x lý chính xác.

Các đối tượng tm thi có th được to trong quá trình tra cu:```text id="yd6imc"
bound methods
property return values
descriptor return values
exception objects
strings or proxy objects in custom hooks
```Đường dn tht bi phi làm sch chúng.

Vì tra cu thuc tính có th gi mã Python nên độ an toàn tham chiếu là rt quan trng.

## 33.38 Tra cứu thuộc tính và truy cập lại

Tra cu thuc tính có th nhp li Python.

Ví d:```python id="cjrgl2"
class C:
    def __getattribute__(self, name):
        return compute_value(name)
```Cuc gi đến`compute_value`có th thc thi mã Python tùy ý.

Điu này có nghĩa là trong mt ln tra cu thuc tính, mã Python có th:```text id="pbs3p5"
mutate the object
mutate the class
change descriptors
trigger garbage collection
raise exceptions
call back into the same object
```Vic thc hin tra cu phi chp nhn điu này.

## 33.39 Tra cứu thuộc tính và proxy

Các đối tượng proxy thường trin khai tra cu thuc tính tùy chnh.```python id="gmm0jz"
class Proxy:
    def __init__(self, target):
        self._target = target

    def __getattr__(self, name):
        return getattr(self._target, name)
```Sau đó:```python id="t9wo3d"
proxy.x
```đại biu ti:```python id="mwraoc"
target.x
```Mt proxy mnh m phi x lý các phương thc đặc bit mt cách cn thn vì vic tra cu phương thc đặc bit tim n thường b qua vic tra cu thuc tính phiên bn thông thường.

Ví d, vic trin khai`__getattr__`mt mình có th không làm được`len(proxy)`y quyn cho`len(target)`.

## 33.40 Tra cứu thuộc tính và ORM

Nhiu ORM s dng mô t.

Hình dng ví d:```python id="9lk1n2"
class Field:
    def __get__(self, obj, cls):
        return obj._data[self.name]

    def __set__(self, obj, value):
        obj._data[self.name] = value

class User:
    name = Field()
```Sau đó:```python id="gygh09"
user.name
```không đọc mt thuc tính đơn gin. Nó gi`Field.__get__`.

Điu này cho phép các thư vin trin khai:```text id="m7h3nv"
validation
lazy loading
database column mapping
change tracking
computed fields
relationship loading
```B mô t biến cú pháp thuc tính thành quyn truy cp có th lp trình.

## 33.41 Tra cứu thuộc tính và các lớp dữ liệu

Các lp d liu v cơ bn không thay đổi vic tra cu thuc tính.```python id="itowya"
from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int
```Các phiên bn thường lưu tr các trường trong t đin phiên bn tr khi các v trí được bt.```python id="2es6x4"
p = Point(1, 2)
print(p.x)
```Đây là tra cu thuc tính cá th thông thường.

Vi các khe:```python id="zkk0iv"
@dataclass(slots=True)
class Point:
    x: int
    y: int
```lưu tr trường s dng các v trí thay vì t đin phiên bn thông thường.

## 33.42 Tra cứu thuộc tính và loại đối tượng

Các loi là các đối tượng và chúng cũng có các thuc tính.```python id="veiddt"
int.bit_length
str.upper
dict.items
```Đây là các thuc tính trên các đối tượng loi.

Khi tra cu các thuc tính trên các phiên bn, kiu tra cu ca phiên bn s điu khin.

Khi tra cu các thuc tính trên các lp, siêu d liu s điu khin vic tra cu.

Mô hình đối tượng đệ quy này là trung tâm ca Python:```text id="7jbz3r"
object has type
type is also an object
type has metaclass
metaclass controls class attribute lookup
```## 33.43 Tra cứu thuộc tính và hiệu suất

Quyn truy cp thuc tính có nhiu chi phí hơn quyn truy cp biến cc b.

So sánh:```python id="2vbgf5"
x
```bên trong mt hàm,  đâu`x`là địa phương:```text id="quibql"
LOAD_FAST
```vi:```python id="h0qo06"
obj.x
```đòi hi:```text id="p6kgjq"
LOAD_FAST obj
LOAD_ATTR x

LOAD_ATTRcó thể liên quan đến logic mô tả, tra cứu từ điển, kiểm tra bộ đệm, kiểm tra phiên bản loại và xử lý lỗi.

Đây là lý do tại sao các vòng lặp nóng đôi khi được hưởng lợi từ liên kết cục bộ:```python id="3tqoir" append = xs.append for item in items: append(item)


## 33.44 Tra cứu thuộc tính và lỗi trong đường dẫn nóng

Li tra cu thuc tính tương đối tn kém vì nó to ra mt ngoi l.

Ví d:```python id="uacsdx"
try:
    value = obj.missing
except AttributeError:
    value = default
```Đối vi nhng ln nh thường xuyên, s dng t đin hoc công c canh gác rõ ràng có th nhanh hơn.

Nhưng thiết kế tt nht ph thuc vào ng nghĩa. Li tra cu thuc tính là chính xác và thành ng khi s vng mt là đặc bit hoc khi tương tác vi các API động.

## 33.45 Kiểm tra tra cứu thuộc tính

s dng`vars`để kim tra các t đin mu:```python id="pqoskd"
class C:
    pass

obj = C()
obj.x = 1

print(vars(obj))
```S dng t đin lp:```python id="zw539h"
print(C.__dict__)
```S dng MRO:```python id="oqmr19"
print(C.__mro__)
```S dng`inspect.getattr_static`để kim tra các thuc tính mà không kích hot tra cu động thông thường trong nhiu trường hp:```python id="kb22m2"
import inspect

inspect.getattr_static(obj, "x")
```Điu này rt hu ích khi mô t hoc`__getattr__`s thc thi mã.

## 33.46 Mô hình tra cứu thuộc tính tối thiểu

Mt mô hình tra cu đơn gin:```python id="rjhnk7"
def lookup(obj, name):
    cls = type(obj)

    class_attr = find_in_mro(cls, name)

    if is_data_descriptor(class_attr):
        return class_attr.__get__(obj, cls)

    if hasattr(obj, "__dict__") and name in obj.__dict__:
        return obj.__dict__[name]

    if has_get(class_attr):
        return class_attr.__get__(obj, cls)

    if class_attr is not missing:
        return class_attr

    getattr_hook = find_in_mro(cls, "__getattr__")
    if getattr_hook is not missing:
        return getattr_hook(obj, name)

    raise AttributeError(name)
```Điu này b qua các chi tiết thc tế quan trng:```text id="vn6j5o"
custom __getattribute__
metaclasses
slots internals
C-level fast paths
reference counts
inline caches
error handling
module lookup
special method lookup
```Nhưng nó nm bt được th t ưu tiên ca b mô t thông thường.

## 33.47 Những hiểu lầm phổ biến

| Hiu lm | Đúng mu |
|---|---|
|`obj.x`luôn đọc`obj.__dict__["x"]`| B mô t d liu, v trí, thuc tính lp và móc có th can thip |
| Các phương thc được lưu tr trên mi phiên bn | Các phương thc thông thường được lưu tr trên lp và b ràng buc trong quá trình tra cu |
| Thuc tính là các trường | Thuc tính là các b mô t gi hàm |
|`__getattr__`x lý mi tra cu | Nó ch chy sau khi tra cu thông thường không thành công |
|`__getattribute__`ch x lý các thuc tính b thiếu | Nó x lý tt c các truy cp thuc tính thông thường |
| Thuc tính phiên bn luôn đánh bi thuc tính lp | B mô t d liu đánh bi các thuc tính cá th |
| Các phương pháp đặc bit luôn s dng tra cu thông thường | Nhiu người được tra cu thông qua các khe loi |
| Quyn truy cp thuc tính không có tác dng ph | Nó có th thc thi mã Python tùy ý |

## 33,48 Chiến lược đọc

Để nghiên cu tra cu thuc tính, hãy xây dng các ví d theo th t sau:```python id="xp7o07"
class C:
    x = 1
```Sau đó thêm:```python id="jdu7zp"
obj.x = 2
```Sau đó thêm mt phương thc:```python id="yzo90g"
def f(self): ...
```Sau đó thay thế nó bng:```python id="nku86v"
@property
def x(self): ...
```Sau đó thêm:```python id="6ho4rb"
__getattr__
__getattribute__
__slots__
staticmethod
classmethod
multiple inheritance
metaclass
```Đối vi mi bước, hãy kim tra:```python id="eaahv5"
vars(obj)
C.__dict__
C.__mro__
type(obj)
```Và tháo ri các trang web truy cp:```python id="xhk4lr"
import dis

def read(obj):
    return obj.x

dis.dis(read)
```Điu này xây dng mt bn đồ thc tế t cú pháp đến hành vi ca mô hình đối tượng.

## 33.49 Tóm tắt chương

Tra cu thuc tính là cơ chế đằng sau`obj.name`. Nó là mt giao thc động liên quan đến loi đối tượng, t đin lp, t đin cá th, b mô t, tính kế tha, móc tùy chnh, v trí, mô-đun, siêu d liu và b đệm ni tuyến.

Ưu tiên tra cu ct lõi cho các thuc tính phiên bn thông thường là:```text id="t5lrtf"
data descriptor
instance dictionary
non-data descriptor
class attribute
__getattr__
AttributeError
```Th t này gii thích các phương thc, thuc tính, to bóng, v trí và nhiu mu khung.

CPython ti ưu hóa rt nhiu vic tra cu thuc tính bng các đường dn mã byte chuyên dng và b nh đệm ni tuyến, nhưng nó phi bo toàn ng nghĩa động ca Python. Các lp có th thay đổi, các th hin có th thay đổi, b mô t có th chy mã và các hook tùy chnh có th ghi đè toàn b quá trình.