Ai đó đã viết: "" "Python là thông minh đủ Chừng nào các đối tượng bạn đang iterating trên có một phương pháp __len__
hay __length_hint__
, Python sẽ gọi nó là để xác định kích thước và preallocate mảng.." ""
Theo như tôi có thể biết, không có preallocation trong danh sách hiểu. Python không có cách nào để nói với kích thước của INPUT kích thước của OUTPUT.
Nhìn vào Python 2.6 mã này:
>>> def foo(func, iterable):
... return [func(i) for i in iterable]
...
>>> import dis; dis.dis(foo)
2 0 BUILD_LIST 0 #### build empty list
3 DUP_TOP
4 STORE_FAST 2 (_[1])
7 LOAD_FAST 1 (iterable)
10 GET_ITER
>> 11 FOR_ITER 19 (to 33)
14 STORE_FAST 3 (i)
17 LOAD_FAST 2 (_[1])
20 LOAD_FAST 0 (func)
23 LOAD_FAST 3 (i)
26 CALL_FUNCTION 1
29 LIST_APPEND #### stack[-2].append(stack[-1]); pop()
30 JUMP_ABSOLUTE 11
>> 33 DELETE_FAST 2 (_[1])
36 RETURN_VALUE
Nó chỉ xây dựng một danh sách rỗng, và gắn thêm bất cứ lặp đi lặp lại mang lại.
Bây giờ nhìn vào mã này, trong đó có một 'nếu' trong danh sách hiểu:
>>> def bar(func, iterable):
... return [func(i) for i in iterable if i]
...
>>> import dis; dis.dis(bar)
2 0 BUILD_LIST 0
3 DUP_TOP
4 STORE_FAST 2 (_[1])
7 LOAD_FAST 1 (iterable)
10 GET_ITER
>> 11 FOR_ITER 30 (to 44)
14 STORE_FAST 3 (i)
17 LOAD_FAST 3 (i)
20 JUMP_IF_FALSE 17 (to 40)
23 POP_TOP
24 LOAD_FAST 2 (_[1])
27 LOAD_FAST 0 (func)
30 LOAD_FAST 3 (i)
33 CALL_FUNCTION 1
36 LIST_APPEND
37 JUMP_ABSOLUTE 11
>> 40 POP_TOP
41 JUMP_ABSOLUTE 11
>> 44 DELETE_FAST 2 (_[1])
47 RETURN_VALUE
>>>
Cùng mã, cộng với một số mã để tránh LIST_APPEND.
Trong Python 3.x, bạn cần phải đào sâu hơn một chút:
>>> import dis
>>> def comprehension(f, iterable): return [f(i) for i in iterable]
...
>>> dis.dis(comprehension)
1 0 LOAD_CLOSURE 0 (f)
3 BUILD_TUPLE 1
6 LOAD_CONST 1 (<code object <listcomp> at 0x00C4B8D
8, file "<stdin>", line 1>)
9 MAKE_CLOSURE 0
12 LOAD_FAST 1 (iterable)
15 GET_ITER
16 CALL_FUNCTION 1
19 RETURN_VALUE
>>> dis.dis(comprehension.__code__.co_consts[1])
1 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 18 (to 27)
9 STORE_FAST 1 (i)
12 LOAD_DEREF 0 (f)
15 LOAD_FAST 1 (i)
18 CALL_FUNCTION 1
21 LIST_APPEND 2
24 JUMP_ABSOLUTE 6
>> 27 RETURN_VALUE
>>>
Đó là schtick cũ: bắt đầu với việc xây dựng một danh sách rỗng, sau đó lặp qua các iterable, phụ thêm vào danh sách theo yêu cầu. Tôi thấy không có preallocation ở đây.
Tối ưu hóa mà bạn đang nghĩ đến được sử dụng bên trong một mã vạch duy nhất, ví dụ: việc thực hiện list.extend(iterable)
có thể preallocate nếu iterable
có thể báo cáo chính xác độ dài của nó. list.append(object)
được cấp một đối tượng duy nhất, không được lặp lại.
Cảm ơn đã chỉ cho tôi cách tháo rời trong python, điều đó sẽ giúp tôi rất nhiều trong tương lai. Nhưng có vẻ như bạn đang sử dụng Python 2, trong Python 3 tôi nhận được đầu ra khác nhau. Nó không phù hợp với bình luận này, tôi sẽ sớm chỉnh sửa câu hỏi của tôi để cho thấy những phát hiện của tôi. – mejiwa
Ah, gotcha! Ok, điều đó đã thuyết phục tôi, gắn cờ câu trả lời của bạn là câu trả lời được chấp nhận. Đối với "Tôi giả sử", "có lẽ", "trong thực tế" những điều: Có vẻ như tôi phải đánh bóng tiếng Anh của tôi một chút :-) Tôi sẽ loại bỏ các thông tin gây hiểu lầm tôi đã thêm vào. – mejiwa
@Daniel: vui vì bạn vẫn ở đây, nghĩ rằng tôi sẽ làm bạn sợ hãi bằng cách chấp nhận câu trả lời này. @ John: Chỉ cần chắc chắn 100%: Bạn có bất kỳ bằng chứng nào cho thấy list.extend (iterable) thực sự preallocates nếu iterable có thể báo cáo chiều dài của nó? Không có prob nếu bạn không thể, nó đã được tuyệt vời mà bạn đã kiên trì để làm cho tôi chấp nhận câu trả lời chính xác :) – mejiwa