#38. Sự hiểu biết

Sự hiểu biết là cú pháp nhỏ gọn để xây dựng các thùng chứa hoặc các trình vòng lặp giống như trình tạo từ một vòng lặp khác. CPython triển khai chúng dưới dạng đối tượng mã được biên dịch với phạm vi thực thi riêng.

Các hình thức phổ biến:python [x * 2 for x in xs] {x * 2 for x in xs} {x: x * 2 for x in xs} (x * 2 for x in xs) Những điều này tương ứng với:```text list comprehension set comprehension dict comprehension generator expression


## 38.1 Hiểu danh sách

Vic hiu danh sách s xây dng mt danh sách mt cách háo hc.```python
ys = [x * 2 for x in xs]
```V mt khái nim:```python
ys = []
for x in xs:
    ys.append(x * 2)
```Kết qu là mt đối tượng danh sách cha tt c các giá tr được to ra.

Biu mu ngun ngn hơn nhưng công vic trong thi gian chy vn là các thao tác lp, đánh giá biu thc và ni thêm.

## 38.2 Lọc

S hiu biết có th bao gm mt`if`khon.```python
ys = [x * 2 for x in xs if x > 0]
```V mt khái nim:```python
ys = []
for x in xs:
    if x > 0:
        ys.append(x * 2)
```B lc chy cho tng mc. Nếu điu kin sai thì biu thc phn t s không chy cho mc đó.

## 38.3 Nhiều`for`khoản

S hiu biết có th cha các vòng lp lng nhau.```python
pairs = [(x, y) for x in xs for y in ys]
```V mt khái nim:```python
pairs = []
for x in xs:
    for y in ys:
        pairs.append((x, y))
```Th t t trái sang phi, khp vi th t vòng lp lng nhau.

Vì:```python
[(x, y, z) for x in xs for y in ys for z in zs]
```t vòng lp khái nim là:```python
result = []
for x in xs:
    for y in ys:
        for z in zs:
            result.append((x, y, z))
```## 38.4 Nhiều bộ lọc

B lc gn vào cp độ vòng lp nơi chúng xut hin.```python
result = [x for x in xs if x > 0 if x % 2 == 0]
```V mt khái nim:```python
result = []
for x in xs:
    if x > 0:
        if x % 2 == 0:
            result.append(x)
```Vi nhiu vòng lp:```python
result = [(x, y) for x in xs if x > 0 for y in ys if y > x]
```V mt khái nim:```python
result = []
for x in xs:
    if x > 0:
        for y in ys:
            if y > x:
                result.append((x, y))
```Th t quan trng vì các mnh đề sau có th s dng các tên b ràng buc bi các mnh đề trước đó.

## 38.5 Phạm vi hiểu

Trong Python 3, vic hiu có phm vi riêng.```python
x = 100
ys = [x for x in range(3)]
print(x)
```Đầu ra:```text
100
```các`x`bên trong s hiu biết không ghi đè lên bên ngoài`x`.

V mt khái nim, s hiu biết hot động ging như mt hàm lng nhau nh:```python
def _listcomp(iterable):
    result = []
    for x in iterable:
        result.append(x)
    return result

ys = _listcomp(range(3))
```Đây không phi là s chuyn đổi ngun chính xác nhưng nó gii thích phm vi.

## 38.6 Tại sao phần hiểu lại có đối tượng mã riêng

Mt s hiu biết cn mt nơi để lưu tr các biến vòng lp ca nó mà không rò r chúng ra phm vi xung quanh.

CPython gii quyết vn đề này bng cách biên dch nhiu phn hiu thành các đối tượng mã lng nhau.

Ví d:```python
def f(xs):
    return [x * 2 for x in xs]
```Hàm bên ngoài có mt đối tượng mã. Vic hiu danh sách có mt đối tượng mã khác được lưu tr trong các hng s ca đối tượng mã bên ngoài.

Bn có th kim tra điu này:```python
def f(xs):
    return [x * 2 for x in xs]

for const in f.__code__.co_consts:
    print(type(const), const)
