44. Lớp và siêu lớp

Một lớp là một đối tượng thời gian chạy tạo ra các thể hiện, lưu trữ các thuộc tính, tham gia kế thừa và xác định hành vi thông qua mô hình đối tượng Python. Trong CPython, một lớp là một đối tượng có kiểu thường làtype.

Siêu dữ liệu là lớp của một lớp. Nó kiểm soát cách các đối tượng lớp được tạo, khởi tạo, biểu diễn và gọi.

Đối với lớp học bình thường:```python id="g3fkzi" class User: pass

print(type(User)) Đầu ra:text id="iqt3cc" <class 'type'> ```Điều này có nghĩaUserlà một đối tượng và loại của nó làtype.

44.1 Lớp là đối tượng

Một định nghĩa lớp tạo ra một đối tượng lớp.```python id="8zc5m6" class User: name = "anonymous"

def hello(self):
    return "hello"

Sau khi thực hiện,`User`là một tên bình thường bị ràng buộc trong không gian tên xung quanh.python id="rx6c1m" print(User) print(type(User)) print(User.name) print(User.dict) Đối tượng lớp lưu trữ các thuộc tính như:text id="xxewj0" name qualname module dict bases mro methods descriptors class variables annotations


## 44.2 Định nghĩa lớp là thực thi

Thân lp là mã thc thi được.```python id="938wkx"
class Example:
    print("inside class body")
    x = 1 + 2
```Đầu ra trong quá trình định nghĩa:```text id="jiq7he"
inside class body
```Ni dung lp chy ngay lp tc khi CPython thc thi lnh`class`tuyên b. Nó không b trì hoãn cho đến khi mt th hin được to ra.

Điu này quan trng vì mi mã cp cao nht bên trong ni dung lp đều chy vào thi đim to lp:```python id="aj5kyg"
class Bad:
    data = load_large_file()
```Công vic đó xy ra khi lp được xác định.

## 44.3 Đường dẫn tạo lớp

Mt định nghĩa lp:```python id="yzw9ss"
class User(Base):
    x = 1

    def hello(self):
        return "hello"
```v mt khái nim tương t như:```python id="g55w7a"
namespace = {}
namespace["x"] = 1
namespace["hello"] = function_object
User = type("User", (Base,), namespace)
```Quá trình thc tế có nhiu bước hơn:```text id="zd6xb1"
1. Evaluate base classes.
2. Determine the metaclass.
3. Ask the metaclass for a class namespace.
4. Execute the class body in that namespace.
5. Create the class object.
6. Call descriptor __set_name__ methods.
7. Call subclass initialization hooks.
8. Bind the class object to its name.
```Quy trình này gii thích cách siêu lp, b mô t, b trang trí và tính kế tha tương tác vi nhau như thế nào.

## 44.4 Đánh giá các lớp cơ sở

Trong:```python id="zu9u35"
class User(Model):
    pass
```CPython đánh giá đầu tiên`Model`.

Các lp cơ s là các biu thc:```python id="fnc7gv"
class User(get_base_class()):
    pass
```Cuc gi hàm xy ra trước khi đối tượng lp được to.

Nhiu cơ s được đánh giá t trái sang phi:```python id="qtk75l"
class C(A(), B()):
    pass
```Các đối tượng kết qu phi là các lp cơ s hp l hoc có th chuyn đổi thông qua`__mro_entries__`.

## 44,5`__mro_entries__`Cái móc`__mro_entries__`cho phép các đối tượng cơ sở không thuộc lớp tự thay thế chúng trong quá trình tạo lớp.

Điu này được s dng bi mt s máy đánh máy và máy móc chung.

Hình dng ví d:```python id="esjxp2"
class BaseAlias:
    def __mro_entries__(self, bases):
        return (RealBase,)

class C(BaseAlias()):
    pass
```V mt khái nim, CPython biến:```python id="154gd3"
class C(BaseAlias()):
    pass
```vào trong:```python id="kfk2ta"
class C(RealBase):
    pass
```nhm mc đích tha kế.

Hu hết mã ng dng không bao gi trin khai`__mro_entries__`, nhưng nó là mt phn ca vic to lp.

## 44.6 Xác định Metaclass

Siêu d liu có th được ch định rõ ràng:```python id="o3wmta"
class User(metaclass=Meta):
    pass
