43. 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 trên một đối tượng khác. Bộ mô tả là một trong những cơ chế chính đằng sau mô hình đối tượng của Python. Chúng giải thích cách các phương thức liên kết với các thể hiện, cáchpropertyhoạt động như thế nàostaticmethodclassmethodhoạt động, cách các khe hoạt động và số lượng thao tác loại cấp CPython kết nối với cú pháp cấp Python.

Ở cấp độ ngôn ngữ, bộ mô tả là bất kỳ đối tượng nào xác định một hoặc nhiều phương thức sau:python id="x7hcrg" __get__(self, obj, objtype=None) __set__(self, obj, value) __delete__(self, obj) Một vật thể có__get__là một mô tả.

Một vật thể có__set__hoặc__delete__là một bộ mô tả dữ liệu.

Sự khác biệt giữa bộ mô tả không phải dữ liệu và bộ mô tả dữ liệu kiểm soát mức độ ưu tiên tra cứu.

43.1 Tại sao bộ mô tả tồn tại

Truy cập thuộc tính Python trông đơn giản:python id="96l8i5" obj.name Nhưng biểu thức này không có nghĩa là “đọc một trường có tênnametừ trí nhớ.”

Nó có nghĩa là:```text id="drqc0j" ask the object's type how attribute lookup works search descriptors and dictionaries in a defined order possibly call descriptor methods return the resulting object


Ví d:```python id="tkau0z"
obj.method
obj.property_name
Class.class_method
Class.static_method
obj.slot_name
```Tt c nhng điu này liên quan đến hành vi mô t.

## 43.2 Giao thức mô tả cơ bản

Mt b mô t xác định`__get__`.

```python id="ct8qxy"
class Descriptor:
    def __get__(self, obj, objtype=None):
        return "computed value"
```S dng nó như mt thuc tính lp:```python id="d0fypg"
class Example:
    value = Descriptor()

e = Example()

print(e.value)
```Đầu ra:```text id="qz34l2"
computed value
```Đối tượng mô t được lưu tr trên lp:```python id="csuohy"
print(Example.__dict__["value"])
```Nhưng truy cp thuc tính thông qua các cuc gi cá th`Descriptor.__get__`.

## 43.3 Đối số mô tả

Phương thc mô t nhn được:

| Lp lun | Ý nghĩa |
|---|---|
|`self`| Đối tượng mô t |
|`obj`| Phiên bn đang được truy cp, hoc`None`để truy cp lp hc |
|`objtype`| Lp ch s hu |

Ví d:```python id="v4lvjg"
class Descriptor:
    def __get__(self, obj, objtype=None):
        print("obj:", obj)
        print("objtype:", objtype)
        return 42

class Example:
    value = Descriptor()

e = Example()

print(e.value)
print(Example.value)
```Để truy cp ví d:```text id="by7jq8"
obj: <__main__.Example object at ...>
objtype: <class '__main__.Example'>
```Để truy cp lp:```text id="k4ktgr"
obj: None
objtype: <class '__main__.Example'>
```Mt b mô t có th s dng s khác bit này để tr v các giá tr khác nhau cho vic truy cp phiên bn và lp.

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

Mt b mô t phi d liu xác định`__get__`, nhưng không`__set__`hoc`__delete__`.

```python id="hb1iji"
class NonDataDescriptor:
    def __get__(self, obj, objtype=None):
        return "descriptor value"
```Ví d:```python id="bvccxu"
class Example:
    value = NonDataDescriptor()

e = Example()

print(e.value)
```Đầu ra:```text id="j61t3h"
descriptor value
```Nhưng vì nó là mt b mô t phi d liu nên mt mc t đin mu có th ghi đè lên nó:```python id="vu3t3a"
e.__dict__["value"] = "instance value"

print(e.value)
```Đầu ra:```text id="6xj4jn"
instance value
```Quyn ưu tiên này là có ch ý. Đó là cách các phương thc thông thường có th b che khut bi các thuc tính cá th.

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

B mô t d liu xác định`__set__`hoc`__delete__`.

```python id="rk5sgr"
class DataDescriptor:
    def __get__(self, obj, objtype=None):
        return "descriptor value"

    def __set__(self, obj, value):
        print("setting", value)
