32. Cuộc gọi phương thức

Cuộc gọi phương thức là cuộc gọi hàm thường bắt đầu bằng quyền truy cập thuộc tính. Chúng là trung tâm của mô hình đối tượng của Python vì hầu hết hành vi của đối tượng được thể hiện thông qua các phương thức.

Một cuộc gọi phương thức như:python id="l3owku" obj.method(arg) trông giống như một thao tác, nhưng CPython thực hiện một số bước khái niệm:```text id="j39rdj" load obj look up attribute method bind obj if needed load arg call the resolved callable return result or raise exception


## 32.1 Cuộc gọi phương thức là cuộc gọi truy cập thuộc tính Plus

Biu thc ngun:```python id="xgyvgk"
obj.method(10)
```có th được hiu là:```python id="gg912h"
tmp = obj.method
tmp(10)
```Đây là mô hình ng nghĩa chính xác. Vic tra cu thuc tính xy ra đầu tiên. Kết qu ca vic tra cu đó sau đó được gi.

Kết qu đó có th là:```text id="mfp3rd"
a bound method
a function
a built-in method
a callable object
a descriptor result
a property result
any object returned by __getattribute__
```Cuc gi ch thành công nếu giá tr đã gii quyết có th gi được.

Ví d:```python id="hsu4g1"
class C:
    value = 10

obj = C()
obj.value()
```Điu này tht bi vì`obj.value`quyết tâm`10`và mt s nguyên không th gi được.

## 32.2 Hàm đơn giản được lưu trữ trên một lớp

Mt hàm được định nghĩa bên trong mt lp s tr thành mt b mô t.```python id="ys9rpg"
class User:
    def greet(self, name):
        return "hello " + name
```T đin lp cha mt đối tượng hàm:```python id="vcrq8f"
print(User.__dict__["greet"])
```Khi được truy cp thông qua mt th hin:```python id="moa6m1"
u = User()
u.greet
```hành vi mô t ca hàm liên kết th hin như`self`.

V mt khái nim:```text id="ho345m"
User.__dict__["greet"].__get__(u, User)
    -> bound method
```Phương thc ràng buc lưu tr:```text id="3tilp4"
function object
self object
```Gi:```python id="tnkuwp"
u.greet("Ada")
```v mt khái nim tương đương vi:```python id="zdsl7s"
User.greet(u, "Ada")
```t động`self`đối s là đim khác bit chính gia lnh gi hàm và lnh gi phương thc cá th thông thường.

## 32.3 Phương thức ràng buộc

Mt phương thc b ràng buc đóng gói mt hàm vi mt đối tượng.```python id="xz4yfy"
class C:
    def f(self, x):
        return x + 1

obj = C()
m = obj.f

print(m(10))
```Đây,`m`là mt phương pháp ràng buc. Nó nh`obj`.

V mt khái nim:```text id="vqipye"
bound method
    __func__ -> C.f
    __self__ -> obj
```Bn có th kim tra điu này:```python id="e0hgzo"
print(m.__func__)
print(m.__self__)
```Khi`m(10)`được gi, CPython gi hàm cơ bn bng`obj`được chèn làm đối s đầu tiên:```python id="9rt8ja"
m.__func__(m.__self__, 10)
```## 32.4 Truy cập chức năng không liên kết thông qua lớp

Vic truy cp mt phương thc thông qua lp s cung cp mt đối tượng ging hàm không liên kết mt th hin theo cách tương t.```python id="kyy416"
class C:
    def f(self, x):
        return x + 1

obj = C()

print(C.f(obj, 10))
```Đây,`obj`được thông qua mt cách rõ ràng.

Quyn truy cp lp:```python id="0trmyu"
C.f
```không ràng buc mt trường hp c th như`self`.

V mt khái nim:```text id="xgfyue"
C.__dict__["f"].__get__(None, C)
    -> function object or descriptor result suitable for class access
