Lưu ý : đây là một lỗi trong việc CPython xử lý các yieldbiểu thức hiểu và trình tạo, được sửa trong Python 3.8, với cảnh báo không dùng nữa trong Python 3.7. Xem báo cáo lỗi Python và các mục nhập Có gì mới cho Python 3.7 và Python 3.8 .
Biểu thức trình tạo, và tập hợp và hiểu chính tả được biên dịch thành các đối tượng hàm (trình tạo). Trong Python 3, các phần hiểu danh sách có cùng cách xử lý; về bản chất, tất cả chúng đều là một phạm vi lồng nhau mới.
Bạn có thể thấy điều này nếu bạn cố gắng tháo rời một biểu thức trình tạo:
>>> dis.dis(compile("(i for i in range(3))", '', 'exec'))
  1           0 LOAD_CONST               0 (<code object <genexpr> at 0x10f7530c0, file "", line 1>)
              3 LOAD_CONST               1 ('<genexpr>')
              6 MAKE_FUNCTION            0
              9 LOAD_NAME                0 (range)
             12 LOAD_CONST               2 (3)
             15 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             18 GET_ITER
             19 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             22 POP_TOP
             23 LOAD_CONST               3 (None)
             26 RETURN_VALUE
>>> dis.dis(compile("(i for i in range(3))", '', 'exec').co_consts[0])
  1           0 LOAD_FAST                0 (.0)
        >>    3 FOR_ITER                11 (to 17)
              6 STORE_FAST               1 (i)
              9 LOAD_FAST                1 (i)
             12 YIELD_VALUE
             13 POP_TOP
             14 JUMP_ABSOLUTE            3
        >>   17 LOAD_CONST               0 (None)
             20 RETURN_VALUE
Ở trên cho thấy rằng một biểu thức trình tạo được biên dịch thành một đối tượng mã, được tải dưới dạng một hàm ( MAKE_FUNCTIONtạo đối tượng hàm từ đối tượng mã). Các .co_consts[0]tài liệu tham khảo cho chúng ta thấy đối tượng mã được tạo cho các biểu hiện, và nó sử dụng YIELD_VALUEgiống như một chức năng máy phát điện sẽ.
Như vậy, yieldbiểu thức hoạt động trong ngữ cảnh đó, vì trình biên dịch coi đây là những hàm trong ngụy trang.
Đây là một lỗi; yieldkhông có vị trí trong các biểu thức này. Ngữ pháp Python trước Python 3.7 cho phép nó (đó là lý do tại sao mã có thể biên dịch được), nhưng yieldđặc tả biểu thức cho thấy rằng việc sử dụng yieldở đây không thực sự hoạt động:
  Biểu thức sản lượng chỉ được sử dụng khi xác định hàm bộ tạo và do đó chỉ có thể được sử dụng trong phần thân của định nghĩa hàm.
Đây đã được xác nhận là một lỗi trong số 10544 . Giải pháp của lỗi là sử dụng yieldvà yield fromsẽ tăng a SyntaxErrortrong Python 3.8 ; trong Python 3.7, nó tăng mộtDeprecationWarning để đảm bảo mã ngừng sử dụng cấu trúc này. Bạn sẽ thấy cảnh báo tương tự trong Python 2.7.15 trở lên nếu bạn sử dụng công -3tắc dòng lệnh bật cảnh báo tương thích Python 3.
Cảnh báo 3.7.0b1 trông như thế này; chuyển cảnh báo thành lỗi sẽ cho bạn một SyntaxErrorngoại lệ, giống như bạn làm trong 3.8:
>>> [(yield i) for i in range(3)]
<stdin>:1: DeprecationWarning: 'yield' inside list comprehension
<generator object <listcomp> at 0x1092ec7c8>
>>> import warnings
>>> warnings.simplefilter('error')
>>> [(yield i) for i in range(3)]
  File "<stdin>", line 1