```Mt hng s thường là mt đối tượng mã lng nhau để d hiu.

## 38.7 Phân tách sự hiểu biết về danh sách

s dng`dis`:

```python
import dis

def f(xs):
    return [x * 2 for x in xs]

dis.dis(f)
```Sau đó kim tra các đối tượng mã lng nhau:```python
for const in f.__code__.co_consts:
    if hasattr(const, "co_code"):
        dis.dis(const)
```Bn s thy hai lp:```text
outer function:
    create comprehension function
    get iterator from xs
    call comprehension function
    return list

inner comprehension:
    build list
    iterate input
    compute x * 2
    append to list
    return list
```Mã byte chính xác thay đổi trên các phiên bn CPython, nhưng hình dng vn gi nguyên.

## 38.8 Tối ưu hóa việc nối thêm danh sách

Vic hiu danh sách thường s dng mt đường dn mã byte ni thêm danh sách chuyên bit.

V mt khái nim:```python
result.append(value)
```Nhưng CPython có th tránh được vic tra cu phương thc thông thường cho mi phn b sung.

Thay vì làm điu này cho tng mc:```text
load result.append
call append
```cơ quan hiu có th s dng thao tác chp thêm ni b.

V mt khái nim:```text
LIST_APPEND
```Điu này giúp tiết kim chi phí tra cu thuc tính và gi phương thc lp đi lp li.

Đây là mt lý do khiến vic hiu danh sách thường nhanh hơn các vòng lp cp Python tương đương vi`append`.

## 38.9 Hiểu bộ

S hiu biết v tp hp s xây dng mt tp hp mt cách háo hc.```python
unique = {x.lower() for x in words}
```V mt khái nim:```python
unique = set()
for x in words:
    unique.add(x.lower())
```Kết qu cha các phn t duy nht theo phép băm và đẳng thc tp hp thông thường.

Vic hiu tp hp s dng hành vi thêm tp hp trong ni b, tương t như cách hiu danh sách s dng hành vi ni thêm.

## 38.10 Hiểu chính tả

Kh năng hiu chính t s xây dng mt t đin mt cách háo hc.```python
index = {item.id: item for item in items}
```V mt khái nim:```python
index = {}
for item in items:
    index[item.id] = item
```Nếu khóa trùng lp xut hin, các giá tr sau s ghi đè các giá tr trước đó:```python
d = {x % 2: x for x in range(5)}
print(d)
```Đầu ra:```text
{0: 4, 1: 3}
```Vic hiu tuân theo ng nghĩa phân công t đin thông thường.

## 38.11 Trình tạo biểu thức

Mt biu thc ca trình to là lười biếng.```python
g = (x * 2 for x in xs)
```Nó không xây dng mt danh sách ngay lp tc. Nó to ra mt đối tượng ging như trình to để tính toán các giá tr khi lp li.```python
g = (x * 2 for x in range(3))

print(next(g))
print(next(g))
print(next(g))
```Đầu ra:```text
0
2
4
```Sau khi kit sc, nó tăng lên`StopIteration`.

## 38.12 Biểu thức trình tạo và hiểu danh sách

So sánh:```python
[x * 2 for x in xs]
```Và:```python
(x * 2 for x in xs)
```| Tính năng | Danh sách hiu | Biu thc máy phát đin |
|---|---|---|
| Đánh giá | Háo hc | Lười biếng |
| Kết qu | Danh sách | Đối tượng máy phát đin |
| Ký c | Lưu tr tt c kết qu | Lưu tr trng thái thc thi |
| Lp li | Có th lp li kết qu nhiu ln | Mt ln |
| Cú pháp | Du ngoc vuông | Du ngoc đơn |
| Trường hp s dng | Cn tt c các giá tr ngay bây gi | Giá tr lung |

Vic hiu danh sách thường nhanh hơn khi bn cn danh sách đầy đủ.

Biu thc trình to thường tt hơn khi bn mun truyn phát các giá tr hoc dng sm.

## 38.13 Bản chất một lần của biểu thức tạo

Mt biu thc trình to được s dng mt ln.```python
g = (x for x in range(3))

