2012-03-17 19 views
7

... và mỗi vòng lặp giống như một danh sách hiểu.Tôi thấy mình đang vung búa đọc danh sách

Thay vì:

for stuff in all_stuff: 
    do(stuff) 

tôi đang làm (không gán danh sách để bất cứ điều gì):

[ do(stuff) for stuff in all_stuff ] 

Đây là một mô hình phổ biến được tìm thấy trên list-comp how-to's. 1) OK, vậy không có vấn đề gì lớn phải không? Sai rồi. 2) Đây không phải là kiểu mã? Siêu sai.

1) Yea đã sai. Như NiklasB chỉ ra, của HowTos là xây dựng một danh sách mới.

2) Có thể, nhưng không rõ ràng và rõ ràng, vì vậy tốt hơn không nên sử dụng.

Tôi không nhớ rằng những cách thực hiện đó chủ yếu dựa trên dòng lệnh. Sau khi nhóm của tôi hét lên với tôi tự hỏi tại sao địa ngục tôi đã xây dựng danh sách lớn và sau đó để cho họ đi, nó xảy ra với tôi rằng tôi có thể giới thiệu một lỗi liên quan đến bộ nhớ lớn.

Vì vậy, đây là câu hỏi của tôi. Nếu tôi đã làm điều này trong một quá trình chạy rất dài, nơi mà rất nhiều dữ liệu đã được tiêu thụ, liệu danh sách "này" có tiếp tục tiêu thụ trí nhớ của tôi cho đến khi đi không? Khi nào thì bộ thu gom rác sẽ lấy lại bộ nhớ? Sau khi phạm vi danh sách này được xây dựng trong bị mất?

Tôi đoán là có, nó sẽ tiếp tục tiêu thụ trí nhớ của tôi. Tôi không biết làm thế nào các bộ thu gom rác python hoạt động, nhưng tôi sẽ liên doanh để nói rằng danh sách này sẽ tồn tại cho đến sau khi next cuối cùng được gọi là trên all_stuff.

EDIT.

Bản chất của câu hỏi của tôi được chuyển tiếp sạch hơn nhiều in this question (nhờ các liên kết Niklas)

Trả lời

6

Nếu tôi được làm điều này trong một quá trình rất dài chạy, nơi rất nhiều dữ liệu đã được tiêu thụ, sẽ này "Danh mục" chỉ cần tiếp tục tiêu thụ bộ nhớ của tôi cho đến khi buông tay ?

Tuyệt đối.

Khi nào bộ thu gom rác sẽ nhận lại bộ nhớ? Sau khi phạm vi danh sách này được xây dựng trong bị mất?

CPython sử dụng tính tham chiếu, vì vậy đó là trường hợp có khả năng nhất. Các triển khai khác hoạt động khác nhau, do đó, đừng dựa vào nó.

Nhờ Karl đã chỉ ra rằng do các cơ chế quản lý bộ nhớ phức tạp được CPython sử dụng, điều này không không có nghĩa là bộ nhớ ngay lập tức được trả về hệ điều hành sau đó.

Tôi không biết cách trình thu gom rác python hoạt động, nhưng tôi sẽ nói rằng danh sách này sẽ tồn tại cho đến sau lần tiếp theo cuối cùng được gọi trên all_stuff.

Tôi không nghĩ rằng bất kỳ bộ gom rác nào hoạt động như thế. Thông thường họ đánh dấu và quét, vì vậy nó có thể được khá một thời gian trước khi danh sách là rác thu thập được.

Đây là mô hình phổ biến được tìm thấy trong danh sách-cách làm.

Tuyệt đối không. Vấn đề là bạn lặp lại danh sách với mục đích làm điều gì đó với mọi mục (do được gọi là side-effects). Trong tất cả các ví dụ về HOWTO List-comp, danh sách được lặp lại thành tạo danh sách mới dựa trên các mục của danh sách cũ. Hãy xem xét một ví dụ:

# list comp, creates the list [0,1,2,3,4,5,6,7,8,9] 
[i for i in range(10)] 

# loop, does nothing 
for i in range(10): 
    i # meh, just an expression which doesn't have an effect 

Có thể bạn sẽ đồng ý rằng vòng lặp này hoàn toàn vô nghĩa, vì nó không làm bất cứ điều gì, trái với hiểu, xây dựng danh sách. Trong ví dụ của bạn, đó là cách khác vòng: Việc hiểu là hoàn toàn vô nghĩa, bởi vì bạn không cần danh sách! Bạn có thể tìm thêm thông tin về sự cố trên related question