```Ví d:```python id="c9rzsd"
class Example:
    value = DataDescriptor()

e = Example()
e.__dict__["value"] = "instance value"

print(e.value)
```Đầu ra:```text id="m34bnr"
descriptor value
```B mô t d liu chiến thng t đin cá th.

Quy tc này rt quan trng đối vi`property`.

## 43.6 Độ ưu tiên tra cứu

Để truy cp thuc tính cá th thông thường:```python id="ynllax"
obj.name
```Vic tra cu đối tượng ca CPython đại khái tuân theo th t sau:```text id="rpb90z"
1. Look for name on the type or base types.
2. If found and it is a data descriptor, call its __get__.
3. Look in the instance dictionary.
4. If found on the type and it is a non-data descriptor, call its __get__.
5. If found on the type as a normal attribute, return it.
6. If not found, call __getattr__ if defined.
7. Otherwise raise AttributeError.
```Th t này gii thích ti sao mt s thuc tính lp có th b che khut bi các thuc tính th hin còn nhng thuc tính khác thì không.

## 43.7 Ví dụ về mức độ ưu tiên của bộ mô tả```python id="n4y91b"
class NonData:
    def __get__(self, obj, objtype=None):
        return "non-data descriptor"

class Data:
    def __get__(self, obj, objtype=None):
        return "data descriptor"

    def __set__(self, obj, value):
        raise AttributeError("read-only")

class Example:
    a = NonData()
    b = Data()

e = Example()
e.__dict__["a"] = "instance a"
e.__dict__["b"] = "instance b"

print(e.a)
print(e.b)
```Đầu ra:```text id="0dzdun"
instance a
data descriptor

abị che khuất vì nó là một bộ mô tả phi dữ liệu.bkhông bị che khuất vì nó là bộ mô tả dữ liệu.

43.8 Hàm là 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="4040yq" class Example: def method(self): return 42

e = Example()

print(Example.dict["method"]) print(e.method)


Đối tượng được tr v bi quyn truy cp cá th là mt phương thc b ràng buc.```text id="j0sg2u"
function object stored on class
     __get__(instance, class)
bound method object
```Đây là lý do ti sao:```python id="r1yoxy"
e.method()
```vượt qua`e`như đối s đầu tiên.

## 43.9 Liên kết phương thức

Hành vi mô t ca hàm có th được mô hình hóa như thế này:```python id="rrmwg4"
class FunctionLike:
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return BoundMethod(self, obj)
```Phương thc ràng buc lưu tr:```text id="9ac6b1"
function
instance
```Gi phương thc ràng buc:```python id="zs0r2l"
e.method(1, 2)
```gn tương đương vi:```python id="0jmqjg"
Example.method(e, 1, 2)
```Đây không phi là cú pháp đặc bit trong trình phân tích cú pháp. Đó là tra cu thuc tính thông thường cng vi ràng buc mô t cng vi lnh gi.

## 43.10 Lớp truy cập vào các phương thức

Khi được truy cp thông qua lp, b mô t hàm s nhn được`obj=None`.

```python id="c1o0cb"
class Example:
    def method(self):
        return 42

print(Example.method)
```Kết qu là đối tượng ging hàm ban đầu, không phi là mt phương thc b ràng buc vi mt th hin.

Vì vy, điu này hot động:```python id="ce7spz"
e = Example()

print(Example.method(e))
```Ví d được thông qua mt cách rõ ràng.

## 43.11 Đối tượng phương thức ràng buộc

Mt đối tượng phương thc b ràng buc hin th các thuc tính hu ích:```python id="0hd310"
class Example:
    def method(self):
        return 42

e = Example()
m = e.method

print(m.__self__)
print(m.__func__)

__self__là trường hợp bị ràng buộc.__func__là chức năng cơ bản.

Về mặt khái niệm:text id="9rhbma" bound_method.__self__ -> e bound_method.__func__ -> Example.__dict__["method"] Gọi:python id="r7sscl" m() cuộc gọi:python id="sqt0vq" m.__func__(m.__self__) ## 43,12property

propertylà một bộ mô tả dữ liệu.```python id="o83sqw" class User: def init(self, name): self._name = name

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