print(list(g))
print(list(g))
```Đầu ra:```text
[0, 1, 2]
[]
```đầu tiên`list(g)`làm cn kit nó.

Nếu bn cn d liu có th tái s dng, hãy to danh sách hoc vùng cha khác.

## 38.14 Dừng sớm

Biu thc ca trình to rt hu ích vi người tiêu dùng dng sm.```python
first = next(x for x in xs if x > 100)
```Vic này ch tính toán cho đến khi tìm thy phn t phù hp đầu tiên.

Mt phiên bn hiu danh sách:```python
first = [x for x in xs if x > 100][0]
```xây dng danh sách đầy đủ các kết qu phù hp trước khi chn mc đầu tiên.

Đối vi đầu vào ln hoc vô hn, biu thc trình to là mô hình chính xác.

## 38.15 Hiểu và kết thúc

S hiu biết có th nm bt các biến bên ngoài.```python
def scale(xs, factor):
    return [x * factor for x in xs]
```S hiu biết s dng`factor`t chc năng bên ngoài.

V mt khái nim:```text
outer function frame:
    factor stored in local or cell

comprehension code object:
    reads factor as free variable
```Trình biên dch sp xếp các ô đóng khi kh năng hiu cn truy cp vào các biến phm vi bên ngoài.

## 38.16 Liên kết biến vòng lặp

Biến vòng lp thuc phm vi hiu.```python
def f():
    x = "outer"
    ys = [x for x in range(3)]
    return x, ys

print(f())
```Đầu ra:```text
('outer', [0, 1, 2])
```Bên trong s hiu biết,`x`là mt cc b ca đối tượng mã hiu.

Bên ngoài`x`vn không thay đổi.

## 38.17 Biểu thức gán ở dạng hiểu

Biu thc gán có th xut hin trong phn hiu.```python
result = [y for x in xs if (y := f(x)) > 0]
```Các quy tc ràng buc là tinh tế. Biu thc gán liên kết trong phm vi cha, không phi trong phm vi hiu ngm theo cách tương t như biến vòng lp.

Ví d:```python
def f(xs):
    result = [y for x in xs if (y := x * 2) > 3]
    return y, result
```Sau khi hiu rõ,`y`có th hin th trong phm vi hàm cha nếu xy ra ít nht mt phép gán.

Hành vi này tn ti vì các biu thc gán được thiết kế để cung cp tên được gán bên ngoài mt s ng cnh cc b ca biu thc.

## 38.18 Sự hiểu biết lồng nhau

Mt s hiu biết có th cha đựng mt s hiu biết khác.```python
matrix = [[i * j for j in range(3)] for i in range(3)]
```V mt khái nim:```python
matrix = []
for i in range(3):
    row = []
    for j in range(3):
        row.append(i * j)
    matrix.append(row)
```Mi cách hiu có đối tượng và phm vi mã riêng.

Do đó, kh năng hiu lng nhau có th to ra các lp thc thi ging như hàm lng nhau.

## 38.19 Hiểu Từ điển

Lp li mt t đin mang li các khóa.```python
keys = [k for k in d]
```Để s dng các giá tr:```python
values = [v for v in d.values()]
```Để s dng cp khóa-giá tr:```python
pairs = [(k, v) for k, v in d.items()]
```Mt phép biến đổi chung:```python
inverted = {v: k for k, v in d.items()}
```Nếu các giá tr b trùng lp, các khóa sau s ghi đè các khóa trước đó vì các khóa t đin phi là duy nht.

## 38.20 Thứ tự hiểu và đánh giá

Mnh đề hiu thc hin t trái sang phi.```python
[(x, y) for x in xs for y in f(x)]
```Đối vi mi`x`, `f(x)`được đánh giá để to ra ln lp bên trong.

V mt khái nim:```python
result = []
for x in xs:
    for y in f(x):
        result.append((x, y))
