2009-05-17 38 views
10

Bản đồ() lặp qua danh sách như "cho" sẽ? Có giá trị trong việc sử dụng bản đồ vs cho không?Có giá trị khi sử dụng map() vs cho không?

Nếu vậy, ngay bây giờ mã của tôi trông như thế này:

for item in items: 
    item.my_func() 

Nếu nó có ý nghĩa, tôi muốn thực hiện nó là map(). Điều đó có thể không? Ví dụ như thế nào?

Trả lời

23

Bạn có thể sử dụng map thay vì for vòng lặp bạn đã thể hiện, nhưng kể từ khi bạn dường như không sử dụng kết quả của item.my_func(), điều này được không được khuyến khích. map nên được sử dụng nếu bạn muốn áp dụng một chức năng mà không có tác dụng phụ cho tất cả các yếu tố của danh sách. Trong tất cả các tình huống khác, sử dụng một vòng lặp rõ ràng.

Ngoài ra, như của Python 3.0 map trả về một máy phát điện, vì vậy trong trường hợp đó map sẽ không cư xử như nhau (trừ khi bạn đánh giá một cách rõ ràng tất cả các yếu tố được trả về bởi các máy phát điện, ví dụ bằng cách gọi list vào nó).


Sửa: kibibu hỏi trong các ý kiến ​​làm rõ về việc tại sao map 's đối số đầu tiên không phải là một chức năng với tác dụng phụ. Tôi sẽ trả lời câu hỏi đó một shot:

map có nghĩa là được chuyển một hàm fin the mathematical sense. Trong những trường hợp như vậy, không có vấn đề gì trong đó thứ tự f được áp dụng cho các yếu tố của đối số thứ hai (miễn là chúng là trả lại theo thứ tự ban đầu của chúng, tất nhiên). Quan trọng hơn, trong những trường hợp đó, map(g, map(f, l)) tương đương ngữ nghĩa với map(lambda x: g(f(x)), l), bất kể thứ tự trong đó fg được áp dụng cho các đầu vào tương ứng.

Ví dụ: không quan trọng là map trả về và lặp lại hay danh sách đầy đủ cùng một lúc. Tuy nhiên, nếu f và/hoặc g tác dụng phụ gây ra, sau đó tương đương này chỉ được đảm bảo nếu ngữ nghĩa của map(g, map(f, l)) là như vậy mà ở bất kỳ giai đoạn g được áp dụng cho n yếu tố đầu tiên được trả về bởi map(f, l) trước map(f, l) áp dụng f đến (n + 1) ​ yếu tố st của l. (Nghĩa là map phải thực hiện lặp đi lặp lại có thể lười nhất --- mà nó bằng Python 3, nhưng không phải trong Python 2!)

Đi thêm một bước xa hơn: ngay cả nếu chúng ta giả định việc thực hiện Python 3 của map, sự tương đương ngữ nghĩa có thể dễ dàng bị hỏng nếu đầu ra của map(f, l) là ví dụ được chuyển qua itertools.tee trước khi được cung cấp cho cuộc gọi bên ngoài map.

Thảo luận ở trên có vẻ có tính chất lý thuyết, nhưng khi các chương trình trở nên phức tạp hơn, chúng trở nên khó khăn hơn để giải thích và do đó khó gỡ lỗi hơn. Đảm bảo rằng một số điều là bất biến làm giảm bớt vấn đề đó một chút, và thực tế có thể ngăn chặn toàn bộ một lớp lỗi.

Cuối cùng, map nhắc nhở nhiều người trong số các đối tác thực sự chức năng của nó bằng các ngôn ngữ khác nhau (thuần túy). Vượt qua nó một "chức năng" với các tác dụng phụ sẽ gây nhầm lẫn cho những người đó. Do đó, việc xem xét thay thế (tức là sử dụng vòng lặp rõ ràng) không khó thực hiện hơn là gọi đến map, chúng tôi khuyên bạn nên hạn chế sử dụng map đối với những trường hợp mà chức năng được áp dụng không gây ra tác dụng phụ .

+0

Cảm ơn mọi người! – roder

+0

Tại sao nó không được khuyến cáo? Nó là một điều ngữ nghĩa, hoặc một số loại xử lý phân tán (nơi tác dụng phụ phá vỡ song song)? – kibibu

+1

@kibibu: Tôi đã bắt đầu trả lời câu hỏi của bạn, nhưng kết thúc với quá nhiều văn bản cho trường nhận xét này có chứa. Vì vậy, tôi cập nhật câu trả lời :) Làm thế nào điều này sẽ giúp! (Đối với nhận xét của bạn về xử lý phân tán của iterable: mặc dù * có thể * được trích dẫn như là một đối số bổ sung khi nói về 'map' trong các ngôn ngữ khác, tôi không nghĩ rằng Python (hiện tại) thực hiện bất kỳ tối ưu hóa loại đó.) – Stephan202