Truy cập:python id="q15uwm" u = User("Ada") print(u.name)


Mt mô hình thô:```python id="e1wqf0"
class property:
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)
```Bi vì`property`định nghĩa`__set__`, nó là mt b mô t d liu. Nó chiến thng t đin cá th.

## 43.13 Thuộc tính chỉ đọc

Thuc tính ch đọc vn hot động như mt b mô t d liu.```python id="bjmyqo"
class Example:
    @property
    def value(self):
        return 42

e = Example()
e.__dict__["value"] = 100

print(e.value)
```Đầu ra:```text id="8qw90w"
42
```Mc dù thuc tính không có setter,`property`loi có`__set__`hành vi gây ra li. Điu đó làm cho nó tr thành mt b mô t d liu.

## 43.14 Thuộc tính có thể ghi

Thuc tính có th ghi thêm mt setter.```python id="7362gp"
class User:
    def __init__(self):
        self._name = ""

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

    @name.setter
    def name(self, value):
        if not value:
            raise ValueError("empty name")
        self._name = value
```Cách s dng:```python id="ly2z3r"
u = User()
u.name = "Ada"
print(u.name)
```Phân công:```python id="pzyvzj"
u.name = "Ada"
```gi b mô t`__set__`.

Nó không ch đơn gin là viết`u.__dict__["name"]`.

## 43,15`staticmethod`

`staticmethod`là mt b mô t ngăn chn ràng buc phương thc.```python id="7h9gwf"
class Math:
    @staticmethod
    def add(a, b):
        return a + b

print(Math.add(2, 3))
print(Math().add(2, 3))
```Trong c hai trường hp, không có phiên bn nào được chèn làm đối s đầu tiên.

Mt mô hình thô:```python id="k4n2sv"
class staticmethod:
    def __init__(self, func):
        self.func = func

    def __get__(self, obj, objtype=None):
        return self.func

staticmethodlưu trữ một chức năng và trả về nó không thay đổi.

43,16classmethod

classmethodlà một bộ mô tả liên kết lớp thay vì thể hiện.```python id="m0y4q8" class User: @classmethod def create(cls): return cls()

u = User.create() Một mô hình thô:python id="vn2wvc" class classmethod: def init(self, func): self.func = func

def __get__(self, obj, objtype=None):
    if objtype is None:
        objtype = type(obj)
    return BoundMethod(self.func, objtype)

Gọi:python id="cn0iaw" User.create() gần tương đương với:python id="mzdvxl" User.dict["create"].get(None, User)() cuộc gọi nào:python id="mgiurn" original_function(User) ```## 43,17__slots__và mô tả__slots__sử dụng các bộ mô tả để quản lý các thuộc tính thể hiện bố cục cố định.

Ví dụ:```python id="tv0e9k" class Point: slots = ("x", "y")

def __init__(self, x, y):
    self.x = x
    self.y = y

Từ điển lớp chứa các bộ mô tả vị trí:python id="ziiwfx" print(Point.dict["x"]) print(Point.dict["y"])


Vi các khe cm, các phiên bn bình thường có th không có`__dict__`tr khi được yêu cu rõ ràng.```python id="mv07bu"
p = Point(1, 2)

print(hasattr(p, "__dict__"))
```Đầu ra:```text id="drcrll"
False
```## 43.18 Bộ mô tả thành viên và Bộ mô tả Getset

CPython hin th mt s b mô t cp độ C dưới dng đối tượng.

Các ví d ph biến:```text id="vtr7cq"
member_descriptor
getset_descriptor
wrapper_descriptor
method_descriptor
```Bn có th thy chúng trong t đin lp hc:```python id="7ln1br"
class Point:
    __slots__ = ("x",)

print(type(Point.__dict__["x"]))
```Đối vi các loi tích hp:```python id="inwepf"
print(type(int.__dict__["real"]))
print(type(str.__dict__["upper"]))
print(type(object.__dict__["__str__"]))
```Đây là các đối tượng mô t cp CPython bao bc hành vi cp C.