```Điu này có nghĩa là các mnh đề sau có th ph thuc vào các biến vòng lp trước đó.

Biu thc phn t ch chy sau khi tt c các mnh đề vòng lp và b lc cho giá tr đầu ra đó đã thành công.

## 38.21 Tác dụng phụ

S hiu biết có th cha đựng nhng tác dng ph, nhưng thường nên được s dng để to ra các giá tr.

Có th nhưng phong cách kém:```python
[print(x) for x in xs]
```Điu này xây dng mt danh sách`None`giá tr ch để thc hin in n.

Thích hơn:```python
for x in xs:
    print(x)
```S dng s hiu biết khi kết qu quan trng.

## 38.22 Ngoại lệ trong cách hiểu

Các ngoi l lan truyn bình thường.```python
result = [10 / x for x in xs]
```Nếu như`x`bng không,`ZeroDivisionError`lan truyn và s hiu biết dng li.

Các vùng cha ni b được xây dng mt phn s b loi b tr khi được tham chiếu  nơi khác, điu mà các phn ni b hiu thông thường không tiết l.

Đối vi các biu thc ca trình to, các ngoi l xy ra mt cách lười biếng:```python
g = (10 / x for x in xs)
```To`g`không phân chia. Ngoi l xy ra khi mc có vn đề được yêu cu.

## 38.23 Sự hiểu biết và`try`Sự hiểu biết không cho phép những phát biểu như`try`ngay bên trong chúng.

Không hp l:```python
[x for x in xs try ...]
```S dng chc năng tr giúp:```python
def parse_or_none(x):
    try:
        return int(x)
    except ValueError:
        return None

values = [y for x in xs if (y := parse_or_none(x)) is not None]
```Hoc s dng vòng lp thông thường khi x lý ngoi l là trung tâm:```python
values = []
for x in xs:
    try:
        values.append(int(x))
    except ValueError:
        pass
```## 38.24 Hiểu biết không đồng bộ

Bên trong`async def`, s hiu biết có th s dng`async for`.

```python
async def collect(stream):
    return [item async for item in stream]
```V mt khái nim:```python
result = []
async for item in stream:
    result.append(item)
return result
```H cũng có th s dng`await`trong biu thc phn t hoc b lc:```python
async def collect(xs):
    return [await process(x) for x in xs]
```Kh năng hiu không đồng b s biên dch thành mã byte nhn biết không đồng b và có th tm dng trong khi thc thi.

## 38.25 Biểu thức trình tạo không đồng bộ

Biu thc trình to không đồng b có th s dng`async for`.

```python
gen = (item async for item in stream)
```Nó to ra mt đối tượng ging như trình to không đồng b được s dng vi`async for`hoc`anext`.

```python
async for item in gen:
    ...
```Mô hình thc thi kết hp phm vi hiu vi phép lp không đồng b và tm ngưng coroutine.

## 38.26 Sự hiểu biết và`locals()`Bởi vì sự hiểu biết có phạm vi riêng của nó,`locals()`bên trong một trình trợ giúp giống như hiểu sẽ nhìn thấy các biến cục bộ hiểu, không chính xác là các biến cục bộ xung quanh.

Điu này d thy hơn vi các hàm tr giúp so vi cú pháp trc tiếp vì kh năng hiu hn chế các câu lnh.

Nguyên tc quan trng:```text
loop variables in comprehensions do not leak into the surrounding scope
```Đối vi mã thông thường, hãy da vào quy tc đó thay vì chi tiết v`locals()`bên trong các khung do trin khai thc hin.

## 38.27 Hiểu biết và ràng buộc muộn

Vic đóng ca bên trong s hiu biết vn có th hin th hành vi ràng buc mun.```python
funcs = [lambda: x for x in range(3)]
print([f() for f in funcs])
```Đầu ra:```text
[2, 2, 2]
```Mi lambda đóng trên cùng mt biến hiu`x`, có giá tr cui cùng là`2`.

S dng đối s mc định để nm bt giá tr hin ti:```python
funcs = [lambda x=x: x for x in range(3)]
print([f() for f in funcs])
```Đầu ra:```text
[0, 1, 2]
```Phm vi hiu ngăn chn s rò r ra bên ngoài, nhưng nó không to ra mt ràng buc mi cho mi ln lp đối vi các bao đóng.

## 38.28 Mức độ hiểu và thời gian tham khảo

Vic hiu danh sách không gi cho khung ca nó tn ti sau khi hoàn thành tr khi có th gì đó nm bt được nó.

Tuy nhiên, biu thc trình to vn gi trng thái ging khung ca nó trong khi b treo.```python
g = (x * 2 for x in range(10))
```Biu thc trình to gi:```text
code object
iteration state
current iterator
locals
suspended frame state
```Nếu nó bt được mt vt th ln, vt th đó có th vn còn sng cho đến khi máy phát đin cn kit hoc b loi b.```python
def f():
    big = bytearray(100_000_000)
    return (x for x in range(3) if big is not None)