```Vì vy, đây là tương đương vi các phương thc cá th thông thường:```python id="1yhu3p"
obj.f(10)
C.f(obj, 10)
```Biu mu đầu tiên thc hin ràng buc cá th. Biu mu th hai chuyn th hin mt cách rõ ràng.

## 32.5 Giao thức mô tả

Liên kết phương thc là mt phn ca giao thc mô t.

B mô t là mt đối tượng có mt hoc nhiu phương thc sau:```text id="02rkfq"
__get__
__set__
__delete__
```Các hàm không phi là b mô t d liu vì chúng xác định`__get__`.

Khi CPython đánh giá:```python id="8f0fmh"
obj.method
```và tìm thy mt đối tượng hàm trong lp, nó gi logic mô t ca hàm.

V mt khái nim:```python id="q89qnh"
method = function.__get__(obj, type(obj))
```Điu này to ra phương thc ràng buc.

Giao thc mô t cũng h tr:```text id="7keg5l"
methods
staticmethod
classmethod
property
slots
many built-in attributes
ORM fields
cached attributes
validation descriptors
```Các cuc gi phương thc không th được hiu đầy đủ nếu không có b mô t.

## 32.6 Dữ liệu và mô tả phi dữ liệu

B mô t có hai loi ln.

| Loi mô t | Định nghĩa | Ưu tiên |
|---|---|---|
| B mô t d liu |`__get__`Và`__set__`hoc`__delete__`| Cao hơn t đin d |
| B mô t phi d liu | Thông thường ch`__get__`| T đin thp hơn ví d |

Các hàm thông thường được lưu tr trên các lp là các b mô t phi d liu.

Điu này có nghĩa là mt thuc tính th hin có th che khut mt phương thc:```python id="8vtwg1"
class C:
    def f(self):
        return "method"

obj = C()
obj.f = lambda: "instance function"

print(obj.f())
```T đin mu cha`f`, vì vy nó chiến thng b mô t phi d liu trong lp.

Thuc tính là mt b mô t d liu, vì vy nó chiếm ưu thế trong t đin mu:```python id="tfs80s"
class C:
    @property
    def x(self):
        return 10
```Các quy tc tra cu nh hưởng đến đối tượng cui cùng được gi.

## 32.7 Thứ tự tra cứu thuộc tính cho các phương thức

Để truy cp thuc tính phiên bn đin hình:```python id="ebj6os"
obj.name
```CPython tuân theo quy trình tra cu gn như thế này:```text id="r7zrsx"
1. Determine type(obj)
2. Look for name in type and base classes
3. If a data descriptor is found, call its __get__
4. Otherwise, look in obj.__dict__ if present
5. If found in instance dictionary, return it
6. Otherwise, if a non-data descriptor was found, call its __get__
7. Otherwise, return the class attribute
8. Otherwise, call __getattr__ if defined
9. Otherwise, raise AttributeError
```Cuc gi phương thc ph thuc vào vic tra cu này. Phương pháp này không ch được chn theo tên. Nó được chn bi giao thc tra cu thuc tính đầy đủ.

## 32.8 Mã byte cuộc gọi phương thức

Dành cho:```python id="fwr5qr"
def call(obj, x):
    return obj.method(x)
```mã byte khái nim trông ging như:```text id="yqk6u7"
LOAD_FAST obj
LOAD_METHOD method
LOAD_FAST x
CALL 1
RETURN_VALUE
```Các hướng dn chính xác khác nhau tùy theo phiên bn Python, nhưng CPython hin đại phân bit ti phương thc vi ti thuc tính chung trong các trường hp ph biến.

Mc tiêu là ti ưu hóa mu này:```python id="2kv28s"
obj.method(arg)
```mà không làm thay đổi kết qu ng nghĩa.

## 32.9 Tại sao`LOAD_METHOD`tồn tại

Mt cuc gi phương thc ngây thơ s thc hin điu này:```text id="dg1ri1"
LOAD_FAST obj
LOAD_ATTR method
LOAD_FAST arg
CALL 1
```Nếu như`method`là mt chc năng bình thường trên lp,`LOAD_ATTR`to ra mt đối tượng phương thc b ràng buc.

Sau đó`CALL`ngay lp tc gi nó.

Vic phân b phương pháp ràng buc tm thi đó thường không cn thiết.

Thay vào đó, mt đường dn được ti ưu hóa có th ti:```text id="eeqqg9"
underlying function
self object
```và gi hàm trc tiếp vi`self`chèn vào.

V mt khái nim:```text id="q3brdt"
obj.method(arg)

optimized:
    function = C.__dict__["method"]
    self = obj
    call function(self, arg)