## 43.19 Bộ mô tả và gán thuộc tính

Đối vi nhim v:```python id="4ja4xk"
obj.name = value
```CPython không phi lúc nào cũng ghi vào`obj.__dict__`.

Nếu loi có b mô t d liu cho`name`, phép gán gi b mô t`__set__`.

Ví d:```python id="2t9ndx"
class Descriptor:
    def __set__(self, obj, value):
        print("set", value)

class Example:
    x = Descriptor()

e = Example()
e.x = 10
```Đầu ra:```text id="jfd4bi"
set 10
```Không cn viết t đin phiên bn thông thường.

## 43.20 Bộ mô tả và xóa thuộc tính

Để xóa:```python id="mxpuzk"
del obj.name
```Nếu mt b mô t d liu xác định`__delete__`, CPython gi nó.```python id="wuc0pw"
class Descriptor:
    def __delete__(self, obj):
        print("delete")

class Example:
    x = Descriptor()

e = Example()
del e.x
```Đầu ra:```text id="fkv43g"
delete
```Nếu không, vic xóa có th xóa mt mc khi t đin mu hoc nâng cao`AttributeError`.

## 43,21`__set_name__`Bộ mô tả có thể xác định`__set_name__`.

```python id="yvbjoc"
class Field:
    def __set_name__(self, owner, name):
        self.owner = owner
        self.name = name

class User:
    id = Field()
    name = Field()
```Trong quá trình to lp, Python gi:```text id="zf52ho"
User.__dict__["id"].__set_name__(User, "id")
User.__dict__["name"].__set_name__(User, "name")
```Điu này cho phép b mô t tìm hiu tên thuc tính mà chúng được gán.

Không có`__set_name__`, các b mô t thường yêu cu cu hình d phòng:```python id="k9fsdd"
id = Field("id")
name = Field("name")
```## 43.22 Bộ mô tả xác thực thực tế```python id="okxfod"
class PositiveInt:
    def __set_name__(self, owner, name):
        self.name = "_" + name

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return getattr(obj, self.name)

    def __set__(self, obj, value):
        if not isinstance(value, int):
            raise TypeError("expected int")
        if value <= 0:
            raise ValueError("expected positive integer")
        setattr(obj, self.name, value)
```Cách s dng:```python id="u85219"
class User:
    age = PositiveInt()

    def __init__(self, age):
        self.age = age

u = User(30)
print(u.age)
```Nhim v:```python id="7h7peb"
self.age = age
```cuc gi`PositiveInt.__set__`.

Quyn truy cp:```python id="jvsgys"
u.age
```cuc gi`PositiveInt.__get__`.

## 43.23 Lựa chọn lưu trữ mô tả

B mô t thường lưu tr các giá tr theo tng phiên bn  mt nơi khác.

Các la chn ph biến:

| Lưu tr | Ví d | Đánh đổi |
|---|---|---|
| T đin sơ thm |`obj.__dict__[name]`| Đơn gin, đòi hi`__dict__`|
| Thuc tính riêng |`obj._name`| Đơn gin, có th va chm |
| T đin khóa yếu |`WeakKeyDictionary[obj]`| Hot động mà không cn chm vào lnh chính t, chi phí cao hơn |
| Khe bù đắp | CPython ni b | B cc nhanh, c định |
| Ca hàng bên ngoài | Bng ORM/phiên/trng thái | Hu ích cho các framework |

Mt đối tượng mô t thường được chia s bi lp, do đó vic lưu tr d liu c th ca cá th trc tiếp trên b mô t thường là sai.

Xu:```python id="httjyo"
class BadField:
    def __set__(self, obj, value):
        self.value = value
```Tt c các phiên bn chia s mt đối tượng mô t.

Tt hơn:```python id="qgjw4l"
class Field:
    def __set_name__(self, owner, name):
        self.name = "_" + name

    def __set__(self, obj, value):
        setattr(obj, self.name, value)