g = f()
```Đây,`big`vn còn tn ti thông qua vic đóng biu thc trình to.

## 38.29 Hiểu biết và Hiệu suất

Vic hiu danh sách thường nhanh hơn các vòng lp tương đương vì CPython có th s dng các hot động ni b chuyên bit.

Ví d:```python
result = []
for x in xs:
    result.append(x * 2)
```So sánh vi:```python
result = [x * 2 for x in xs]
```Vic hiu có th tránh vic lp li vic tra cu phương thc cp Python cho`append`.

Tuy nhiên, hiu sut ph thuc vào biu thc, kích thước d liu, phiên bn Python và liu độ lười có quan trng hay không.

Nguyên tc chung:```text
use list/set/dict comprehensions when building that container directly
use generator expressions when streaming or stopping early
use explicit loops when control flow is complex
```## 38.30 Khả năng hiểu và dễ đọc

S hiu biết rõ ràng nht khi chúng phù hp vi mt s chuyn đổi đơn gin.

Tt:```python
names = [user.name for user in users]
```Tt:```python
active = [user for user in users if user.active]
```Thường quá dày đặc:```python
result = [(a, b, c) for a in xs if p(a) for b in f(a) if q(b) for c in g(a, b) if r(c)]
```S dng vòng lp rõ ràng khi có nhiu mnh đề, tác dng ph, x lý ngoi l hoc phân nhánh phc tp.

## 38,31 Luồng đối tượng CPython

Để hiu danh sách:```python
[x * 2 for x in xs]
```CPython v mt khái nim thc hin:```text
create result list
get iterator from xs
loop:
    get next item
    store item in comprehension local x
    load x
    load constant 2
    multiply
    append to result list
return result list
```Đối tượng danh sách được gi bên trong khung hiu trong khi nó đang được xây dng.

Để hiu chính t:```python
{x: x * 2 for x in xs}
```dòng chy là:```text
create result dict
iterate xs
compute key
compute value
store key-value pair
return dict
```## 38.32 Tên đối tượng mã hiểu

Các đối tượng mã hiu có tên ni b như:```text
<listcomp>
<setcomp>
<dictcomp>
<genexpr>
```Bn có th nhìn thy chúng trong quá trình truy nguyên và xem xét ni tâm.

Ví d:```python
def f(xs):
    return [10 / x for x in xs]

f([2, 1, 0])
```Truy nguyên có th bao gm`<listcomp>`vì ngoi l xy ra bên trong đối tượng mã hiu.

Điu này cho thy rng vic thc thi hiu có bi cnh ging như khung riêng ca nó.

## 38.33 Truy tìm lại sự hiểu biết

Nếu mt ngoi l xy ra bên trong phn hiu, thì quá trình truy nguyên có th bao gm c chc năng bên ngoài và phn hiu.```python
def f(xs):
    return [10 / x for x in xs]

f([1, 0])
```Vic chia cho s 0 xy ra bên trong mã hiu.

V mt khái nim:```text
frame f
    calls <listcomp>
        division by zero