```Điu này tránh vic to đối tượng phương thc b ràng buc trong trường hp gi ngay lp tc thông thường.

## 32.10 Tránh phân bổ phương thức ràng buộc

Hãy xem xét mt vòng lp:```python id="v4zxb6"
for item in items:
    obj.process(item)
```Vic trin khai đơn gin có th phân b mt phương thc ràng buc cho mi ln lp:```text id="th33f3"
obj.process -> new bound method
call bound method
discard bound method
```Điu đó s to ra lưu lượng truy cp phân b và đếm tham chiếu không cn thiết.

Ti ưu hóa cuc gi phương thc ca CPython tránh điu này trong các trường hp ph biến.

Mô hình ng nghĩa vn còn:```python id="vxkr9d"
tmp = obj.process
tmp(item)
```Nhưng vic thc hin có th b qua vic hin thc hóa`tmp`như mt đối tượng heap khi phương thc được gi ngay lp tc.

## 32.11 Khi các phương thức ràng buộc vẫn được tạo

Mt đối tượng phương thc b ràng buc vn được to khi vic truy cp phương thc chính là kết qu.

Ví d:```python id="vnqqc0"
m = obj.method
``` đây, mã Python yêu cu giá tr thuc tính. CPython phi to đối tượng phương thc b ràng buc vì chương trình có th lưu tr, kim tra, chuyn nó hoc gi nó sau.```python id="ipgvev"
callbacks.append(obj.method)
```Trong trường hp này, đối tượng phương thc b ràng buc là kết qu chính xác mà Python có th nhìn thy.

Ti ưu hóa ch yếu áp dng cho các mu cuc gi ngay lp tc trong đó phương thc b ràng buc không cn phi thoát.

## 32.12 Các phương thức tích hợp

Các kiu tích hp hin th nhiu phương thc được trin khai trong C.```python id="dkd1sx"
xs = []
xs.append(1)
```Phương pháp lit kê`append`được thc hin trong C.

Mt cuc gi phương thc tích hp bao gm:```text id="8n6a77"
method lookup
binding to list object
argument setup
C method call
mutation of list object
return None
```Đối tượng b ràng buc vn hin din v mt khái nim, nhưng vic trin khai có th được ti ưu hóa cao.

Để ni thêm danh sách, thao tác s thay đổi cu trúc danh sách cơ bn trc tiếp trong C.

## 32.13 Bộ mô tả phương thức

Các phương thc tích hp thường được biu din bng các đối tượng mô t thay vì các đối tượng hàm Python thông thường.

Ví d:```python id="sfrzai"
print(list.__dict__["append"])
```Đây không phi là mt hàm Python bình thường. Nó là mt b mô t phương thc tích hp.

Khi được truy cp thông qua mt th hin:```python id="20nfof"
[].append
```nó to ra mt đối tượng phương thc tích hp được liên kết vi danh sách đó.

Khi được gi ngay lp tc:```python id="n6aps6"
[].append(1)
```CPython có th đi theo con đường riêng chuyên bit.

## 32,14`staticmethod`

`staticmethod`vô hiu hóa ràng buc cá th.```python id="i095gy"
class Math:
    @staticmethod
    def add(a, b):
        return a + b

Math.add(2, 3)
Math().add(2, 3)
```Trong c hai trường hp, không`self`được chèn vào.

B mô t tr v hàm cơ bn mà không ràng buc mt th hin.

V mt khái nim:```text id="1s9dk7"
staticmethod.__get__(obj, cls)
    -> original function
```Vì vy, điu này hot động:```python id="opmkar"
Math().add(2, 3)
```vì hàm nhn chính xác hai đối s ch không phi ba đối s.

## 32,15`classmethod`

`classmethod`liên kết lp ch không phi là th hin.```python id="dlj84i"
class C:
    @classmethod
    def make(cls, value):
        return cls(value)
```Gi:```python id="g1ck47"
C.make(10)
```vượt qua`C`như đối s đầu tiên.

Gi thông qua mt th hin:```python id="frurij"
obj = C()
obj.make(10)
```cũng vượt qua lp hc, thường là`C`, không`obj`.

V mt khái nim:```text id="2cfzmr"
classmethod.__get__(obj, cls)
    -> bound method with cls as first argument