Nhân tiện, nếu bạn thực sự muốn viết vòng lặp đó trong một dòng, hãy sử dụng người tiêu dùng máy phát điện như deque.extend. Đây sẽ là hơi chậm hơn so với một vòng lặp for liệu trong ví dụ đơn giản này, mặc dù:

>>> from collections import deque 
>>> consume = deque(maxlen=0).extend 
>>> consume(do(stuff) for stuff in all_stuff) 
+0

Bạn có thể làm một số 'chuẩn timeit' cho mã cuối cùng của bạn khối? – Blender

+0

@Blender: Meh, dường như không thể chứng minh điều này ... Cảm ơn bạn đã buộc tôi phải học nó một cách khó khăn: P –

+0

Có một câu hỏi một thời gian trước đây về điều đó: [Chuyển các trình vòng lặp đến bất kỳ để thực hiện Tốc độ và Tại sao?] (http://stackoverflow.com/q/9144934/1132524) –

3

Hãy thử bằng tay làm GC và bán phá giá số liệu thống kê.

gc.DEBUG_STATS

Thống kê in trong khi thu thập. Thông tin này có thể hữu ích khi điều chỉnh tần suất thu thập.

TỪ

http://docs.python.org/library/gc.html

2

Các CPython GC sẽ gặt hái nó một lần không có tài liệu tham khảo để nó bên ngoài của một chu kỳ. Jython và IronPython tuân thủ các quy tắc của các GC bên dưới.

0

Tôi không biết cách trình thu thập rác python hoạt động, nhưng tôi sẽ nói rằng danh sách này sẽ tồn tại cho đến sau lần tiếp theo cuối cùng được gọi trên all_stuff.

Vâng, tất nhiên, vì bạn đang tạo danh sách có cùng số thành phần là all_stuff. Người thông dịch không thể hủy bỏ danh sách trước khi nó kết thúc, phải không? Bạn có thể gọi gc.collect giữa một trong các vòng lặp này và một vòng khác, nhưng mỗi cái sẽ được xây dựng hoàn chỉnh trước khi nó có thể được khai hoang.

Trong một số trường hợp, bạn có thể sử dụng một biểu thức máy phát điện thay vì một sự hiểu biết danh sách, vì vậy nó không phải xây dựng một danh sách với tất cả các giá trị của bạn:

(do_something(i) for i in xrange(1000)) 

Tuy nhiên bạn vẫn sẽ phải "exaust "máy phát điện đó theo cách nào đó ...

+0

Đó là vấn đề, all_stuff là một máy phát điện năng suất dữ liệu mạng. Nó sẽ không bị cạn kiệt bất cứ lúc nào. – sbartell

+0

Tôi có nghĩa là bạn phải đảm bảo thông dịch viên sẽ lặp lại trên máy phát điện (xin lỗi tiếng anh của tôi). Sử dụng một trong các đề xuất của những người khác, như 'any' hoặc' deque.extend' sẽ tiêu thụ từng phần tử ngay khi chúng được tạo, mà không lưu trữ chúng trong danh sách. – mgibsonbr

2

Nếu bạn thích thành ngữ đó, do lợi nhuận cái gì đó luôn đánh giá hoặc là Đúng hay Sai và sẽ xem xét một sự thay thế tương tự không có tác dụng phụ xấu xí, bạn có thể sử dụng một biểu thức máy phát điện kết hợp với một trong hai any hoặc all.

Đối với chức năng mà trả về giá trị False (hoặc không trở về):

any(do(stuff) for stuff in all_stuff) 

Đối với chức năng mà trở về giá trị thật:

all(do(stuff) for stuff in all_stuff) 
+2

Trừ khi 'do' có giá trị trả về có ý nghĩa mà chỉ đơn giản là không được xem xét ở đây. 'any' chỉ loại bỏ vòng lặp cho đến khi giá trị True đầu tiên mà nó mang lại. – lvc

+0

Đúng vậy. Xấu của tôi, cảm ơn vì đã chỉ ra điều đó. –

+0

Lưu ý rằng đôi khi có lợi thế về hiệu suất (ít nhất là với CPython) với phương pháp này so với vòng lặp bình thường. – agf

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