```Đây là mt hiu ng có th nhìn thy khác ca vic hiu các đối tượng mã.

## 38.34 Khả năng hiểu có thể thay đổi trọn đời

Mt biến vòng lp hiu tn ti trong phm vi hiu.

Sau khi hoàn thành:```python
def f():
    result = [x for x in range(3)]
    return "x" in locals()

print(f())
```Điu này tr v:```text
False
```Biến vòng lp`x`đã không tr thành người địa phương `f`.

Bên trong khung hiu,`x`tn ti trong khi s hiu biết chy.

## 38.35 Phím tắt đối số biểu thức trình tạo

Mt biu thc trình to có th được chuyn làm đối s duy nht cho hàm mà không cn thêm du ngoc đơn.```python
total = sum(x * x for x in xs)
```Điu này tương đương vi:```python
total = sum((x * x for x in xs))
```Nhưng nếu có nhiu đối s thì bt buc phi có du ngoc đơn:```python
result = func((x for x in xs), other)
```Đây là s tin li  cp độ cú pháp. Đối tượng thi gian chy vn là biu thc trình to.

## 38.36 Hiểu biết và tích hợp

S hiu biết thường kết hp vi các phn dng sn.

Ví d:```python
sum(x for x in xs)
any(x > 0 for x in xs)
all(x.valid for x in items)
max(score(x) for x in xs)
```Chúng s dng các biu thc ca trình to và có th dng sm trong mt s trường hp.`any`dng  giá tr thc đầu tiên.`all`dng  giá tr sai đầu tiên.`sum`tiêu th toàn b máy phát đin.

Vic chn biu thc trình to s tránh to danh sách trung gian không cn thiết.

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

| Hiu lm | Đúng mu |
|---|---|
| Vic hiu ch là viết li cú pháp trong cùng mt phm vi | Nó thường có đối tượng và phm vi mã lng nhau |
| Biến vòng lp rò r ra phm vi bên ngoài | Trong Python 3 thì không |
| Biu thc trình to xây dng mt b d liu | Nó to ra mt đối tượng máy phát đin |
| Vic hiu danh sách luôn tt hơn | Biu thc ca trình to tt hơn cho vic phát trc tuyến và dng sm |
| S hiu biết không th nm bt được các biến bên ngoài | H có th nm bt thông qua vic đóng ca |
| Mi lambda trong mt cách hiu s nm bt mt biến vòng lp khác nhau | H thường chia s cùng mt biến hiu biết ràng buc |
| Các ngoi l xy ra khi biu thc trình to được to | Chúng xy ra khi nó được tiêu th |
| Hiu chính t gi các khóa trùng lp | Các giá tr sau ghi đè lên các giá tr trước đó |

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

Bt đầu vi:```python
def f(xs):
    return [x * 2 for x in xs if x > 0]
```Thanh tra:```python
import dis

dis.dis(f)

for const in f.__code__.co_consts:
    if hasattr(const, "co_code"):
        print(const.co_name)
        dis.dis(const)
```Sau đó so sánh vi:```python
def g(xs):
    return (x * 2 for x in xs if x > 0)
```Theo dõi:```text
outer function bytecode
nested comprehension code object
iteration setup
local loop variable
filter jump
append or yield operation
return value
closure variables
```Sau đó nghiên cu các cách hiu v tp hp, chính t, lng nhau và không đồng b.

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

Phn hiu là các đơn v thc thi được biên dch để xây dng danh sách, b, t đin hoc các trình vòng lp ging như trình to. Chúng kết hp vic lp li, lc, đánh giá biu thc, liên kết và xây dng vùng cha  dng biu thc.

Mô hình ct lõi là:```text
evaluate outer iterable
    
create comprehension execution scope
    
iterate
    
apply filters
    
compute element, key-value pair, or yielded value
    
append, add, store, or yield
    
return container or generator object
```Kh năng hiu danh sách, tp hp và chính t rt háo hc. Biu thc ca trình to là lười biếng. CPython trin khai các cu trúc này bng cách s dng các đối tượng mã lng nhau, trng thái khung, x lý đóng, các hot động mã byte chuyên dng và truyn bá ngoi l thông thường.