```Đây là lý do ti sao các phương thc lp li hu ích cho các hàm to thay thế và cu trúc đa hình.

## 32,16`property`và quyền truy cập giống như phương thức

Mt thuc tính biến logic phương thc thành quyn truy cp thuc tính.```python id="b2eu4v"
class C:
    @property
    def value(self):
        return 42

obj = C()
print(obj.value)
```Điu này không gi`obj.value()`.

Cuc gi xy ra trong quá trình truy cp thuc tính:```text id="m2zdkj"
obj.value
    property.__get__(obj, C)
        calls getter function
        returns result
```Nếu thuc tính tr v mt lnh gi được thì lnh gi sau có th xy ra:```python id="ylxm9w"
obj.factory()
```Nếu như`factory`là mt tài sn, điu này có nghĩa là:```text id="95d6z5"
call property getter
call returned object
```Vì vy, mt lnh gi cp ngun có th liên quan đến các lnh gi mô t n trước lnh gi rõ ràng.

## 32,17`__getattribute__`Mọi tra cứu thuộc tính bình thường đều trải qua`__getattribute__`.

```python id="e8vyww"
class C:
    def __getattribute__(self, name):
        print("lookup", name)
        return super().__getattribute__(name)

    def f(self):
        return 1

obj = C()
obj.f()
```biu thc`obj.f()`cuc gi đầu tiên`obj.__getattribute__("f")`.

Điu này có nghĩa là các cuc gi phương thc có th b chn.

mt phong tc`__getattribute__`Có th:```text id="xczvn9"
return a normal bound method
return a different callable
return a non-callable
raise AttributeError
log access
implement proxies
implement lazy loading
```Máy gi không biết mc đích ngun ban đầu. Nó gi bt k thuc tính nào mà vic tra cu tr v.

## 32,18`__getattr__`

`__getattr__`ch được gi sau khi tra cu thông thường không thành công.```python id="zewpol"
class Dynamic:
    def __getattr__(self, name):
        if name == "run":
            return lambda: "dynamic"
        raise AttributeError(name)

obj = Dynamic()
print(obj.run())
```Đây,`run`không tn ti trong th hin hoc lp.`__getattr__`tr v mt cuc gi được. Cuc gi sau đó s gi ra kết qu có th gi được.

Điu này ph biến :```text id="xud82d"
proxies
RPC clients
ORM models
mock objects
lazy APIs
dynamic wrappers
```Điu đó cũng có nghĩa là các cuc gi phương thc có th được gii quyết linh hot khi chy.

## 32.19 Lệnh gọi phương thức trên mô-đun

Các mô-đun cũng có th h tr truy cp thuc tính động vi cp độ mô-đun`__getattr__`.

```python id="m9w5tu"
# module.py
def __getattr__(name):
    if name == "run":
        return lambda: 42
    raise AttributeError(name)
```Sau đó:```python id="pkzy1x"
import module
module.run()
```có th gii quyết mt cách linh hot.

Đường dn tra cu khác vi liên kết phương thc phiên bn, nhưng mu ngun vn là quyn truy cp thuc tính theo sau là lnh gi.

## 32.20 Thứ tự giải quyết phương pháp

Đối vi các th hin ca lp, tra cu phương thc s tìm kiếm lp và các lp cơ s ca nó bng cách s dng th t phân gii phương thc.```python id="pvvfui"
class A:
    def f(self):
        return "A"

class B(A):
    pass

obj = B()
print(obj.f())
```Các tìm kiếm tra cu`B`, sau đó`A`.

Đối vi đa kế tha:```python id="f6sw15"
class A:
    def f(self):
        return "A"

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

class C(A, B):
    pass
```Phương pháp được la chn ph thuc vào`C.__mro__`.

```python id="ig5h2o"
print(C.__mro__)
```MRO là trung tâm ca các cuc gi phương thc vì nó xác định nơi tra cu thuc tính lp tìm thy b mô t.

## 32,21`super()`Cuộc gọi phương thức`super()`những thay đổi nơi việc tra cứu phương thức bắt đầu trong MRO.```python id="ujmrwo"
class Base:
    def f(self):
        return 1

class Child(Base):
    def f(self):
        return super().f() + 1