```Nếu không có siêu d liu nào được ch định, CPython s ly nó t các lp cơ s.

Đối vi lp hc bình thường:```python id="oe50zn"
class User:
    pass
```siêu d liu là:```text id="ythfx3"
type
```Đối vi mt lp con:```python id="t5oe3k"
class Child(Base):
    pass
```siêu d liu thường là`type(Base)`hoc mt siêu d liu dn xut tương thích.

Siêu d liu được chn phi tương thích vi siêu d liu ca tt c các lp cơ s. Nếu không thì CPython s gây ra xung đột siêu d liu.

## 44.7 Xung đột siêu lớp

Xung đột siêu d liu xy ra khi các lp cơ s yêu cu siêu d liu không tương thích.

Ví d:```python id="dk85qy"
class MetaA(type):
    pass

class MetaB(type):
    pass

class A(metaclass=MetaA):
    pass

class B(metaclass=MetaB):
    pass

class C(A, B):
    pass
```Điu này gây ra li vì CPython không th chn mt siêu d liu duy nht tương thích vi c hai`MetaA`Và`MetaB`.

Cách khc phc thông thường là xác định mt siêu d liu kết hp:```python id="7bm0x5"
class MetaC(MetaA, MetaB):
    pass

class C(A, B, metaclass=MetaC):
    pass
```Xung đột siêu d liu là ph biến khi kết hp các khung s dng siêu d liu.

## 44.8 Chuẩn bị không gian tên lớp

Trước khi thc thi ni dung lp, CPython yêu cu siêu d liu cung cp mt không gian tên.

Nó thc hin điu này bng cách gi`__prepare__`nếu có mt.```python id="0o8dg6"
class Meta(type):
    @classmethod
    def __prepare__(mcls, name, bases, **kwargs):
        return {}

class User(metaclass=Meta):
    x = 1
```Đối tượng tr v được s dng làm không gian tên cc b cho ni dung lp.

V mt lch s, điu này cho phép các không gian tên lp được sp xếp. T đin hin đại gi nguyên th t chèn, nhưng`__prepare__`vn h tr hành vi không gian tên tùy chnh.

Các trường hp s dng ví d:```text id="rq5a86"
tracking declaration order
rejecting duplicate names
collecting field definitions
custom class DSLs
framework model declarations
```## 44.9 Không gian tên nội dung lớp

Thân lp thc thi vi không gian tên cc b ca chính nó.```python id="4q8zlf"
x = "global"

class Example:
    x = "class local"
    y = x

print(Example.x)
print(Example.y)
```Đầu ra:```text id="7d4l4l"
class local
class local
```Các bài tp trong ni dung lp ghi vào vùng tên lp ch không phi vào mt th hin.

Các thân hàm bên trong lp không t động ghi li tên cc b ca lp:```python id="kkxro6"
class Example:
    x = 10

    def method(self):
        return x
```Điu này thường tht bi trong thi gian chy tr khi có mt toàn cc`x`, bi vì phương thc tra cu toàn cc s dng toàn cc mô-đun ch không phi không gian tên lp.

Chính xác:```python id="mjh0gx"
class Example:
    x = 10

    def method(self):
        return self.x
```hoc:```python id="73a9fm"
class Example:
    x = 10

    def method(self):
        return type(self).x
```## 44.10 Tạo đối tượng lớp

Sau khi thc thi phn thân lp, CPython gi siêu d liu.

Đối vi mt lp bình thường, điu này có nghĩa là gi`type`.

V mt khái nim:```python id="y5jzez"
User = type("User", bases, namespace)
```Cuc gi đến`type`to ra mt`PyTypeObject`ni b.

Đối tượng lp kết qu lưu tr:```text id="q6gq90"
class name
base classes
method resolution order
class dictionary
type flags
slot tables
weakref support
instance layout
descriptor information
subclass relationships
```Do đó, mt lp do người dùng định nghĩa là mt đối tượng kiu.

## 44.11`type(name, bases, namespace)`Bạn có thể tạo các lớp theo cách thủ công với`type`.

```python id="swqmpu"
def hello(self):
    return "hello"

User = type("User", (), {"hello": hello})

u = User()
print(u.hello())
```Điu này tương đương v mt tinh thn vi:```python id="owh4rx"
class User:
    def hello(self):
        return "hello"