```## 43.24 Chia sẻ mô tả

Mt b mô t được lưu tr trên lp.```python id="poo2z7"
class Field:
    pass

class User:
    name = Field()
```Có mt cái`Field`đối tượng cho`User.name`.

Tt c`User`các trường hp truy cp vào cùng mt đối tượng mô t.```python id="ghzk97"
print(User.__dict__["name"])
```Đây là lý do ti sao trng thái mô t phi được thiết kế cn thn.

Trng thái cp độ mô t phù hp cho:```text id="lzdzy9"
field name
validation rule
default configuration
metadata
owner class
```Trng thái cp độ phiên bn thuc v phiên bn hoc trong kho lưu tr theo phiên bn bên ngoài.

## 43.25 Bộ mô tả và kế thừa

Các b mô t được kế tha ging như các thuc tính lp khác.```python id="07zg83"
class Field:
    def __get__(self, obj, objtype=None):
        return "value"

class Base:
    x = Field()

class Child(Base):
    pass

print(Child().x)
```Đầu ra:```text id="23j8kz"
value
```Tra cu tìm kiếm th t phân gii phương pháp. Nếu mt b mô t được tìm thy trong lp cơ s, nó s tham gia truy cp thuc tính cho các th hin con.

Mt lp con có th ghi đè b mô t bng cách xác định cùng tên.```python id="jgv5bi"
class Child(Base):
    x = 100
```Hin nay:```python id="a343w1"
print(Child().x)
```tr v:```text id="sbrd9y"
100
```tr khi áp dng các quy tc tra cu khác.

## 43.26 Bộ mô tả và`super`

`super()`cũng s dng liên kết mô t.

Ví d:```python id="klco94"
class Base:
    def method(self):
        return "base"

class Child(Base):
    def method(self):
        return super().method()
```Biu thc:```python id="vz6j6v"
super().method
```tìm thy`method`trên lp tiếp theo trong MRO và liên kết nó vi phiên bn gc.

Ràng buc đó vn s dng logic mô t.

## 43.27 Bộ mô tả và`__getattribute__`Tất cả quyền truy cập thuộc tính bình thường đều phải trải qua`__getattribute__`.

```python id="0h0zfk"
obj.name
```gi đại khái là:```python id="wrm9c8"
type(obj).__getattribute__(obj, "name")
```Vic thc hin mc định,`object.__getattribute__`, thc hin tra cu mô t.

Nếu mt lp ghi đè`__getattribute__`, nó có th thay đổi hoc b qua hành vi ca b mô t.

Ví d:```python id="6hlojz"
class Example:
    @property
    def x(self):
        return 42

    def __getattribute__(self, name):
        return "intercepted"

e = Example()
print(e.x)
```Đầu ra:```text id="i8f18x"
intercepted
```Tài sn không bao gi đạt được bi vì`__getattribute__`chn mi th.

## 43.28 Bộ mô tả và`__getattr__`

`__getattr__`ch được gi sau khi tra cu thông thường không thành công.```python id="1tg4g8"
class Example:
    def __getattr__(self, name):
        return "missing"

e = Example()
print(e.anything)
```Đầu ra:```text id="cafj83"
missing
```Nếu mt b mô t tn ti và tr v mt giá tr,`__getattr__`không được gi.

Th t tra cu:```text id="hpfu2m"
__getattribute__ runs first
descriptor rules happen inside normal __getattribute__
__getattr__ handles missing names only
```## 43.29 Bộ mô tả và siêu lớp

Quyn truy cp thuc tính lp cũng s dng logic mô t, nhưng đối tượng đang được tìm kiếm là đối tượng lp.```python id="6g2hvo"
class Meta(type):
    @property
    def label(cls):
        return cls.__name__.lower()

class User(metaclass=Meta):
    pass