```Cuc gi:```python id="w4m10h"
super().f()
```không có nghĩa là gi tên lp cha. Nó có nghĩa là tìm kiếm MRO sau lp hin ti, có liên kết vi phiên bn hin ti.

V mt khái nim:```text id="nlfcwi"
current class = Child
instance = self
MRO = [Child, Base, object]
search after Child
find Base.f
bind to self
call
```Kết qu là mt phương thc b ràng buc s dng cùng mt th hin.

## 32.22 Phương thức và Kế thừa

Mt cuc gi phương thc có th s dng mt phương thc được kế tha t mt lp cơ s.```python id="xtljqg"
class Base:
    def save(self):
        return "saved"

class User(Base):
    pass

u = User()
u.save()
```Vic tra cu tìm thy`save`TRONG`Base`, sau đó liên kết nó vi`u`.

V mt khái nim:```text id="e2s1rr"
find Base.__dict__["save"]
bind with self = u
call Base.save(u)
```Lp xác định ca hàm và lp thc tế ca th hin có th khác nhau. Điu này là bình thường.

## 32.23 Phương thức ghi đè

Các phương thc lp con ghi đè các phương thc cơ s.```python id="3eakv8"
class Base:
    def f(self):
        return "base"

class Child(Base):
    def f(self):
        return "child"

print(Child().f())
```Tra cu tìm thy`Child.f`trước`Base.f`.

Đây là tra cu thi gian chy. Cuc gi không b ràng buc tĩnh bi loi biến.```python id="43x5xb"
def call_f(obj):
    return obj.f()
```Phương pháp được la chn ph thuc vào`type(obj)`vào thi gian chy.

## 32.24 Lệnh gọi phương thức đa hình

Các cuc gi phương thc Python được gi động.```python id="uwb85l"
def speak(animal):
    return animal.speak()
```Các đối tượng khác nhau có th cung cp các cách trin khai khác nhau:```python id="fcv0ik"
class Dog:
    def speak(self):
        return "woof"

class Cat:
    def speak(self):
        return "meow"
```Cùng mt mã byte có th gi các phương thc khác nhau tùy thuc vào đối tượng thi gian chy.

V mt khái nim:```text id="cje20f"
LOAD_FAST animal
LOAD_METHOD speak
CALL 0
```Mc tiêu thc tế được phát hin trong quá trình thc hin.

Công văn động này linh hot nhưng to ra nhng thách thc ti ưu hóa.

## 32.25 Trang web gọi đơn hình và đa hình

Mt trang web gi phương thc là đơn hình nếu nó thường nhìn thy mt loi đối tượng.```python id="j7bxa8"
for user in users:
    user.validate()
```Nếu mi`user`có cùng loi, trang gi là đơn hình.

Mt trang web cuc gi là đa hình nếu nó thy mt s loi:```python id="kw1tz2"
for shape in shapes:
    shape.area()
``` đâu`shape`Có l`Circle`, `Square`, hoc`Triangle`.

B nh đệm ni tuyến hot động tt nht khi các trang web cuc gi n định. Mt trang gi đơn hình có th lưu vào b nh đệm thông tin tra cu loi và phương thc hiu qu hơn.

## 32.26 Bộ nhớ đệm nội tuyến cho lệnh gọi phương thức

CPython có th lưu tr thông tin tra cu phương thc gn lnh mã byte.

B đệm phương thc có th ghi li các s kin như:```text id="cdvqx9"
expected receiver type
type version tag
resolved descriptor
method object or function pointer
offset or lookup result
call shape
```Trong ln thc hin tiếp theo:```text id="9o02ps"
if receiver type still matches
and type version is unchanged
    use cached method path
else
    fall back to generic lookup
```Điu này tăng tc các cuc gi lp li mà không thay đổi ng nghĩa.

Nếu mt lp được sa đổi, th phiên bn hoc b bo v b đệm s vô hiu hóa đường dn nhanh.

## 32.27 Đột biến lớp và vô hiệu hóa bộ đệm

Python cho phép các lp thay đổi khi chy.```python id="jtw9f0"
class C:
    def f(self):
        return 1

obj = C()
print(obj.f())

def new_f(self):
    return 2