```các`class`câu lnh là cú pháp cho mt giao thc to lp có cu trúc.

## 44.12 Siêu lớp`__new__`Siêu dữ liệu có thể tùy chỉnh việc tạo lớp bằng cách ghi đè`__new__`.

```python id="55v7xr"
class Meta(type):
    def __new__(mcls, name, bases, namespace, **kwargs):
        print("creating", name)
        return super().__new__(mcls, name, bases, namespace)

class User(metaclass=Meta):
    pass
```Đầu ra:```text id="xsdbla"
creating User

__new__nhận tên lớp, lớp cơ sở và không gian tên trước khi đối tượng lớp tồn tại.

Sử dụng__new__khi bạn cần thay đổi lớp trước khi tạo:text id="e80nxe" modify namespace validate definitions inject methods collect metadata change base classes control class object allocation ## 44.13 Siêu lớp__init__Siêu dữ liệu có thể tùy chỉnh việc khởi tạo lớp bằng cách ghi đè__init__.

class Meta(type):
    def __init__(cls, name, bases, namespace, **kwargs):
        print("initializing", name)
        super().__init__(name, bases, namespace)

class User(metaclass=Meta):
    pass

__init__nhận đối tượng lớp đã được tạo dưới dạngcls.

Sử dụng siêu dữ liệu__init__khi bạn cần đăng ký hoặc kiểm tra lớp sau khi tạo:text id="u1q6kk" register subclasses validate final class attach metadata update external registries ## 44.14 Siêu lớp__call__Việc gọi một lớp được điều khiển bởi siêu dữ liệu của nó.

Đối với lớp học bình thường:python id="kq4rc6" u = User("Ada") được xử lý bởi:text id="y1lk7w" type(User).__call__(User, "Ada") Đối với siêu dữ liệu bình thường,type.__call__thực hiện:```text id="vxizzk"

  1. call User.new(User, ...)
  2. if result is an instance of User, call User.init(instance, ...)
  3. return instance ```Một siêu dữ liệu có thể ghi đè__call__:
class SingletonMeta(type):
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls._instance = super().__call__(*args, **kwargs)
        return cls._instance

class Config(metaclass=SingletonMeta):
    pass
```Bây giờ mỗi`Config()`cuộc gọi trả về cùng một đối tượng.

Sử dụng điều này một cách tiết kiệm. Siêu lớp`__call__`thay đổi việc tạo  thể trên toàn cầu cho lớp.

## 44.15 Tạo phiên bản

Đối với lớp học bình thường:```python id="6kcvu5"
class User:
    def __new__(cls, name):
        print("__new__")
        return super().__new__(cls)

    def __init__(self, name):
        print("__init__")
        self.name = name

u = User("Ada")
```Đầu ra:```text id="868s0q"
__new__
__init__

__new__tạo ra đối tượng.__init__khởi tạo đối tượng.__new__là một hàm tạo giống như tĩnh. Nó nhận lớp và trả về một đối tượng.__init__nhận được phiên bản đã tạo và sẽ trả vềNone.

44.16 Từ điển lớp

Một lớp hiển thị không gian tên của nó thông qua__dict__.

class User:
    kind = "human"

    def hello(self):
        return "hello"

print(User.__dict__)

User.__dict__thường là proxy ánh xạ chỉ đọc.python id="pj2w2d" print(type(User.__dict__)) Bạn không thể gán trực tiếp vào proxy ánh xạ:python id="sgmmu2" User.__dict__["x"] = 1 Nhưng bạn có thể gán thuộc tính cho lớp:```python id="4utuvq" User.x = 1


## 44.17 Biến lớp

Mt biến lp được lưu tr trên đối tượng lp.```python id="hkk4e1"
class Counter:
    count = 0
```Truy cp thông qua lp:```python id="kts1o0"
print(Counter.count)
```Truy cp thông qua mt th hin:```python id="8w340h"
c = Counter()
print(c.count)
```Nếu instance không có`count`, tra cu tìm thy nó trên lp.

Vic gán thông qua phiên bn s to hoc cp nht mt thuc tính phiên bn:```python id="d1dq8x"
c.count = 10

print(c.__dict__)
print(Counter.count)
```Đầu ra:```text id="frwv5a"
{'count': 10}
0
```Đây là ngun li ph biến vi các biến lp có th thay đổi.

## 44.18 Cạm bẫy biến đổi lớp có thể thay đổi```python id="x8s3te"
class Bag:
    items = []

    def add(self, item):
        self.items.append(item)