print(User.label)
```Đây,`label`là mt mô t trên siêu d liu. Truy cp`User.label`gi tra cu mô t trên`type(User)`.

Đây là lý do ti sao siêu d liu có th định nghĩa các thuc tính lp được tính toán.

## 43.30 Tra cứu mô tả trên các lớp

Dành cho:```python id="bugwo3"
Class.attr
```tra cu được x lý bi`type.__getattribute__`.

Vic tìm kiếm din ra trên đối tượng lp và siêu d liu ca nó.

Nếu mt thuc tính trong siêu d liu là mt b mô t, nó có th liên kết vi lp làm đối tượng.

Đây là cách`classmethod`, thuc tính siêu d liu và nhiu thao tác kiu tích hp hot động.

Tra cu lp và tra cu cá th có liên quan nhưng không ging nhau. Tra cu phiên bn tìm kiếm MRO ca loi phiên bn. Tìm kiếm tra cu lp thông qua máy móc siêu d liu.

## 43.31 Bộ mô tả trong ORM

B mô t là ph biến trong ORM.

Hình dng ví d:```python id="gs116j"
class Column:
    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return obj._row[self.name]

    def __set__(self, obj, value):
        obj._row[self.name] = value
```Cách s dng:```python id="3gj06d"
class User:
    id = Column()
    name = Column()

    def __init__(self, row):
        self._row = row
```Sau đó:```python id="e6nz6o"
u = User({"id": 1, "name": "Ada"})
print(u.name)
u.name = "Grace"
```B mô t ánh x quyn truy cp thuc tính vào b lưu tr hàng.

## 43.32 Bộ mô tả trong Thư viện xác thực

Các khung xác thc s dng các b mô t để thc thi các ràng buc.```python id="kcyh88"
class String:
    def __set_name__(self, owner, name):
        self.storage = "_" + name

    def __set__(self, obj, value):
        if not isinstance(value, str):
            raise TypeError("expected str")
        setattr(obj, self.storage, value)

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return getattr(obj, self.storage)
```Cách s dng:```python id="4vl57c"
class User:
    name = String()

    def __init__(self, name):
        self.name = name
```Định nghĩa lp khai báo trường. B mô t thc thi quy tc.

## 43.33 Bộ mô tả trong tính toán được lưu trong bộ nhớ đệm

Thuc tính được lưu trong b nh đệm là mt b mô t phi d liu.```python id="yh220g"
class cached_property:
    def __init__(self, func):
        self.func = func
        self.name = func.__name__

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self

        value = self.func(obj)
        obj.__dict__[self.name] = value
        return value
```Cách s dng:```python id="kxogrn"
class Data:
    @cached_property
    def total(self):
        print("computing")
        return 100

d = Data()
print(d.total)
print(d.total)
```Quyn truy cp đầu tiên gi b mô t và lưu tr giá tr trong t đin mu.

Quyn truy cp th hai tr v giá tr t đin mu vì b mô t không phi là d liu.

Điu này ph thuc trc tiếp vào quyn ưu tiên ca b mô t.

## 43.34 Quy tắc thiết kế dữ liệu và phi dữ liệu

S dng b mô t d liu khi b mô t phi kim soát vic ghi hoc không được ghi đè bi các thuc tính phiên bn.

S dng b mô t không phi d liu khi mun lưu vào b nh đệm hoc theo dõi cp phiên bn.

| Loi mô t | Định nghĩa | Instance dict có th ghi đè? | Ví d ph biến |
|---|---|---:|---|
| B mô t phi d liu |`__get__`ch | Có | chc năng, thuc tính được lưu tr |
| B mô t d liu |`__set__`hoc`__delete__`| Không | thuc tính, v trí, trường xác thc |

S khác bit này gii thích nhiu hành vi truy cp thuc tính.

## 43,35 Khe nội bộ CPython dành cho bộ mô tả

 cp độ C, hành vi ca b mô t được th hin thông qua các khe kiu.

Các hot động liên quan tương ng vi:```text id="3v2e6f"
tp_descr_get
tp_descr_set
```Mt loi thc hin`tp_descr_get`có th hành động như th nó có`__get__`.

Mt loi thc hin`tp_descr_set`có th hành động như th nó có`__set__`hoc`__delete__`.

Các b mô t tích hp thường là các đối tượng C có loi cung cp các v trí này.

Đây là cách các phương thc tích hp, b mô t v trí, b mô t getset và b mô t trình bao bc tích hp vi tra cu Python thông thường.

## 43.36 Tra cứu thuộc tính trong thuật ngữ CPython

Tra cu cp độ CPython được đơn gin hóa cho`obj.name`:

```text id="m04p6t"
1. type = Py_TYPE(obj)
2. descr = lookup name in type MRO
3. if descr has tp_descr_get and tp_descr_set:
       return descr.__get__(obj, type)