C.f = new_f
print(obj.f())
```Cuc gi th hai phi s dng phương thc mi.

Do đó, bt k b đệm nào s dng phương thc cũ đều phi b vô hiu hóa hoc được bo v.

Quy tc an toàn:```text id="89t5m7"
fast method path is valid only while class and lookup assumptions remain true
```Đột biến lp động là mt lý do khiến ti ưu hóa CPython s dng các b bo v.

## 32.28 Đột biến từ điển sơ thẩm

Thuc tính phiên bn cũng có th nh hưởng đến vic tra cu phương thc cho các b mô t phi d liu.```python id="4tnwq5"
class C:
    def f(self):
        return "class method"

obj = C()
obj.f = lambda: "instance value"

print(obj.f())
```Mc nhp t đin phiên bn che m hàm lp vì các hàm thông thường không phi là b mô t d liu.

B đệm phương thc phi tính đến trng thái t đin khi có liên quan.

Đây là mt lý do khác khiến vic tra cu phương thc phc tp hơn vic nhy trc tiếp vào bng lp.

## 32,29 Slots và lệnh gọi phương thức

Lp hc vi`__slots__`có th không có t đin mu thông thường.```python id="vhbgrn"
class C:
    __slots__ = ("x",)

    def f(self):
        return self.x
```Các v trí nh hưởng đến vic lưu tr thuc tính, nhưng vic tra cu phương thc vn tìm kiếm lp và cơ s ca nó.

S vng mt ca`__dict__`có th đơn gin hóa mt s trường hp thuc tính, nhưng các b mô t, s kế tha và đột biến lp động vn còn quan trng.

## 32.30 Phương pháp đặc biệt

Các phương pháp đặc bit như`__len__`, `__add__`, Và`__iter__`thường được tra cu thông qua các v trí loi thay vì tra cu thuc tính phiên bn thông thường.

Ví d:```python id="k6wyb3"
len(obj)
```không ch đơn gin là thc thi:```python id="9dm1lp"
obj.__len__()
```v mi mt. CPython thường s dng khe ca loi cho độ dài.

S khác bit này quan trng:```python id="0t598r"
class C:
    def __len__(self):
        return 10

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

print(len(obj))
print(obj.__len__())
```Cuc gi phương thc rõ ràng có th s dng thuc tính instance. các`len()`hot động s dng phương pháp tra cu đặc bit thông qua kiu.

Các phương pháp đặc bit được ti ưu hóa và tích hp vào các khe giao thc đối tượng.

## 32.31 Cuộc gọi của nhà điều hành so với Cuộc gọi phương thức

Các toán t thường ánh x ti các phương thc đặc bit.```python id="3pof5j"
a + b
```có th gi:```text id="pzts11"
a.__add__(b)
b.__radd__(a)
```Nhưng CPython không hot động bình thường`obj.__add__`tra cu thuc tính cho mi ln b sung. Nó s dng các khe s trên các đối tượng loi.

Vì thế:```python id="rizu1b"
obj.method()
```Và:```python id="g6n28n"
obj + other
```đều là công văn động, nhưng chúng s dng các đường dn ni b khác nhau.

Cuc gi phương thc s dng tra cu thuc tính và máy gi. Người vn hành s dng các khe giao thc, vi hành vi d phòng.

## 32.32 Lệnh gọi phương thức và số lượng tham chiếu

Mt cuc gi phương thc phi được duy trì:```text id="nb20se"
receiver object
resolved callable
arguments
temporary bound method, if created
return value
exception state, if raised
```Đối vi lnh gi phương thc được ti ưu hóa nhm tránh đối tượng phương thc b ràng buc, CPython vn cn đảm bo b thu vn hot động trong khi hàm cơ bn chy.

V mt khái nim:```text id="7pxphh"
load receiver
resolve method
prepare self and args
call
release temporaries
push result
```Vic x lý tham chiếu không chính xác  đây có th gây ra li nghiêm trng vì các lnh gi phương thc thường nhp li Python và mã tùy ý có th chy.

## 32.33 Cuộc gọi phương thức có thể nhập lại Python

Bn thân phương thc tra cu có th thc thi mã Python.

Ví d:```text id="av2mft"
custom __getattribute__
descriptor __get__
property getter
__getattr__
metaclass attribute lookup
```Sau đó, lnh gi phương thc đã gii quyết có th thc thi nhiu mã Python hơn.

Mt biu thc ngun duy nht:```python id="1eq7mu"
obj.method(arg)
```có th liên quan đến:```text id="44juqs"
call __getattribute__
call descriptor __get__
call method body
```Mi cuc gi có th nâng cao, thay đổi trng thái hoc thay đổi hành vi tra cu trong tương lai.

## 32.34 Lệnh gọi phương thức và ngoại lệ

Mt cuc gi phương thc có th tht bi  nhiu đim:```text id="8b856f"
receiver expression raises
attribute lookup raises AttributeError or another exception
descriptor binding raises
argument expression raises
resolved object is not callable
argument binding fails
method body raises
return cleanup raises indirectly
```Ví d:```python id="q0kkqy"
obj.missing()
```tht bi trong quá trình tra cu thuc tính.

Ví d:```python id="68k1hw"
obj.method(bad())
```có th tht bi trong khi đánh giá đối s trước khi phương thc được gi.

Ví d:```python id="ex1xt4"
obj.method()
```có th tht bi bên trong thân phương thc.

Đường dn li mã byte phi xóa các giá tr ngăn xếp tm thi trong mi trường hp.

## 32.35 Cuộc gọi phương thức và`None`Một lỗi phổ biến:```python id="ov87fl"
xs = []
result = xs.append(1)
result.append(2)