```Cách s dng:```python id="81dg5u"
a = Bag()
b = Bag()

a.add("x")
print(b.items)
```Đầu ra:```text id="kqxpp6"
['x']
```C hai phiên bn đều có chung danh sách cp lp.

Thiết kế đúng:```python id="l9yqqx"
class Bag:
    def __init__(self):
        self.items = []

    def add(self, item):
        self.items.append(item)
```S dng các biến lp cho các hng chia s hoc trng thái chia s có ch ý. S dng các biến mu cho trng thái ca tng phiên bn.

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

Các đối tượng do người dùng định nghĩa thông thường có mt t đin mu.```python id="8j4hxd"
class User:
    pass

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

print(u.__dict__)
```Đầu ra:```text id="e5beij"
{'name': 'Ada'}
```Vic gán thuc tính lưu tr các giá tr trong t đin mu tr khi b mô t d liu chn vic gán.

Đây là lý do ti sao các đối tượng Python li linh hot theo mc định. Các thuc tính mi có th được thêm động.

## 44,20`__slots__`và bố cục sơ thẩm

Mt lp có th định nghĩa`__slots__`để s dng các v trí thuc tính c định thay vì t đin phiên bn thông thường.```python id="ok0zm7"
class Point:
    __slots__ = ("x", "y")

    def __init__(self, x, y):
        self.x = x
        self.y = y
```Trường hp ca`Point`ca hàng`x`Và`y`trong các khe c định.```python id="3bbvk2"
p = Point(1, 2)

print(hasattr(p, "__dict__"))
```Thường xuyên:```text id="mk5rwc"
False
```Các khe to mô t trên lp:```python id="1l1jy7"
print(Point.__dict__["x"])
print(Point.__dict__["y"])
```Nhng b mô t này đọc và ghi các v trí lưu tr c định.

## 44.21 Kế thừa

Mt lp có th kế tha t mt hoc nhiu lp cơ s.```python id="9jq7to"
class Animal:
    def speak(self):
        return "..."

class Dog(Animal):
    def speak(self):
        return "woof"
```Lp con lưu tr các lp cơ s ca nó trong`__bases__`.

```python id="s4yqfg"
print(Dog.__bases__)
```Th t phân gii phương thc được lưu tr trong`__mro__`.

```python id="zfn7t5"
print(Dog.__mro__)
```Tra cu thuc tính tuân theo MRO.

## 44.22 Phương thức Thứ tự giải quyết

Dành cho:```python id="z3o721"
class A:
    def f(self):
        return "A"

class B(A):
    pass

class C(B):
    pass

C().f()tìm thấyfTRONGAthông qua MRO.python id="km9ffo" print(C.__mro__) Hình dạng đầu ra:```text id="mvct9m" (<class 'main.C'>, <class 'main.B'>, <class 'main.A'>, <class 'object'>)


## 44.23 Đa kế thừa

Python h tr đa kế tha.```python id="vr4scb"
class A:
    def f(self):
        return "A"

class B:
    def f(self):
        return "B"

class C(A, B):
    pass

print(C().f())
print(C.__mro__)
```Căn c ngoài cùng bên trái thường được ưu tiên, tuân theo quy tc C3 MRO.

Đầu ra:```text id="njnz6d"
A
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
```Đa kế tha rt mnh m nhưng nó đòi hi phi có thiết kế hp tác khi các lp chia s các phương thc và đường dn khi to.

##44.24 Hợp tác xã`super`

`super()`tuân theo MRO.```python id="xgd0er"
class A:
    def f(self):
        return "A"

class B(A):
    def f(self):
        return "B" + super().f()

class C(A):
    def f(self):
        return "C" + super().f()

class D(B, C):
    def f(self):
        return "D" + super().f()

print(D().f())
print(D.__mro__)
```Đầu ra:```text id="f6z3iu"
DBCA

super()không có nghĩa là “gọi cho bố mẹ tôi.” Nó có nghĩa là “tiếp tục MRO sau lớp hiện tại.”

Điều này là cần thiết trong đa kế thừa.

44.25 Trang trí lớp học