-3
map(lambda item: item.my_func(), items) 
+1

Tính năng này hoạt động, nhưng không trả lời được câu hỏi tại sao điều này tốt hơn sử dụng vòng lặp for (cụ thể là không phải). – Kiv

1

Lợi thế chính của map là khi bạn muốn nhận được kết quả của một số phép tính trên mọi phần tử trong danh sách. Ví dụ: đoạn mã này tăng gấp đôi mọi giá trị trong danh sách:

map(lambda x: x * 2, [1,2,3,4]) #=> [2, 4, 6, 8] 

Điều quan trọng cần lưu ý là map trả về danh sách mới với kết quả. Nó không sửa đổi danh sách ban đầu tại chỗ.

Để làm điều tương tự với for, bạn sẽ phải tạo một danh sách trống và thêm một dòng thừa vào cơ thể for để thêm kết quả của mỗi phép tính vào danh sách mới. Phiên bản map ngắn gọn và chức năng hơn.

+4

Việc hiểu danh sách thậm chí còn ngắn gọn hơn, ví dụ: [x * 2 cho x trong [1,2,3,4]) trong ví dụ của bạn. – Kiv

5

Bạn có thể viết bản đồ sử dụng này như thế này:

map(cls.my_func, items) 

thay thế cls với lớp của các mục mà bạn đang lặp kết thúc.

Như đã đề cập bởi Stephan202, đây là không được đề xuất trong trường hợp này.

Theo quy tắc, nếu bạn muốn tạo danh sách mới bằng cách áp dụng một số chức năng cho từng mục trong danh sách, hãy sử dụng bản đồ. Điều này có ý nghĩa ngụ ý rằng hàm không có tác dụng phụ, và do đó bạn có thể (có khả năng) chạy bản đồ song song.

Nếu bạn không muốn tạo danh sách mới hoặc nếu hàm có tác dụng phụ, hãy sử dụng vòng lặp for. Đây là trường hợp trong ví dụ của bạn.

2

Có sự khác biệt nhỏ về ngữ nghĩa, có thể được đóng trong thông số ngôn ngữ python. Bản đồ rõ ràng song song, trong khi chỉ cho chỉ trong các trường hợp đặc biệt. Mã số có thể ngắt từ số cho, nhưng chỉ thoát với ngoại lệ từ bản đồ.

Theo ý kiến ​​của tôi bản đồ cũng không được đảm bảo đơn đặt hàng của ứng dụng chức năng trong khi cho phải. AFAIK không triển khai python hiện có thể thực hiện việc tự động song song này.

2

Bạn có thể chuyển đổi map của mình thành một số khung tính toán HOẶC đa xử lý HOẶC được phân phối mát mẻ nếu bạn cần. Disco là một ví dụ về phân phối, chống thất bại erlang-và-python dựa trên khuôn khổ. Tôi cấu hình nó trên 2 hộp của 8 lõi và bây giờ chương trình của tôi chạy nhanh hơn 16 lần, nhờ vào cụm Disco, tuy nhiên tôi đã phải viết lại chương trình của tôi từ danh sách hiểu và cho các vòng bản đồ/giảm. Đó là cùng một thỏa thuận để viết một chương trình sử dụng cho vòng lặp và danh sách hiểu và bản đồ/giảm, nhưng khi bạn cần nó để chạy trên một cụm, bạn có thể làm điều đó gần như miễn phí nếu bạn sử dụng bản đồ/giảm.Nếu bạn không, tốt, bạn sẽ phải viết lại.

Hãy coi chừng: theo như tôi biết, python 2.x trả về danh sách thay vì một trình lặp từ bản đồ. Tôi đã nghe nói điều này có thể được bỏ qua bằng cách sử dụng iter.imap() (không bao giờ được sử dụng nó mặc dù).

2

Sử dụng vòng lặp rõ ràng khi bạn không cần danh sách kết quả lại (ví dụ: chức năng có tác dụng phụ).

Sử dụng danh sách hiểu khi bạn cần danh sách kết quả trả về (ví dụ: hàm trả về giá trị dựa trên đầu vào).

Sử dụng bản đồ() khi bạn đang cố thuyết phục người dùng Lisp rằng Python đáng được sử dụng. ;)

0

Bản đồ đôi khi có thể nhanh hơn cho các chức năng tích hợp hơn so với mã hóa vòng lặp for theo cách thủ công. Hãy thử bản đồ thời gian (str, range (1000000)) so với một vòng lặp tương tự.

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