list.appendtrả lạiNone.

Dòng thứ hai thất bại vìresultNone, không phải danh sách.

Ở cấp độ gọi phương thức:text id="dx8gic" xs.append(1) mutates xs returns None Giá trị trả về vẫn được đẩy bởi lệnh gọi, sau đó được lưu trữ trongresult.

Các cuộc gọi phương thức không ngụ ý chuỗi trôi chảy trừ khi phương thức đó trả về một cách rõ ràngselfhoặc một vật thể khác.

32.36 Cuộc gọi phương thức theo chuỗi

Cuộc gọi theo chuỗi thực hiện từ trái sang phải.python id="jxorjs" obj.a().b().c() Về mặt khái niệm:```text id="dylm9m" tmp1 = obj.a() tmp2 = tmp1.b() tmp3 = tmp2.c()


Nếu như`a()`tr li`None`, sau đó`.b()`tht bi.

Mã byte s dng ngăn xếp để gi tng kết qu trung gian đủ lâu để truy cp phương thc tiếp theo.

## 32.37 API thông thạo

Mt s API c tình tr li`self`:

```python id="36isx5"
class Builder:
    def set_name(self, name):
        self.name = name
        return self

    def set_age(self, age):
        self.age = age
        return self

builder = Builder().set_name("Ada").set_age(37)
```Mi phương thc làm thay đổi đối tượng và tr v nó.

B máy gi phương thc là bình thường. Phong cách trôi chy là quy ước ca thư vin, không phi là tính năng phiên dch đặc bit.

## 32.38 Các phương thức như đối tượng hạng nhất

Các phương thc có th được lưu tr và truyn đi.```python id="63bqx2"
class C:
    def f(self, x):
        return x + 1

obj = C()
callback = obj.f

print(callback(10))
```Phương pháp ràng buc gi`obj`còn sng.

V mt khái nim:```text id="jrk395"
callback
    function = C.f
    self = obj
```Điu này có th nh hưởng đến tui th b nh:```python id="ka89yy"
callbacks.append(obj.method)
```Danh sách gi li hin gi cho đối tượng tn ti thông qua phương thc b ràng buc.

## 32.39 Phương thức gọi và thu gom rác

Các phương thc ràng buc có th tham gia vào các biu đồ tham chiếu.

Ví d:```python id="7qj87e"
class C:
    def f(self):
        return 1

obj = C()
obj.callback = obj.f
```Hin nay:```text id="7udx0g"
obj
    -> callback bound method
        -> self obj
```Điu này to ra mt chu k.

Trình thu gom rác theo chu k ca CPython có th thu thp các chu k như vy nếu chúng không th truy cp được và nếu các quy tc quyết toán cho phép dn dp.

Đây là mt ví d thc tế v cách các đối tượng phương thc kết ni vi qun lý b nh.

## 32.40 Phương pháp kiểm tra

Bn có th kim tra các đối tượng phương thc:```python id="dcn13l"
class C:
    def f(self, x):
        return x + 1

obj = C()
m = obj.f

print(type(m))
print(m.__func__)
print(m.__self__)
```Bn có th kim tra ni dung t đin lp:```python id="brp4q2"
print(C.__dict__["f"])
```Bn có th kim tra mã byte:```python id="xq1plc"
import dis