Trình trang trí lớp sẽ nhận đối tượng lớp sau khi nó được tạo.```python id="6z5a86" def register(cls): registry[cls.name] = cls return cls

registry = {}

@register class User: pass Đại khái là thế này:python id="alod77" class User: pass

User = register(User)


## 44,26`__init_subclass__`Một lớp cơ sở có thể định nghĩa`__init_subclass__`để chạy mã khi nó được phân lớp.```python id="zfxjod"
class Model:
    registry = []

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        Model.registry.append(cls)

class User(Model):
    pass

class Post(Model):
    pass

print(Model.registry)
```Điu này thường đơn gin hơn siêu d liu để đăng ký lp con.

S dng`__init_subclass__`vì:```text id="yp6gp0"
subclass registration
subclass validation
default subclass configuration
lightweight framework hooks
```## 44,27`__set_name__`Trong quá trình tạo lớp

Sau khi to mt lp, CPython gi`__set_name__`trên các b mô t trong không gian tên lp.```python id="5vzb6d"
class Field:
    def __set_name__(self, owner, name):
        print(owner, name)

class User:
    id = Field()
    name = Field()
```Hình dng đầu ra:```text id="vzb7xd"
<class '__main__.User'> id
<class '__main__.User'> name
```Điu này cho phép các b mô t khám phá tên lp và thuc tính mà chúng được gán.

Th t là:```text id="4ow51f"
class body executes
class object is created
descriptor __set_name__ hooks run
__init_subclass__ hooks run on bases
class decorators run
class name is bound
```## 44.28 Siêu lớp so với Trang trí lớp so với`__init_subclass__`| Cơ chế | Chạy | Tốt nhất cho |
|---|---|---|
| Siêu lp | Trong quá trình to lp | Kim soát sâu vic to đối tượng lp |
| Trang trí lp hc | Sau khi to lp | Chuyn đổi hoc đăng ký mt ln |
|`__init_subclass__`| Khi lp con được to | Móc lp con điu khin lp cơ s |
| B mô t`__set_name__`| Trong quá trình hoàn thin lp hc | Khám phá tên trường |

Thích cơ chế đơn gin nht để gii quyết vn đề.

Đối vi hu hết các mã:```text id="wd9e73"
class decorator > __init_subclass__ > metaclass
```Siêu d liu là hp lý khi bn cn tùy chnh vic chun b không gian tên, phân b lp, các phương thc  cp độ siêu d liu, cách gi lp hoc thc thi các quy tc trên toàn h thng phân cp lp.

## 44.29 Ví dụ về siêu dữ liệu: Thực thi các thuộc tính bắt buộc```python id="p13a12"
class RequireTableName(type):
    def __new__(mcls, name, bases, namespace):
        cls = super().__new__(mcls, name, bases, namespace)

        if bases and not hasattr(cls, "table_name"):
            raise TypeError(f"{name} must define table_name")

        return cls

class Model(metaclass=RequireTableName):
    pass

class User(Model):
    table_name = "users"
```Siêu d liu này xác nhn các lp con.

Điu này cũng có th được thc hin vi`__init_subclass__`, thường đơn gin hơn:```python id="8wx9md"
class Model:
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        if not hasattr(cls, "table_name"):
            raise TypeError(f"{cls.__name__} must define table_name")
```S dng hook lp cơ s tr khi siêu d liu mang li li thế c th.

## 44.30 Ví dụ về siêu dữ liệu: Sổ đăng ký```python id="q07d17"
class RegistryMeta(type):
    registry = {}

    def __init__(cls, name, bases, namespace):
        super().__init__(name, bases, namespace)
        if name != "Base":
            RegistryMeta.registry[name] = cls

class Base(metaclass=RegistryMeta):
    pass

class User(Base):
    pass

class Post(Base):
    pass

print(RegistryMeta.registry)
```Điu này ghi li các lp con khi chúng được to ra.

Li,`__init_subclass__`có th là đủ:```python id="byf0x9"
class Base:
    registry = {}

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        Base.registry[cls.__name__] = cls
```Nên s dng siêu d liu khi chúng đơn gin hóa h thng ch không phi khi chúng ch mang li cm giác mnh m.

## 44.31 Ví dụ về siêu dữ liệu: Không gian tên tùy chỉnh

Siêu d liu có th t chi các tên thuc tính trùng lp bng cách tr v mt không gian tên tùy chnh t`__prepare__`.

```python id="9r9h1q"
class NoDuplicateDict(dict):
    def __setitem__(self, key, value):
        if key in self:
            raise TypeError(f"duplicate name: {key}")
        super().__setitem__(key, value)