4. if obj has dict and name in dict:
       return dict[name]
5. if descr has tp_descr_get:
       return descr.__get__(obj, type)
6. if descr exists:
       return descr
7. call fallback or raise AttributeError
```Đây là trung tâm hot động ca b mô t.

## 43.37 Lỗi mô tả

Mô t nên nâng cao`AttributeError`đối vi các thuc tính b thiếu khi h mun hành vi d phòng thuc tính thông thường.

Ví d:```python id="xeje8w"
class Maybe:
    def __get__(self, obj, objtype=None):
        raise AttributeError("not available")
```Mt mô t làm tăng`AttributeError`có th tương tác vi`getattr`, `hasattr`và cơ chế d phòng.

Đưa ra các ngoi l chính xác. Đừng giu nhng li không liên quan vì`AttributeError`tr khi thuc tính đó thc s không có sn.

## 43.38 Mô tả Nội tâm

Để kim tra mt b mô t, hãy truy cp nó thông qua t đin lp.```python id="047r6b"
class Example:
    @property
    def value(self):
        return 42

print(Example.__dict__["value"])
```Truy cp thông qua lp có th gi`__get__`:

```python id="2rtf24"
print(Example.value)
```Vì`property`, quyn truy cp lp tr v đối tượng thuc tính. Nhưng các b mô t khác có th tr v các giá tr được tính toán.

Cách an toàn nht để truy xut b mô t thô thường là:```python id="gvvuc9"
vars(Example)["value"]
```hoc:```python id="h6m1qm"
Example.__dict__["value"]
```## 43.39 Các lỗi mô tả phổ biến

| Li | Nguyên nhân | Sa cha |
|---|---|---|
| Tt c các phiên bn đều có chung mt giá tr | Trng thái phiên bn được lưu tr trên b mô t | Lưu tr trng thái trên phiên bn hoc bn đồ theo phiên bn bên ngoài |
| Thuc tính b lp tùy chnh b qua | ghi đè`__getattribute__`sai | y quyn cho`object.__getattribute__`|
| Thuc tính được lưu trong b nh đệm không được lưu vào b đệm | B mô t là b mô t d liu | Làm cho nó không phi là d liu hoc viết logic ưu tiên tùy chnh |
| Thuc tính sơ thm không th ghi đè trường | B mô t xác định`__set__`| S dng b mô t không phi d liu nếu mun ghi đè |
| B mô t thiếu tên trường | Không thc hin`__set_name__`| Thêm vào`__set_name__`hoc truyn tên mt cách rõ ràng |
| Ngh truy cp lp hc |`__get__`không x lý`obj is None`| B mô t tr v hoc đối tượng cp lp |

## 43,40 Điểm chính

B mô t là các đối tượng xác định`__get__`, `__set__`, hoc`__delete__`.

Mt b mô t phi d liu xác định`__get__`ch mt.

B mô t d liu xác định`__set__`hoc`__delete__`.

B mô t d liu được ưu tiên hơn các t đin mu.

Các b mô t phi d liu có th b che khut bi các t đin mu.

Hàm là b mô t, đó là lý do ti sao các phương thc liên kết vi các th hin.`property`, `staticmethod`, `classmethod`, v trí, phương thc tích hp và nhiu phn bên trong CPython s dng b mô t.

B mô t được trin khai trong CPython thông qua các khe mô t trên các đối tượng kiu.

Cn phi hiu các b mô t để hiu các phương thc, thuc tính, v trí, siêu d liu và tra cu thuc tính.