def call(obj, x):
    return obj.f(x)

dis.dis(call)
```Điu này cho phép bn xem liu trình biên dch có đưa ra các hướng dn dành riêng cho phương pháp cho phiên bn Python ca bn hay không.

## 32.41 Mô hình liên kết phương thức tối thiểu

Mô hình mô t đồ chơi:```python id="b5ukc4"
class Function:
    def __init__(self, code):
        self.code = code

    def __get__(self, obj, cls):
        if obj is None:
            return self
        return BoundMethod(self, obj)

    def __call__(self, *args):
        return self.code(*args)

class BoundMethod:
    def __init__(self, func, self_obj):
        self.__func__ = func
        self.__self__ = self_obj

    def __call__(self, *args):
        return self.__func__(self.__self__, *args)
```S dng nó:```python id="f8zqma"
def body(self, x):
    return self.value + x

class C:
    value = 10

C.f = Function(body)

obj = C()
print(obj.f(5))
```Đây không phi là cách trin khai ca CPython, nhưng nó nm bt được ý tưởng ràng buc:```text id="lybvyc"
function stored on class
access through instance
descriptor creates bound method
call inserts self
```## 32.42 Những hiểu lầm phổ biến

| Hiu lm | Đúng mu |
|---|---|
|`obj.method(x)`gi trc tiếp mt hàm được lưu tr trên`obj`| Nó thc hin tra cu thuc tính, liên kết, sau đó gi |
|`self`là t khóa được chèn theo cú pháp |`self`ch là đối s đầu tiên theo quy ước |
| Các phương thc luôn tn ti trong các phiên bn | Các phương thc thông thường tn ti trên các lp và liên kết vi các th hin |
| Các phương thc ràng buc luôn được phân b | CPython có th tránh phân b cho các cuc gi ngay lp tc |
|`staticmethod`nhn được`self`| Nó không nhn được đối s đầu tiên t động |
|`classmethod`nhn được phiên bn | Nó nhn được lp |
| Các phương thc đặc bit luôn được tra cu như các phương thc thông thường | Nhiu th được gii quyết thông qua các khe loi |
| Tra cu phương thc tĩnh | Nó ph thuc vào loi thi gian chy, MRO, b mô t và trng thái phiên bn |

## 32.43 Chiến lược đọc

Để nghiên cu các lnh gi phương thc, hãy bt đầu vi chương trình này:```python id="fybmbx"
class C:
    def f(self, x):
        return x + 1

def call(obj):
    return obj.f(10)
```Thanh tra:```python id="r4y4v3"
import dis

dis.dis(call)

obj = C()
m = obj.f

print(m.__func__)
print(m.__self__)
print(C.__dict__["f"])
```Sau đó thay đổi lp:```python id="10svlx"
@staticmethod
def s(x): ...

@classmethod
def c(cls, x): ...

@property
def p(self): ...
```Ngoài ra kim tra:```python id="p178dp"
obj.f = lambda x: x * 2
```và kim tra cách tra cu thay đổi.

Điu này cho thy s tương tác gia các b mô t, t đin phiên bn, mã byte và máy gi.

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

Mt cuc gi phương thc là tra cu thuc tính, theo sau là mt cuc gi. Đối vi các phương thc cá th thông thường, các b mô t hàm liên kết đối tượng nhn làm đối s đầu tiên, to ra mt phương thc liên kết tương đương v mt khái nim vi vic gi hàm lp vi cá th được chèn vào.

Mô hình ct lõi là:```text id="xs3s0t"
obj.method(arg)
    
lookup "method" on obj
    
apply descriptor binding if needed
    
obtain callable
    
call callable with arguments
    
return result or raise exception
```CPython ti ưu hóa đường dn này rt nhiu. Nó có th tránh vic phân b phương thc b ràng buc tm thi, tra cu phương thc b đệm, các trang gi n định chuyên bit và gi các phương thc tích hp thông qua đường dn C nhanh.

Ng nghĩa vn năng động. Loi thi gian chy, MRO, b mô t, t đin phiên bn, móc thuc tính tùy chnh, đột biến lp và các quy tc phương thc đặc bit đều nh hưởng đến phương thc nào thc s được gi.