class NoDuplicateMeta(type):
    @classmethod
    def __prepare__(mcls, name, bases):
        return NoDuplicateDict()

class Example(metaclass=NoDuplicateMeta):
    x = 1
    y = 2
```Nếu như`x`được ch định hai ln, vic to lp s tht bi.

Đây là mt trường hp siêu d liu phù hp vì ch siêu d liu mi có th tùy chnh không gian tên ni dung lp trước khi thc thi.

## 44.32 Các lớp tích hợp và các loại vùng heap

CPython có c loi tích hp được xác định tĩnh và loi vùng heap được phân b động.

Ví d v các loi tích hp:```python id="bsov46"
int
str
list
dict
tuple
type
object
```Nhiu loi tích hp được định nghĩa trong C.

Các lp do người dùng định nghĩa là các kiu heap được to trong thi gian chy.

C hai đều tham gia vào cùng mt mô hình đối tượng:```python id="fbhr47"
print(type(list))
print(type(object))
print(type(type))
```Đầu ra:```text id="errhki"
<class 'type'>
<class 'type'>
<class 'type'>
```Ngay c các lp dng sn cũng là đối tượng.

## 44,33`object`Và`type`Mối quan hệ giữa`object`Và`type`là trung tâm.```python id="ls93k5"
print(isinstance(object, type))
print(isinstance(type, object))
print(type(type))
print(type(object))
```S tht quan trng:```text id="9186px"
object is the base class of most Python objects
type is the default metaclass of classes
type is an instance of itself
object is an instance of type
type inherits from object
```Cu trúc hình tròn này được khi động cn thn bên trong CPython.

Nó cho phép các lp tr thành đối tượng trong khi vn có h thng phân cp kế tha gc.

## 44.34 Đối tượng loại CPython

 cp độ C, mt đối tượng lp được biu din bng mt đối tượng kiu, thông thường`PyTypeObject`.

Mt đối tượng loi cha:```text id="pj1kt2"
object header
type name
basic instance size
item size for variable-sized objects
method table
slot functions
base classes
MRO
dictionary
flags
allocation functions
deallocation functions
attribute access functions
call behavior
numeric, sequence, and mapping operation tables
```Đây là lý do ti sao các lp kim soát hành vi ca đối tượng. Đối tượng lp cha các con tr hàm và siêu d liu được s dng trong thi gian chy.

## 44,35 Loại khe cắm

Các phương thc đặc bit ca Python thường tương ng vi các khe cp độ C.

Ví d:

| Phương pháp Python | Hot động thi gian chy |
|---|---|
|`__len__`| chiu dài hot động |
|`__getitem__`| lp ch mc |
|`__setitem__`| phân công mc |
|`__iter__`| lp đi lp li |
|`__next__`| trình vòng lp tiếp theo |
|`__call__`| gi |
|`__add__`| phép cng s |
|`__getattribute__`| tra cu thuc tính |
|`__new__`| phân b |
|`__init__`| khi to |

Khi mt lp được to, CPython s xây dng các bng v trí t các phương thc đặc bit.

Điu này cho phép mã byte và API C gi các hot động mt cách hiu qu mà không cn thc hin tra cu thuc tính Python thông thường mi ln.

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

Tra cu phương pháp đặc bit thường b qua các t đin mu.

Ví d:```python id="w8gu52"
class Example:
    pass

e = Example()
e.__len__ = lambda: 10

len(e)
```Điu này làm tăng`TypeError`, bi vì`len(e)`tìm kiếm`__len__`trên loi, không phi là thuc tính th hin tùy ý.

Chính xác:```python id="a41p2c"
class Example:
    def __len__(self):
        return 10

e = Example()
print(len(e))
```Các phương thc đặc bit thuc v lp để CPython có th đin và s dng các v trí kiu.

## 44.37 Tra cứu thuộc tính cho các lớp

Để truy cp ví d:```python id="ars6ez"
obj.attr
```CPython tìm kiếm phiên bn và h thng phân cp lp ca nó.

Để truy cp lp:```python id="e6vx8d"
Class.attr
```CPython tìm kiếm đối tượng lp và siêu d liu ca nó.

Ví d:```python id="511n1a"
class Meta(type):
    label = "meta"