SyntaxError: 'yield' inside list comprehension
Sự khác biệt giữa cách thức hoạt động trong cách yieldhiểu danh sách và yieldtrong biểu thức trình tạo bắt nguồn từ sự khác biệt trong cách hai biểu thức này được triển khai. Trong Python 3, tính năng hiểu danh sách sử dụng LIST_APPENDcác lệnh gọi để thêm phần trên cùng của ngăn xếp vào danh sách đang được xây dựng, trong khi biểu thức trình tạo thay thế mang lại giá trị đó. Thêm vào (yield <expr>)chỉ thêm một YIELD_VALUEopcode khác vào:
>>> dis.dis(compile("[(yield i) for i in range(3)]", '', 'exec').co_consts[0])
  1           0 BUILD_LIST               0
              3 LOAD_FAST                0 (.0)
        >>    6 FOR_ITER                13 (to 22)
              9 STORE_FAST               1 (i)
             12 LOAD_FAST                1 (i)
             15 YIELD_VALUE
             16 LIST_APPEND              2
             19 JUMP_ABSOLUTE            6
        >>   22 RETURN_VALUE
>>> dis.dis(compile("((yield i) for i in range(3))", '', 'exec').co_consts[0])
  1           0 LOAD_FAST                0 (.0)
        >>    3 FOR_ITER                12 (to 18)
              6 STORE_FAST               1 (i)
              9 LOAD_FAST                1 (i)
             12 YIELD_VALUE
             13 YIELD_VALUE
             14 POP_TOP
             15 JUMP_ABSOLUTE            3
        >>   18 LOAD_CONST               0 (None)
             21 RETURN_VALUE
Mã YIELD_VALUEopcode ở các chỉ số bytecode lần lượt là 15 và 12 là phụ, một con chim cu gáy trong tổ. Vì vậy, đối với trình tạo danh sách-hiểu-biến, bạn có 1 lợi suất tạo ra phần trên cùng của ngăn xếp mỗi lần (thay thế đầu của ngăn xếp bằng yieldgiá trị trả về) và đối với biến thể biểu thức trình tạo, bạn mang lại ở trên cùng của ngăn xếp ( số nguyên) và sau đó lại cho kết quả , nhưng bây giờ ngăn xếp chứa giá trị trả về của yieldvà bạn nhận được Nonelần thứ hai đó.
Sau đó, listđối với khả năng hiểu danh sách, đầu ra đối tượng dự định vẫn được trả về, nhưng Python 3 coi đây là trình tạo nên giá trị trả về thay vào đó được gắn với StopIterationngoại lệ dưới dạng valuethuộc tính:
>>> from itertools import islice
>>> listgen = [(yield i) for i in range(3)]
>>> list(islice(listgen, 3))  
[0, 1, 2]
>>> try:
...     next(listgen)
... except StopIteration as si:
...     print(si.value)
... 
[None, None, None]
Các Noneđối tượng đó là giá trị trả về từ các yieldbiểu thức.
Và để nhắc lại điều này một lần nữa; vấn đề tương tự cũng áp dụng cho từ điển và thiết lập khả năng hiểu trong Python 2 và Python 3; trong Python 2, các yieldgiá trị trả về vẫn được thêm vào từ điển hoặc đối tượng tập hợp dự định và giá trị trả về được 'mang lại' sau cùng thay vì được đính kèm với StopIterationngoại lệ:
>>> list({(yield k): (yield v) for k, v in {'foo': 'bar', 'spam': 'eggs'}.items()})
['bar', 'foo', 'eggs', 'spam', {None: None}]
>>> list({(yield i) for i in range(3)})
[0, 1, 2, set([None])]
     
              
yield-atomđược phép bên trong một biểu thức (bên trong một hàm trình tạo). Điều này có thể còn nhiều vấn đề hơn nếuyield-atombằng cách nào đó nó được thực hiện sai.