2016-05-24 12 views
7

Đoạn mã sau sẽ tạo và hủy danh sách các hằng số trên mỗi vòng lặp, phát sinh bất cứ điều gì (mặc dù nhỏ) trên đầu trang này ngụ ý, hoặc là danh sách được tạo ra một lần?Danh sách liên tục có được sử dụng trong một vòng lặp được tạo/xóa với mỗi lần truyền không?

for i in <some-type-of-iterable>: 
    if i in [1,3,5,18,3457,40567]: 
     print(i) 

Tôi hỏi về cả "chuẩn" của Python, ví dụ như tồn tại và về triển khai CPython chung.
Tôi biết rằng ví dụ này là giả tạo, cũng như cố gắng lo lắng về hiệu năng sử dụng CPython là ngớ ngẩn, nhưng tôi chỉ tò mò.

+2

câu hỏi như thế này là những gì 'dis' được tạo ra! –

+0

Câu trả lời có vẻ là "không". – Jasper

Trả lời

2

Ví dụ khác với Python 3.5, danh sách được tạo cho mỗi lần lặp.

>>> import dis 
>>> def func(): 
... for i in iterable: 
... for j in [1,2,3]: 
... print(i+j) 
... 
>>> dis.dis(func) 
    2   0 SETUP_LOOP    54 (to 57) 
       3 LOAD_GLOBAL    0 (iterable) 
       6 GET_ITER 
     >> 7 FOR_ITER    46 (to 56) 
      10 STORE_FAST    0 (i) 

    3   13 SETUP_LOOP    37 (to 53)  
      16 LOAD_CONST    1 (1)  # building list 
      19 LOAD_CONST    2 (2) 
      22 LOAD_CONST    3 (3) 
      25 BUILD_LIST    3 
      28 GET_ITER 
     >> 29 FOR_ITER    20 (to 52) # inner loop body begin 
      32 STORE_FAST    1 (j) 

    4   35 LOAD_GLOBAL    1 (print) 
      38 LOAD_FAST    0 (i) 
      41 LOAD_FAST    1 (j) 
      44 BINARY_ADD 
      45 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
      48 POP_TOP 
      49 JUMP_ABSOLUTE   29   # inner loop body end 
     >> 52 POP_BLOCK 
     >> 53 JUMP_ABSOLUTE   7   # outer loop end, 
               # jumping back before list creation 
     >> 56 POP_BLOCK 
     >> 57 LOAD_CONST    0 (None) 
      60 RETURN_VALUE 
+0

Danh sách nào bạn đang nói chỉ được tạo một lần? Tôi không có chuyên gia về đọc mã byte python, nhưng có vẻ như danh sách bên trong ('[4,5,6]') sẽ được xây dựng 3 lần (một lần cho mỗi 'a') vì' JUMP_ABSOLUTE 16' đặt bạn trở lại trước 'SETUP_LOOP' thứ hai,' BUILD_LIST', v.v. – mgilson

+0

Bạn nói đúng. Ví dụ cố định và cập nhật. – Jasper

+0

Tôi sẽ đặt cược rằng python2.7 sẽ có cùng một hiệu suất ở đây quá ... mặc dù tôi không chắc chắn lý do tại sao họ không tối ưu hóa BUILD_LIST đó đi. Tôi không thể nghĩ ra bất kỳ cách nào bạn có thể có thể có được một tham chiếu đến danh sách đó - Tôi đoán rằng một vòng lặp với một danh sách "liên tục" để lặp lại là một trường hợp hiếm hoi mà nó đã bị bỏ qua? – mgilson

3

Điều này phụ thuộc vào việc triển khai và phiên bản python và cách sử dụng "danh sách liên tục". Trên Cpython2.7.10 với ví dụ của bạn, có vẻ như câu trả lời là các danh sách trong điều kiện báo cáo kết quả if chỉ được tạo ra một lần ...

>>> def foo(): 
... for i in iterable: 
...  if i in [1, 3, 5]: 
...  print(i) 
... 
>>> import dis 
>>> dis.dis(foo) 
    2   0 SETUP_LOOP    34 (to 37) 
       3 LOAD_GLOBAL    0 (iterable) 
       6 GET_ITER    
     >> 7 FOR_ITER    26 (to 36) 
      10 STORE_FAST    0 (i) 

    3   13 LOAD_FAST    0 (i) 
      16 LOAD_CONST    4 ((1, 3, 5)) 
      19 COMPARE_OP    6 (in) 
      22 POP_JUMP_IF_FALSE  7 

    4   25 LOAD_FAST    0 (i) 
      28 PRINT_ITEM   
      29 PRINT_NEWLINE  
      30 JUMP_ABSOLUTE   7 
      33 JUMP_ABSOLUTE   7 
     >> 36 POP_BLOCK   
     >> 37 LOAD_CONST    0 (None) 
      40 RETURN_VALUE   

Chú ý: 16 LOAD_CONST 4 ((1, 3, 5))

ưu lổ nhìn trộm Python đã quay danh sách của chúng tôi vào một tuple (nhờ python!) và lưu trữ nó như là một hằng số. Lưu ý rằng trình tối ưu hóa lổ nhìn trộm chỉ có thể thực hiện các biến đổi này trên các đối tượng nếu nó biết rằng bạn là lập trình viên hoàn toàn không có cách nào để tham chiếu đến danh sách (nếu không, bạn có thể thay đổi danh sách và thay đổi ý nghĩa của mã). Theo như tôi biết, họ chỉ thực hiện tối ưu hóa này cho list, set các chữ cái bao gồm các hằng số hoàn toàn và là RHS của toán tử in. Có thể có các trường hợp khác mà tôi không biết (dis.dis là bạn của bạn để tìm các tối ưu hóa này).

Tôi ám chỉ nó ở trên, nhưng bạn có thể làm điều tương tự với set-literals trong các phiên bản mới hơn của python (trong python3.2 +, set được chuyển đổi thành hằng số frozenset). Lợi ích ở đây là set/frozenset có thử nghiệm thành viên nhanh hơn trung bình hơn list/tuple.

Các vấn đề liên quan