39. Đóng cửa và tế bào
39. Đóng cửa và ô
Các bao đóng cho phép hàm lồng nhau sử dụng các biến từ hàm kèm theo sau khi hàm kèm theo đó trả về.```python def make_adder(n): def add(x): return x + n return add
add10 = make_adder(10)
print(add10(5))
Đầu ra:text
15
```Biếnnthuộc vềmake_adder, Nhưngaddsau này vẫn sử dụng nó. CPython hỗ trợ điều này bằng cách di chuyển các biến đã ghi vào đối tượng ô. Hàm bên trong giữ các tham chiếu đến các ô đó.
39.1 Hàm lồng nhau
Hàm lồng nhau là hàm được xác định bên trong một hàm khác.```python def outer(): def inner(): return 1
return inner
```cácdef innercâu lệnh thực thi khiouterchạy. Nó tạo ra một đối tượng hàm và liên kết nó với tên cục bộinner.
Đang gọiouter()trả về đối tượng hàm đó:python fn = outer() print(fn()) Đối tượng hàm choinnerchứa:text code object globals dictionary defaults keyword defaults annotations closure cells, if needed Nếu nhưinnerkhông tham chiếu đến các biến cục bộ bên ngoài, nó không cần đóng.
39.2 Biến miễn phí
Biến tự do là biến được sử dụng bởi đối tượng mã nhưng được xác định trong phạm vi kèm theo.```python def outer(): x = 10
def inner():
return x
return inner
```Bên tronginner, xlà một biến tự do.
Bạn có thể kiểm tra điều này:```python def outer(): x = 10
def inner():
return x
return inner
fn = outer()
print(fn.code.co_freevars)
Đầu ra:text
('x',)
```Đối tượng mã bên trong ghi lại những gì nó cầnxtừ bên ngoài.
39.3 Biến ô
Biến ô là biến cục bộ phải được hàm bên trong nắm bắt.```python def outer(): x = 10
def inner():
return x
return inner
```Vìouter, xlà một biến ô vì hàm bên trong sử dụng nó.
Thanh tra:python print(outer.__code__.co_cellvars) Đầu ra:text ('x',) Biến tương tự được nhìn từ hai hướng:```text
outer:
x is a cell variable
inner: x is a free variable
Một biến cục bộ bình thường tồn tại trong một khe khung.```python
def f():
x = 10
return x
```Sau đó`f`quay trở lại, khung của nó có thể bị phá hủy. Các khe cục bộ của nó biến mất.
Nhưng điều này không thể hoạt động đối với việc đóng cửa:```python
def outer():
x = 10
def inner():
return x
return inner
```Sau đó`outer`trở lại,`inner`vẫn cần`x`.
CPython giải quyết điều này bằng cách lưu trữ`x`trong một đối tượng ô.
Về mặt khái niệm:```text
outer frame
x slot points to cell
cell contains 10
inner function
closure tuple points to same cell
```Khi`outer`trở lại, khung có thể biến mất, nhưng ô vẫn tồn tại vì`inner`tham khảo nó.
## 39.5 Đối tượng di động
Đối tượng ô là một thùng chứa nhỏ chứa tham chiếu đến một đối tượng Python khác.
Về mặt khái niệm:```text
cell
contents -> object
```Vì:```python
def outer():
x = 10
def inner():
return x
return inner
```việc đóng cửa trông giống như:```text
inner function
__closure__:
cell for x
contents: 10
```Kiểm tra nó:```python
fn = outer()
print(fn.__closure__)
print(fn.__closure__[0].cell_contents)
```Hình dạng đầu ra:```text
(<cell at 0x...: int object at 0x...>,)
10
```Tế bào, chứ không phải toàn bộ khung bên ngoài, mới là thứ tồn tại.
## 39.6 Bộ đóng hàm
Một đối tượng hàm có`__closure__`thuộc tính.```python
def outer():
x = 10
def inner():
return x
return inner
fn = outer()
print(fn.__closure__)
__closure__là một trong haiNonehoặc một bộ các đối tượng ô.
Đối với ví dụ này:text fn.__closure__ -> (cell_for_x,) Thứ tự các ô tương ứng vớifn.__code__.co_freevars.
print(fn.__code__.co_freevars)
for cell in fn.__closure__:
print(cell.cell_contents)
```Đầu ra:```text
('x',)
10
```## 39.7 Đọc siêu dữ liệu đóng
Sử dụng ví dụ này:```python
def outer(a):
b = 2
def inner(c):
return a + b + c
return inner
fn = outer(10)
print(outer.__code__.co_cellvars)
print(fn.__code__.co_freevars)
print(fn.__closure__)
```Hình dạng đầu ra:```text
('a', 'b')
('a', 'b')
(<cell ...>, <cell ...>)
```Hàm ngoài có các biến ô`a`Và`b`.
Hàm bên trong có các biến miễn phí`a`Và`b`.
Hàm trả về mang các ô cho cả hai.
## 39,8`LOAD_DEREF`Các biến đóng được truy cập bằng mã byte dereference.
Vì:```python
def outer():
x = 10
def inner():
return x
return inner
innerkhông sử dụngLOAD_FASTvìx. Nó sử dụng quyền truy cập đóng cửa.
Về mặt khái niệm:```text LOAD_DEREF x RETURN_VALUE
`LOAD_DEREF`đọc nội dung của một ô.
Tương tự, việc lưu trữ vào một biến đóng sử dụng lệnh lưu trữ theo định hướng quy định.
## 39.9 Tháo rời một đóng cửa
sử dụng`dis`:
```python
import dis
def outer():
x = 10
def inner():
return x
return inner
dis.dis(outer)
fn = outer()
dis.dis(fn)
```Hãy tìm:```text
MAKE_CELL
LOAD_CLOSURE
MAKE_FUNCTION
LOAD_DEREF
STORE_DEREF
```Hướng dẫn chính xác khác nhau tùy theo phiên bản CPython, nhưng các hoạt động khái niệm ổn định:```text
create cell for captured local
create inner function with closure
load from closure cell inside inner
```## 39.10 Tạo đóng cửa
Khi CPython tạo một đối tượng hàm cho một hàm lồng nhau, nó sẽ gắn các ô đóng nếu hàm lồng nhau cần các biến tự do.
Về mặt khái niệm:```text
outer executes
create cell for x
load inner code object
load closure cell for x
make function object with closure
return function object
```Vì:```python
def outer():
x = 10
def inner():
return x
return inner
```hàm trả về có:```text
inner.__code__
inner.__globals__
inner.__closure__ = (cell_for_x,)
```Bộ đóng cửa đó là như thế nào`inner`thấy`x`.
## 39.11 Closure ghi lại các biến, không phải giá trị
Việc đóng cửa ghi lại các biến thông qua các ô chứ không phải ảnh chụp nhanh các giá trị.```python
def outer():
x = 1
def inner():
return x
x = 2
return inner
fn = outer()
print(fn())
```Đầu ra:```text
2
```Hàm bên trong xem nội dung hiện tại của ô. Ô này đã được cập nhật trước đó`outer`đã quay trở lại.
Về mặt khái niệm:```text
cell x initially contains 1
cell x later contains 2
inner reads cell x
```## 39.12 Ô dùng chung
Nhiều chức năng bên trong có thể chia sẻ cùng một ô.```python
def outer():
x = 0
def get():
return x
def set_value(v):
nonlocal x
x = v
return get, set_value
get, set_value = outer()
print(get())
set_value(10)
print(get())
```Đầu ra:```text
0
10
```Cả hai hàm đều tham chiếu cùng một ô cho`x`.
```text
get.__closure__[0] -> cell x
set_value.__closure__[0] -> same cell x
```Ô cung cấp liên kết có thể thay đổi được chia sẻ.
## 39,13`nonlocal`
`nonlocal`báo cho trình biên dịch biết rằng phép gán phải nhắm mục tiêu một biến hàm kèm theo, chứ không phải tạo một biến cục bộ mới.```python
def outer():
x = 0
def inc():
nonlocal x
x += 1
return x
return inc
```Không có`nonlocal`, bài tập làm cho`x`địa phương đến`inc`:
```python
def outer():
x = 0
def bad():
x += 1
return x
return bad
```Đang gọi`bad()`tăng lên`UnboundLocalError`bởi vì`x += 1`cố gắng đọc địa phương`x`trước khi nó có giá trị.
Với`nonlocal`, CPython thực hiện các hoạt động không quy định đối với ô bên ngoài.
## 39,14`global`vs`nonlocal`
`global`nhắm mục tiêu không gian tên mô-đun.```python
x = 0
def f():
global x
x = 10
nonlocalnhắm mục tiêu một phạm vi chức năng kèm theo.```python
def outer():
x = 0
def inner():
nonlocal x
x = 10
| Tuyên bố | Mục tiêu |
|---|---|
|`global x`| Mô-đun từ điển toàn cầu |
|`nonlocal x`| Phạm vi chức năng kèm theo gần nhất với`x`|
| không khai báo với bài tập | Phạm vi địa phương hiện tại |`nonlocal`không thể nhắm mục tiêu một mô-đun toàn cầu. Nó đòi hỏi một ràng buộc chức năng kèm theo.
## 39.15 Phân tích phạm vi và kết thúc
Trình biên dịch xác định bố cục đóng trong quá trình phân tích bảng ký hiệu.
Đối với mỗi khối mã, nó phân loại tên thành:```text
local
global explicit
global implicit
free
cell
```Ví dụ:```python
def outer():
x = 1
def inner():
return x
```Phân loại:```text
outer:
x = local, promoted to cell
inner = local
inner:
x = free
```Sự phân loại này quyết định hướng dẫn mã byte nào được phát ra.```text
local variable -> LOAD_FAST / STORE_FAST
global name -> LOAD_GLOBAL / STORE_GLOBAL
closure variable -> LOAD_DEREF / STORE_DEREF
```## 39.16 Thời gian đóng cửa
Một ô tồn tại miễn là có thứ gì đó tham chiếu đến nó.
Chủ sở hữu chung:```text
function closure tuple
active frame
generator frame
coroutine frame
another cell or object graph
```Ví dụ:```python
def outer():
x = [1, 2, 3]
def inner():
return x
return inner
fn = outer()
```Danh sách vẫn còn tồn tại:```text
fn
__closure__
cell
list [1, 2, 3]
```Khi`fn`trở nên không thể truy cập được, bộ dữ liệu đóng và ô có thể được giải phóng và danh sách có thể được giải phóng nếu không có tham chiếu nào khác tồn tại.
## 39.17 Việc đóng cửa thường không giữ được toàn bộ khung hình
Một sự hiểu lầm phổ biến là việc đóng giữ cho toàn bộ khung bên ngoài tồn tại.
Thông thường thì không.```python
def outer():
a = "captured"
b = "not captured"
def inner():
return a
return inner
```Hàm trả về cần`a`, nhưng không`b`.
Về mặt khái niệm:```text
inner keeps cell for a
inner does not keep b
outer frame can be destroyed
```Điều này hiệu quả hơn việc bảo toàn toàn bộ khung.
Tuy nhiên, nếu bản thân một đối tượng khung được ghi lại thông qua quá trình xem xét nội tâm thì nó có thể giữ cho tất cả các đối tượng cục bộ còn sống.
## 39.18 Ràng buộc muộn trong vòng lặp
Đóng cửa nắm bắt các biến, không phải giá trị trên mỗi lần lặp.```python
funcs = []
for i in range(3):
funcs.append(lambda: i)
print([f() for f in funcs])
```Đầu ra:```text
[2, 2, 2]
```Tất cả các lambda đều đóng trên cùng một biến`i`. Sau khi vòng lặp kết thúc,`i`là`2`.
Đây là ràng buộc muộn: giá trị được tra cứu khi hàm chạy chứ không phải khi nó được tạo.
## 39.19 Ghi lại các giá trị hiện tại bằng giá trị mặc định
Sử dụng đối số mặc định để nắm bắt giá trị hiện tại.```python
funcs = []
for i in range(3):
funcs.append(lambda i=i: i)
print([f() for f in funcs])
```Đầu ra:```text
[0, 1, 2]
```Ở đây, mỗi lambda có giá trị đối số mặc định riêng.
Điều này sử dụng các giá trị mặc định của hàm, không phải các ô đóng.
Về mặt khái niệm:```text
lambda i=0: i
lambda i=1: i
lambda i=2: i
```## 39.20 Đóng cửa trong sự hiểu biết
Sự hiểu biết có phạm vi riêng của chúng, nhưng sự đóng cửa bên trong chúng vẫn có thể cho thấy sự ràng buộc muộn.```python
funcs = [lambda: x for x in range(3)]
print([f() for f in funcs])
```Đầu ra:```text
[2, 2, 2]
```Biến vòng lặp`x`thuộc phạm vi hiểu và tất cả các lambda đều đóng trên cùng một ô đó.
Sử dụng giá trị mặc định để nắm bắt các giá trị trên mỗi lần lặp:```python
funcs = [lambda x=x: x for x in range(3)]
print([f() for f in funcs])
```Đầu ra:```text
[0, 1, 2]
```## 39.21 Đóng cửa và khả năng thay đổi
Một bao đóng có thể tham chiếu một đối tượng có thể thay đổi.```python
def outer():
xs = []
def add(x):
xs.append(x)
return xs
return add
add = outer()
print(add(1))
print(add(2))
```Đầu ra:```text
[1]
[1, 2]
```KHÔNG`nonlocal`là cần thiết vì hàm này làm thay đổi đối tượng danh sách. Nó không ràng buộc lại tên`xs`.
Điều này hoạt động:```python
xs.append(x)
```Điều này cần`nonlocal`:
```python
xs = xs + [x]
```Hình thức thứ hai gán lại tên.
## 39.22 Rebound vs Đột biến
So sánh:```python
def outer():
xs = []
def add(x):
xs.append(x)
return add
```Và:```python
def outer():
xs = []
def add(x):
xs = xs + [x]
return add
```Cái đầu tiên làm thay đổi đối tượng được tham chiếu bởi`xs`.
Thứ hai gán cho`xs`, do đó trình biên dịch xử lý`xs`như địa phương để`add`trừ khi được khai báo`nonlocal`.
Đảo ngược chính xác:```python
def outer():
xs = []
def add(x):
nonlocal xs
xs = xs + [x]
return xs
return add
```## 39.23 Đóng cửa và các nhà máy hoạt động
Closure thường được sử dụng cho các nhà máy chức năng.```python
def power(exp):
def apply(x):
return x ** exp
return apply
square = power(2)
cube = power(3)
print(square(5))
print(cube(5))
```Đầu ra:```text
25
125
```Mỗi cuộc gọi tới`power`tạo một ô mới cho`exp`.
```text
square closure:
exp = 2
cube closure:
exp = 3
```Đối tượng mã cho`apply`có thể được chia sẻ, nhưng các ô đóng khác nhau.
## 39.24 Đóng cửa và trang trí
Người trang trí thường sử dụng các bao đóng.```python
def log_calls(fn):
def wrapper(*args, **kwargs):
print("calling", fn.__name__)
return fn(*args, **kwargs)
return wrapper
```Sử dụng:```python
@log_calls
def add(a, b):
return a + b
```Về mặt khái niệm:```python
def add(a, b):
return a + b
add = log_calls(add)
```Sự trở lại`wrapper`đóng trên bản gốc`fn`.
```text
wrapper.__closure__
cell for fn -> original add function
```## 39,25 Đóng cửa và trạng thái
Closure có thể lưu trữ trạng thái riêng tư.```python
def counter():
n = 0
def inc():
nonlocal n
n += 1
return n
return inc
c = counter()
print(c())
print(c())
```Đầu ra:```text
1
2
```Nhà nước`n`không được lưu trữ trên một phiên bản. Nó được lưu trữ trong một ô đóng cửa.
Điều này tương tự như một đối tượng nhỏ với một phương thức và trạng thái riêng tư.
## 39.26 Trạng thái đóng so với Trạng thái đối tượng
Phiên bản đóng cửa:```python
def counter():
n = 0
def inc():
nonlocal n
n += 1
return n
return inc
```Phiên bản đối tượng:```python
class Counter:
def __init__(self):
self.n = 0
def inc(self):
self.n += 1
return self.n
```So sánh:
| Tính năng | Đóng cửa | Đối tượng |
|---|---|---|
| Lưu trữ nhà nước | Biến ô | Thuộc tính sơ thẩm |
| Nhiều hoạt động | Ít thuận tiện hơn | Tự nhiên |
| Hướng nội | Ít rõ ràng hơn | Rõ ràng hơn |
| Trạng thái gọi lại nhỏ | Phù hợp tốt | Phù hợp tốt |
| Hành vi phong phú | Lúng túng | Tốt hơn |
Đóng cửa là tốt nhất cho trạng thái bị bắt nhỏ. Các lớp học tốt hơn cho các giao thức lớn hơn.
## 39.27 Đóng cửa và Chu kỳ tham chiếu
Việc đóng cửa có thể tham gia vào các chu kỳ.```python
def outer():
funcs = []
def inner():
return funcs
funcs.append(inner)
return inner
fn = outer()
```Biểu đồ tham khảo:```text
inner function
closure cell
funcs list
inner function
```Chu trình này có thể được thu thập bởi trình thu gom rác tuần hoàn của CPython khi không thể truy cập được.
Các chu trình liên quan đến khâu quyết toán hoặc nguồn lực bên ngoài cần được quan tâm nhiều hơn.
## 39.28 Đóng và lưu giữ bộ nhớ
Đóng cửa có thể giữ lại các đối tượng lớn.```python
def make_reader():
data = bytearray(100_000_000)
def read():
return data[0]
return read
reader = make_reader()
```Cái lớn`data`đối tượng vẫn còn sống miễn là`reader`làm.
Chuỗi lưu giữ:```text
reader function
closure tuple
cell
large bytearray
```Nếu việc đóng không còn cần đối tượng lớn nữa, hãy xóa hoặc tránh chụp đối tượng đó.
## 39.29 Tránh vô tình bị bắt
Điều này nắm bắt`self`:
```python
class C:
def make_callback(self):
def callback():
return self.value
return callback
```Cuộc gọi lại được trả về sẽ giữ cho phiên bản này tồn tại.
Đôi khi điều này được dự định. Đôi khi nó tạo ra sự giữ chân không ngờ tới.
Bạn chỉ có thể nắm bắt giá trị cần thiết:```python
class C:
def make_callback(self):
value = self.value
def callback():
return value
return callback
```Bây giờ cuộc gọi lại tiếp tục`value`, không nhất thiết là toàn bộ trường hợp.
## 39.30 Kiểm tra nội dung đóng cửa
sử dụng`__closure__`cẩn thận:```python
def outer():
x = {"a": 1}
def inner():
return x
return inner
fn = outer()
for name, cell in zip(fn.__code__.co_freevars, fn.__closure__):
print(name, cell.cell_contents)
```Đầu ra:```text
x {'a': 1}
```Điều này hữu ích cho việc học và gỡ lỗi, nhưng mã sản xuất hiếm khi phụ thuộc vào nội bộ đóng.
## 39.31 Ô trống
Ô đóng có thể trống trong một số trường hợp cạnh.
Các mẫu ví dụ liên quan đến việc xóa có thể tạo ra các ô trống:```python
def outer():
x = 1
def inner():
return x
del x
return inner
```Gọi:```python
fn = outer()
fn()
```gây ra lỗi vì ô không còn nội dung nữa.
Truy cập`cell.cell_contents`đối với một ô trống tăng lên`ValueError`.
## 39.32 Đóng cửa và`del`Việc xóa một biến không cục bộ sẽ xóa ô.```python
def outer():
x = 1
def delete():
nonlocal x
del x
def read:
return x
return read, delete
```Phiên bản đã sửa:```python
def outer():
x = 1
def delete():
nonlocal x
del x
def read():
return x
return read, delete
```Sử dụng:```python
read, delete = outer()
print(read())
delete()
print(read())
```trận chung kết`read()`tăng vì ô trống.
## 39.33 Đóng cửa và mặc định là khác nhau
Giá trị mặc định được lưu trữ trên đối tượng hàm.```python
def f(x=[]):
return x
```Các ô đóng cửa được lưu trữ trong`__closure__`.
```python
def outer():
x = []
def inner():
return x
return inner
```Thanh tra:```python
print(f.__defaults__)
print(outer().__closure__)
```Họ giải quyết các vấn đề khác nhau.
| Cơ chế | Cửa hàng |
|---|---|
| Đối số mặc định | Giá trị được sử dụng khi đối số bị bỏ qua |
| Tế bào đóng cửa | Biến từ phạm vi kèm theo |
Thủ thuật đối số mặc định để liên kết muộn hoạt động vì các giá trị mặc định được đánh giá tại thời điểm tạo hàm.
## 39.34 Đóng cửa và Lambdas`lambda`các hàm tuân theo các quy tắc đóng tương tự như`def`.
```python
def outer():
x = 10
return lambda y: x + y
fn = outer()
print(fn(5))
```Đầu ra:```text
15
```Lambda có một biến miễn phí`x`.
```python
print(fn.__code__.co_freevars)
print(fn.__closure__[0].cell_contents)
```Lambda chỉ là một biểu thức hàm thu gọn. Nó không có mô hình đóng cửa đặc biệt.
## 39.35 Đóng cửa và Máy phát điện
Một trình tạo có thể đóng các biến.```python
def outer(limit):
def gen():
for i in range(limit):
yield i
return gen
make = outer(3)
print(list(make()))
```Chức năng máy phát điện đóng lại`limit`.
Khi`make()`được gọi, nó tạo ra một đối tượng máy phát điện. Đối tượng trình tạo đó có thể truy cập vào ô đóng.
Có hai lớp:```text
generator function
closure cell for limit
generator object
suspended frame when running
references generator function/code/closure state
```## 39.36 Đóng và Coroutine
Các hàm không đồng bộ cũng có thể đóng các biến.```python
def outer(delay):
async def wait_then_return(value):
await sleep(delay)
return value
return wait_then_return
```Chức năng async đóng lại`delay`.
Việc gọi nó sẽ tạo ra một đối tượng coroutine. Trong khi bị treo, coroutine vẫn giữ trạng thái khung và hàm mang các ô đóng.
Điều này có thể giữ lại các đối tượng bị bắt trong thời gian chờ đợi.
## 39.37 Hiệu suất đóng cửa
Truy cập một biến đóng thường chậm hơn so với truy cập cục bộ nhanh.
Địa phương nhanh:```text
LOAD_FAST
```Biến đóng cửa:```text
LOAD_DEREF
LOAD_DEREFphải đọc qua một ô.
Trong hầu hết các mã, chi phí này là nhỏ. Trong các vòng lặp rất nóng, ràng buộc cục bộ có thể quan trọng.
Ví dụ:python def outer(value): def inner(xs): v = value total = 0 for x in xs: total += x + v return total return inner Đây,vlà một người địa phương nhanh chóng bên tronginner, trong khivalueđược đọc từ một ô một lần.
39.38 Gỡ lỗi đóng cửa
Khi gỡ lỗi hành vi đóng, hãy kiểm tra:python fn.__code__.co_freevars fn.__closure__ cell.cell_contents Ví dụ:```python
def outer():
x = 1
y = 2
def inner():
return x + y
return inner
fn = outer()
for name, cell in zip(fn.code.co_freevars, fn.closure): print(name, cell.cell_contents)
## 39.39 Những hiểu lầm thường gặp
| Hiểu lầm | Đúng mẫu |
|---|---|
| Giá trị sao chép đóng cửa | Họ nắm bắt các biến thông qua các ô |
| Việc đóng cửa giữ cho toàn bộ khung bên ngoài tồn tại | Thông thường nó chỉ giữ những ô cần thiết |
|`nonlocal`có nghĩa là toàn cầu | Nó nhắm đến một phạm vi chức năng kèm theo |
| Thay đổi nhu cầu danh sách đã chụp`nonlocal`| Chỉ cần đảo ngược tên`nonlocal`|
| Lambdas có quy tắc đóng khác nhau | Lambda và`def`sử dụng cùng một mô hình đóng cửa |
| Việc đóng vòng lặp nắm bắt từng giá trị lặp lại | Họ nắm bắt biến vòng lặp |
| Mặc định và đóng cửa giống nhau | Giá trị lưu trữ mặc định; đóng cửa các tế bào lưu trữ |
| Các biến đóng cửa là các biến cục bộ nhanh | Chúng được truy cập thông qua các ô |
##39.40 Chiến lược đọc
Bắt đầu với:```python
def outer():
x = 10
def inner():
return x
return inner
```Thanh tra:```python
import dis
fn = outer()
print(outer.__code__.co_cellvars)
print(fn.__code__.co_freevars)
print(fn.__closure__)
print(fn.__closure__[0].cell_contents)
dis.dis(outer)
dis.dis(fn)
```Sau đó kiểm tra:```text
nonlocal rebinding
multiple inner functions sharing one variable
lambda inside loops
default-argument capture
closures holding large objects
closures inside generators
closures inside async functions
```Đối với mỗi trường hợp, theo dõi:```text
which scope binds the name
whether the name becomes a cell variable
which inner function sees it as a free variable
which function owns the closure tuple
how long the cell remains alive
```## 39.41 Tóm tắt chương
Các bao đóng là cơ chế của CPython để cho phép các hàm lồng nhau truy cập các biến từ phạm vi hàm kèm theo. Khi một biến cục bộ bên ngoài được hàm bên trong sử dụng, CPython sẽ lưu trữ biến đó trong một ô. Hàm bên trong mang một bộ đóng chứa các ô cần thiết.
Mô hình cốt lõi là:```text
outer function local used by inner function
↓
local becomes a cell variable
↓
inner function records it as a free variable
↓
function object stores closure tuple
↓
cell remains alive after outer frame returns
↓
inner function reads or writes cell contents
```Các bao đóng giải thích các hàm lồng nhau, trình trang trí, nhà máy hàm, trạng thái gọi lại,`nonlocal`, liên kết muộn trong các vòng lặp và duy trì bộ nhớ thông qua các biến được ghi lại.