class User(metaclass=Meta):
    label = "class"

print(User.label)
```Đầu ra:```text id="8dznft"
class
```Nếu như`label`vng mt `User`, tra cu có th tìm thy nó trên`Meta`.

Siêu lp xác định hành vi và thuc tính ca các đối tượng lp.

## 44.38 Phương thức siêu lớp

Phương thc siêu d liu là mt phương thc trên đối tượng lp.```python id="7avylj"
class Meta(type):
    def describe(cls):
        return cls.__name__

class User(metaclass=Meta):
    pass

print(User.describe())
```Đây,`describe`được tìm thy trên`Meta`và ràng buc vi`User`.

Điu này tương t vi cách tìm thy các phương thc instance trên`User`và ràng buc vi`user_instance`.

```text id="dm9zxe"
instance method:
    User.method -> bound to instance

metaclass method:
    Meta.method -> bound to class object
```## 44.39 Các lớp và bộ mô tả

Mô t lưu tr t đin lp.```python id="jcw8ig"
class User:
    @property
    def name(self):
        return "Ada"

print(User.__dict__["name"])
```Khi mt instance truy cp`name`, logic mô t s chy.```python id="bochjq"
u = User()
print(u.name)
```Các phương thc cũng là mô t:```python id="yrosvm"
class User:
    def hello(self):
        return "hello"

u = User()
print(u.hello)
```Chc năng được lưu tr trong`User.__dict__`liên kết vi`u`thông qua mô t ca nó`__get__`.

## 44.40 Lớp học và thu gom rác

Các đối tượng lp có th tham gia vào các chu trình tham chiếu.

Ví d:```text id="zbbqva"
class object references methods
methods reference globals
functions reference code objects
closures may reference class-related state
instances reference class
class may reference descriptors
descriptors may reference owner class
```Trình thu gom rác theo chu k ca CPython có th thu thp các lp không th truy cp và các đối tượng liên quan nếu chúng không được các tham chiếu khác duy trì.

Hu hết các lp thông thường tn ti cho đến khi quá trình thoát ra vì các mô-đun gi các tham chiếu đến chúng.```python id="25zzxi"
class User:
    pass
```T đin mô-đun cha`User`.

## 44.41 Lớp và Mô-đun

Mt lp ghi li mô-đun nơi nó được xác định.```python id="23z7po"
class User:
    pass

print(User.__module__)
```Thường xuyên:```text id="btn8n6"
__main__
```hoc tên mô-đun.

Điu này nh hưởng đến vic trình bày, ty ra, ghi chép và xem xét ni tâm.

Mt lp không thuc v mt mô-đun v mt vt lý. T đin mô-đun ch cha mt tham chiếu đến đối tượng lp.```python id="vxme1s"
OtherName = User
```Bây gi đối tượng lp đó có mt tên khác.

## 44.42 Nhận dạng lớp

Nhn dng lp là nhn dng đối tượng.```python id="05l12d"
class User:
    pass

A = User
B = User

print(A is B)
```Đầu ra:```text id="krnpze"
True
```Nếu mt mô-đun được nhp hai ln dưới các tên khác nhau, các đối tượng lp có th b trùng lp.```text id="59akdg"
package.models.User
models.User
```Đây có th là các đối tượng lp khác nhau ngay c khi chúng đến t cùng mt tp.

Điu đó phá v`isinstance`, tra cu s đăng ký, tun t hóa và các gi định đơn l.

## 44.43 Chú thích lớp

Chú thích lp được lưu tr trong`__annotations__`.

```python id="qmsv40"
class User:
    id: int
    name: str = "anonymous"

print(User.__annotations__)
```Đầu ra:```text id="fzxf79"
{'id': <class 'int'>, 'name': <class 'str'>}
```Chú thích không t động to các trường mu.```python id="pveplo"
u = User()
print(hasattr(u, "id"))
```Thường xuyên:```text id="lxeohq"
False
```Các khung như lp d liu, attrs, Pydantic và ORM kim tra các chú thích để to ra hành vi.

## 44.44 Các lớp dữ liệu dưới dạng chuyển đổi lớp`dataclasses.dataclass`là người trang trí lớp học.```python id="r4xqnl"
from dataclasses import dataclass

@dataclass
class User:
    id: int
    name: str
```Nó nhn đối tượng lp, kim tra các chú thích và thêm các phương thc như:```text id="i9m60v"
__init__
__repr__
__eq__
```Điu này cho thy hành vi chính ca lp có th được thêm vào sau khi to lp mà không cn siêu d liu.

## 44.45 Các lớp cơ sở trừu tượng

các`abc`mô-đun s dng máy móc siêu d liu.```python id="cudwvv"
from abc import ABC, abstractmethod

class Store(ABC):
    @abstractmethod
    def get(self, key):
        pass

ABCcông dụngABCMeta, một siêu dữ liệu theo dõi các phương thức trừu tượng và ngăn chặn việc khởi tạo cho đến khi chúng được triển khai.```python id="j5b315" class BadStore(Store): pass

BadStore() ```Điều này làm tăngTypeError.

Các lớp cơ sở trừu tượng là một ví dụ thực tế về siêu lớp thực thi các hợp đồng lớp.

44.46 Lớp học vàisinstance

isinstance(obj, cls)thường kiểm tra xemtype(obj)clshoặc một lớp con củacls.

class Animal:
    pass

class Dog(Animal):
    pass

d = Dog()

print(isinstance(d, Dog))
print(isinstance(d, Animal))
```Siêu dữ liệu  thể tùy chỉnh điều này thông qua`__instancecheck__`.

Máy ABC sử dụng điều này cho hành vi của lớp con ảo.

## 44.47 Lớp học và`issubclass`

`issubclass(A, B)`kiểm tra xem lớp`A` một lớp con của lớp`B`.

```python id="3tkb0g"
class A:
    pass

class B(A):
    pass

print(issubclass(B, A))
```Siêu dữ liệu  thể tùy chỉnh điều này thông qua`__subclasscheck__`.

Đây  một nơi khác  hành vi của lớp được trung gian bởi logic siêu lớp.

## 44.48 Tạo lớp động

Tạo lớp động rất hữu ích trong các khung  tạo .```python id="pq2ye4"
def make_model(name, fields):
    namespace = {"__annotations__": fields}
    return type(name, (), namespace)

User = make_model("User", {"id": int, "name": str})

print(User)
print(User.__annotations__)
```Các lớp động vẫn phải tuân theo các quy tắc lớp thông thường:```text id="kwqh7u"
valid name
clear module
stable identity
predictable bases
explicit public API
```Bộ`__module__`khi cần thiết:```python id="hyvbmw"
namespace = {
    "__module__": __name__,
    "__annotations__": fields,
}
```Điều này cải thiện sự xem xét nội tâm  tuần tự hóa.

## 44.49 Khi nào nên sử dụng Metaclass

Sử dụng siêu dữ liệu khi bạn cần một trong những thứ sau:```text id="j2iimq"
custom class namespace through __prepare__
control over class allocation through __new__
metaclass-level methods or properties
custom class call behavior
deep integration across a class hierarchy
framework-level class validation
special instance or subclass checks
```Tránh sử dụng siêu dữ liệu để đăng , xác thực hoặc tạo phương thức đơn giản khi trình trang trí lớp hoặc`__init_subclass__` đủ.

Siêu dữ liệu  tính toàn cầu đối với hệ thống phân cấp lớp. Chúng soạn thảo kém khi các thư viện không liên quan xác định các siêu dữ liệu khác nhau.

## 44,50 Điểm chính

Một lớp  một đối tượng thời gian chạy.

Hầu hết các lớp  những thể hiện của`type`.

Siêu dữ liệu  loại của một lớp.

Các định nghĩa lớp thực thi phần thân, thu thập một vùng tên  gọi một siêu dữ liệu để tạo đối tượng lớp.

Các phiên bản được tạo bằng cách gọi một lớp, được xử  bởi siêu dữ liệu`__call__`.

Từ điển lớp lưu trữ các phương thức, bộ  tả, chú thích  biến lớp.

Kế thừa sử dụng thứ tự phân giải phương thức.

Các phương thức đặc biệt được cài đặt vào các khe kiểu  thường được tra cứu trên lớp chứ không phải trên phiên bản.

 tả,`__set_name__`, `__init_subclass__`, trình trang trí lớp  siêu lớp đều tham gia xây dựng lớp.

Chỉ sử dụng siêu dữ liệu khi các  chế lớp đơn giản hơn không thể thể hiện hành vi được yêu cầu.